I’ve posted extensively about leveraging Lithnet services in conjunction with Microsoft Identity Manager. In fact many of the solutions I’ve built for customers just wouldn’t be as functional without Ryan’s extensive contributions to the Microsoft Identity Management community under the Lithnet brand.
What is Lithnet Password Protection for Active Directory
With the latest offering I had the opportunity to test a few elements of the solution before release. Mostly around the Pwned (Compromised) Password functions that leverage the Have I Been Pwned NTLM datasets (available here). This functionality provides the ability to;
add the Have I Been Pwned NTLM dataset to the Lithnet Password Protection Compromised Passwords Data Store that will prohibit those passwords from being used
allow administrators to test individual users Active Directory password against the Have I Been Pwned NTLM dataset to identify if the password has been compromised
allow administrators to test users from an entire Active Directory domain against the Have I Been Pwned NTLM dataset to identify if the password has been compromised
on password change against Active Directory, only permit passwords that don’t appear in the compromised or banned password lists in the Lithnet Password Protection for Active Directory data store
In addition the Lithnet Password Protection for Active Directory solution also allows more granular definition of your Active Directory Password Policy e.g Reward a password with longer length, with less complexity.
Whilst Microsoft does have something similar (for banned passwords), it is still in preview, and for a subset of the functionality you will need to be a Microsoft Azure AD Premium licensed customer. And you can’t ingest the Have I Been Pwned password dataset in as a Custom Banned Password List either. You’re hoping Microsoft has a good overlap with those datasets.
If you’re like the majority of organisations I’ve consulted for, you are currently hoping that your existing password policies (length, complexity, rotation period etc) along with implementing Multi-Factor Authentication will provide you with a balance between end-user usability and security posture.
What you ultimately require however is the peace of mind that your end-users passwords in your on-premise Active Directory and Azure Active Directory don’t contain passwords that will be consistently used in Password Spray and Password Brute Force attacks.
Until we get further down the path to Passwordless Authentication this is the best protection you can have today against two of the common password based attacks.
Whilst that was a proof of concept/discussion point of sorts AND I had a disclaimer about sending passwords across the internet to a third-party service there was a lot of momentum around the HIBP API and I developed a solution and wrote this update to check the passwords locally.
Today Troy has released v2 of that list and updated the API with new features and functionality. If you’re playing catch-up I encourage you to read Troy’s post from August last year, and my two posts about checking Active Directory passwords against that list.
Leveraging V2 (with k-Anonymity) of the Have I Been Pwned API
With v2 of the HIBP passwod list and API the number of leaked credentials in the list has grown to half a billion. 501,636,842 Pwned Passwords to be exact.
With the v2 list in conjunction with Junade Ali from Cloudflare the API has been updated to be leveraged with a level of anonymity. Instead of sending a SHA-1 hash of the password to check if the password you’re checking is on the list you can now send a truncated version of the SHA-1 hash of the password and you will be returned a set of passwords from the HIBP v2 API. This is done using a concept called k-anonymity detailed brilliantly here by Junade Ali.
v2 of the API also returns a score for each password in the list. Basically how many times the password has previously been seen in leaked credentials lists. Brilliant.
Updated Pwned PowerShell Management Agent for Pwned Password Lookup
Below is an updated Password.ps1 script for the previous API version of my Pwned Password Management Agent for Microsoft Identity Manager. It functions by;
taking the new password received from PCNS
hashes the password to SHA-1 format
looks up the v2 HIBP API using part of the SHA-1 hash
updates the MIM Service with Pwned Password status
Of course you can also download (recommended via Torrent) the Pwned Password dataset. Keep in mind that the compressed dataset is 8.75 GB and uncompressed is 29.4 GB. Convert that into an On-Premise SQL Table(s) as I did in the linked post at the beginning of this post and you’ll be well in excess of that.
Earlier this week I posted this blog post that showed a working example of using a custom Pwned Password FIM/MIM Management Agent to flag a boolean attribute in the MIM Service to indicate whether a users password is in the pwned password dataset or not. If you haven’t read that post this won’t make a lot of sense, so read that then come back.
The solution when receiving a new password for a user (via Microsoft Password Change Notification Service) was checking against the Have I Been Pwned API. The disclaimer at the start of the blog post detailed why this is a bad idea for production credentials. The intent was to show a working example of what could be achieved.
This update post shows a working solution that you can implement internal to a network. Essentially taking the Pwned Password Datasets available here and loading them into a local network SQL Server and then querying that from the FIM/MIM Pwned Password Management Agent rather than calling the external public API.
Creating an SQL Server Database for the Pwned Passwords
On my SQL Server using SQL Server Management Studio I right-clicked on Databases and chose New Database. I gave it the name PwnedPasswords and told it where I wanted my DB and Logs to go to.
Then in a Query window in SQL Server Management Studio I used the following script to created a table (dbo.pwnedPasswords).
CREATE TABLE dbo.pwnedPasswords
( password_id int NOT IDENTITY(1,1) NULL,
passwords varchar(max) NOT NULL,
CONSTRAINT passwords_pk PRIMARY KEY (password_id)
Again using a query window in SQL Server Management Studio I used the following script to create an index for the passwords.
USE [PwnedPasswords]USE [PwnedPasswords]
SET ANSI_PADDING ON
CREATE UNIQUE NONCLUSTERED INDEX [PasswordIndex] ON [dbo].[pwnedPasswords]( [password_id] ASC)INCLUDE ( [passwords]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
The last thing I did on the DB was to take the MIM Sync Server Active Directory Service Account (that was already in the SQL Server Logins) and give that account Reader Access to my new PwnedPasswords Database. I gave this account access as I’m using Integrated Authentication for login to SQL and as the MA is initiated by the MIM Sync Service Account, that is the account that needs the access.
Getting the Pwned Password Datasets into the new Database
I’m far from a DBA. I’m an identity guy. So using tools I was most familiar with (PowerShell) I created a simple script to open the password dump files as a stream (as Get-Content wasn’t going to handle the file sizes), read in the lines, convert the format and insert the rows into SQL. I performed the inserts in batches of 1000 and I performed it locally on the SQL Server.
The script could probably be improved as I only spend about 20-30 minutes on it. It is opening and closing a connection to the SQL DB each time it inserts 1000 rows. That could be moved outside the Insert2DB Function and maybe the batch size increased. Either way it is a starting point and I used it to write millions of rows into the DB successfully.
This then is the only other change to the solution. The Password.ps1 script rather than querying the PwnedPasswords API queries the SQL DB and sets the pwned boolean flag accordingly.
This enhancement shows a working concept that will be more appealing to Security Officers within corporate organisations if you have an appetite to know what your potential exposure is based on your Active Directory Users Passwords.
This is Part Two in the two-part blog post on managing users profile photos with Microsoft FIM/MIM. Part one here detailed managing users Azure AD/Active Directory profile photo. This post delves deeper into photos, specifically around Office 365 and the reason why you may want to manage these via FIM/MIM.
User profile photos should be simple to manage. But in a rapidly moving hybrid cloud world it can be a lot more complex than it needs to be. The best summary I’ve found of this evolving moving target is from Paul Ryan here.
Using Paul’s sound advice we too are advising our customers to let users manage their profile photo (within corporate guidelines) via Exchange Online. However as described in this article photos managed in OnPremise Active Directory are synchronized to Azure AD and on to other Office365 services only once. And of course we want them to be consistent across AD DS, Azure AD, Exchange Online and all other Office365 Services.
This post details synchronizing user profile photos from Exchange Online to MIM for further synchronization to other systems. The approach uses a combination of Azure GraphAPI and Exchange Remote PowerShell to manage Exchange Online User Profile Photos.
Users historically had a photo in Active Directory. DirSync/ADSync/AzureADConnect then synchronized that to Azure AD (and once only into Office 365).
Users update their photo in Office365 (via Exchange Online and Outlook Web Access)
the photo is synchronized across Office365 Services
An extension of the Current State is the requirement to be able to take the image uploaded by users in Exchange Online, and synchronize it back to the OnPremise AD, and any other relevant services that leverage a profile photo
Have AzureADConnect keep AzureAD consistent with the new photo obtained from Office365 that is synchronized to the OnPrem Active Directory
Sync the current photo to the MIM Portal
Synchronizing Office365 Profile Photos
Whilst Part-one dealt with the AzureAD side of profile photos as an extension to an existing AzureAD PowerShell Management Agent for FIM/MIM, I’ve separated out the Office365 side to streamline it and make it as efficient as possible. More on that later. As such I’ve created a new PowerShell Management Agent specifically for Office365 User Profile Photos.
I’m storing the Exchange Online photo in the MIM Metaverse as a binary object just as I did for the AzureAD photo (but in a different attribute ). I’m also storing a checksum of the photos (as I did for the AzureAD Photo, but also in a different attribute) to make it easier for comparing what is in Azure AD and Exchange Online, to then be used to determine if changes have been made (eg. user updated their profile photo).
For generating the hash of the profile photos I’m using Get-Hash from the Powershell Community Extensions. Whilst PowerShell has Get-FileHash I don’t want to write the profile photos out to disk and read them back in just to get the checksum. That slows the process up by 25%. You can get the checksum using a number of different methods and algorithms. Just be consistent and use the same method across both profile photos and you’ll be comparing apples with apples and the comparison logic will work.
Some notes on Photos and Exchange Online (and MFA)
This is where things went off on a number of tangents. Initially I tried accessing the photos using Exchange Online Remote PowerShell.
CAVEAT 1: If your Office365 Tenant is enabled for Multi-Factor Authentication (which it should be) you will need to get the Exchange Online Remote PowerShell Module as detailed here. Chances are you won’t have full Office365 Admin access though, so as long as the account you will be using is in the Recipient Management Role you should be able to go to the Exchange Control Panel using a URL like https://outlook.office365.com/ecp/?realm=<tenantname>&wa=wsignin1.0 where tenantname is something like customer.com.au From the Hybrid menu on in the right handside pane you will then be able to download the Microsoft.Online.CSE.PSModule.Client.application I had to use Internet Explorer to download the file and get it installed successfully. Once installed I used a few lines from this script here to load the Function and start my RPS session from within PowerShell ISE during solution development.
CAVEAT 2: The EXO RPS MFA PS Function doesn’t allow you to pass it your account password. You can pass it the identity you want to use, but not the password. That makes scheduled process automation with it impossible.
CAVEAT 3: The RPS session exposes the Get-UserPhoto cmdlet which is great. But the RPS session leverages the GraphAPI. The RPS PS Module doesn’t refresh it’s tokens, so if the import takes longer than 60 minutes then using this method you’re a bit stuffed.
CAVEAT 4: Using the Get-UserPhoto cmdlet detailed above, the syncing of photos is slow. As in I was only getting ~4 profile photos per minute slow. This also goes back to the token refresh issue as for pretty much any environment of the size I deal with, this is too slow and will timeout.
CAVEAT 5: You can whitelist the IP Address (or subnet) of your host so MFA is not required using Contextual IP Addressing Whitelisting. At that point there isn’t really a need to use the MFA Enabled PREVIEW EXO RPS function anyway. That said I still needed to whitelist my MIM Sync Server(s) from MFA to allow integration into the Graph API. I configured just the single host. The whitelist takes CIDR format so that looks like /32 (eg. 18.104.22.168/32)
As I mentioned above,
using the Get-UserPhoto cmdlet was slow. ~4 per minute slow
using the GraphAPI into Exchange Online and looking at each user and determining if they had a photo then downloading it, was also slow. Slow because at this customer only ~50% of their users have a photo on their mailbox. As such I was only able to retrieve ~145 photos in 25 minutes. *Note: all timings listed above were during development and actually outputting the images to disk to verify functionality.
After all my trial and error on this, here is myfinal approach and working solution;
Use the Exchange Online Remote PowerShell (non-MFA version) to query and return a collection of all mailboxes with an image *Note, add an exception for your MIM Sync host to the white-listed hosts for MFA (if your Office365 Tenant is enabled for MFA) so the process can be automated
Use the Graph API to obtain those photos
with this I was able to retrieve ~1100 profile photos in ~17* minutes (after ~2 minutes to query and get the list of mailboxes with a profile photo)
There’s a lot of info above, so let me summarize the pre-requisties;
The Granfeldt PowerShell MA
Whitelist your FIM/MIM Sync Server from MFA (if your Office 365 environment is enabled for MFA)
Add the account you will run the MA as, that will in turn connect to EXO via RPS to the Recipient Management Role
Create a WebApp for the PS MA to use to access users Profile Photos via the Graph API (fastest method)
Powershell Community Extensions to generate the image checksum
Creating the WebApp to access Office365 User Profile Photos
Go to your Azure Portal and select the Azure Active Directory Blade from the Resource Menu bar on the left. Then select App Registrations and from the Manage Section of the Azure Active Directory menu, and finally from the top of the main pane select “New Application Registration“.
Give it a name and select Web app/API as the type of app. Make the sign-in URL https://localhost and then select Create.
Record the ApplicationID that you see in the Registered App Essentials window. You’ll need this soon.
Now select All Settings => Required Permissions. Select Read all users basic profiles in addition to Sign in and read user profile. Select Save.
Under Required Permissions select Add and then select 1 Select an API, and select Office 365 Exchange Online then click Select.
Choose 2 Select Permissions and then select Read user profiles and Read all users’ basic profiles. Click Select.
Select Grant Permissions
From Settings select Keys, give your key a Description, choose a key lifetime and select Save.RECORD the key value. You’ll need this along with the WebApp ApplicationID/ClientID for the Import.ps1 script.
Using the information from your newly registered WebApp, we need to perform the first authentication (and authorization of the WebApp) to the Graph API. Taking your ApplicationID, Key (Client Secret) and the account you will use on on the Management Agent (and that you have assigned the Recipient Management Role in Exchange Online) and run the script detailed in this post here. It will authenticate you to your new WebApp via the GraphAPI after asking you to provide the account you will use on the MA and Authorizing the permissions you selected when registering the app. It will also create a refresh.token file which we will give to the MA to automate our connection. The Authorization dialog looks like this.
As detailed above the PSMA will leverage the WebApp to read users Exchange Profile Photos via the Graph API. The Import script also leverages Remote Powershell into Exchange Online (for reasons also detailed above). The account you run the Management Agent as will need to be added to the Recipient Management Role Group in order to use Remote PowerShell into Exchange Online and get the information required.
Take the Import.ps1 script below and update;
Update lines 11, 24 and 42 for the path to where you have put your PSMA. Mine is under the Extensions directory in a directory named EXOPhotos.
copy the refresh.token generated when authenticating and authorizing the WebApp earlier into the directory you specified in line 42 above.
Create a Debug directory under the directory you specified in lines 11,24 and 42 above so you can see what the MA is doing as you implement and debug it the first few times.
I’ve written the Import to use Paged Imports, so make sure you tick the Paged Imports checkbox on the configuration of the MA
Update Lines 79 and 80 with your ApplicationID and Client Secret that you recorded when creating your WebApp
Running the Exchange User Profile Photos MA
Now that you have created the MA, you should have select the EXOUser ObjectClass and the attributes defined in the schema. You should also create the EXOPhoto (as Binary) and EXOPhotoChecksum (as String) attributes in the Metaverse on the person ObjectType (assuming you are using the built-in person ObjectType).
Configure your flow rules to flow the EXOPhoto and EXOPhotoChecksum on the MA to their respective attributes in the MV.
Create a Stage Only run profile and run it. If you have done everything correctly you will see photos come into the Connector Space.
Looking at the Connector Space, I can see EXOPhoto and EXOPhotoChecksum have been imported.
After performing a Synchronization to get the data from the Connector Space into the Metaverse it is time to test the image that lands in the Metaverse. That is quick and easy via PowerShell and the Lithnet MIIS Automation PowerShell Module.
The file is output to the directory with the filename specified.
Opening the file reveals correctly my Profile Photo.
In Part one we got the AzureAD/Active Directory photo. In this post we got the Office365 photo.
Now that we have the images from Office365 we need to synchronize any update to photos to Active Directory (and in-turn via AADConnect to Azure AD). Keep in mind the image size limits for Active Directory and that we retrieved the largest photo available from Office365 when synchronizing the photo on. There are a number of PowerShell modules for photo manipulation that will allow you to resize accordingly.
Yes, that title is quite a mouthful. And this post is going to be quite long. But worth the read if you are having to create a number of rules in Microsoft/Forefront Identity Manager, or even more so the same rule in multiple environments (eg. Dev, Staging, Production).
In this post I detail using Import-RMConfig to create a Set, Workflow, Synchronization Rule and Management Policy Rule to populate a Development AD Domain with Users from a Production AD Domain. This process is designed to run on a combined MIM Service/Sync Server. If your roles a separated (as they likely will be in a Production environment) you will need to run these scripts on the MIM Sync Server (so it can query the Management Agents, and you will need to add in a line to connect to the MIM Service (eg. Set-ResourceManagementClient ) at the beginning of the script.
In my environment I have two Active Directory Management Agents, each connected to an AD Forest as shown below.
On each of the AD MA’s I have a Constant Flow Attribute (named Source) configured to flow in a value representing the source AD Forest. I’m doing this in my environment as I have more than one production forest (hence the need for automation). You could simply use the Domain attribute for the Set criteria. That attribute is used in the Set later on. Mentioning it up front so it make sense.
The Import-RMConfig cmdlet uses XML and XOML files that contain the configuration required to create the Set, Workflow, Sync Rule and MPR in the FIM/MIM Service. The order that I approach the creation is, Sync Rule, Workflow, Set and finally the MPR.
Each of these objects as indicated above leverage an XML and/or XOML input file. I’ve simplified base templates and included them in the scripts.
The Sync Rule Script includes a prompt to choose a folder (you can create one through the GUI presented) to store the XML/XOML files to allow the Import-RMConfig to use them. Once generated you can simply reference the files with Import-RMConfig to replicate the creation in another environment.
Creating the Synchronization Rule
For creation of the Sync Rule we need to define which Management Agent will be the target for our Sync Rule. In my script I’ve automated that too (as I have a number to do). I’m querying the MIM Sync Server for all its Active Directory MA’s and then providing a dialog to allow you to choose the target MA for the Sync Rule. That dialog simply looks like the one below.
Creating the Sync Rule will finally ask you to give the Rule a name. This name will then be used as the base Display Name for the Set, MPR and Workflow (and a truncated version as the Rule ID’s).
The script below in the $SyncRuleXML section defines the rules of the Sync Rule. Mine is an Outbound Sync Rule, with a base set of attributes and transforming the users UPN and DN (for the differing Development AD namespace). Update lines 42 and 45 for the users UPN and DN your namespace.
Creating the Workflow
The Workflow script is pretty self-explanatory. A simple Action based workflow and is below.
Creating the Set
The Set is the group of objects that will be synchronized to the target management agent. As my Sync Rule is only for Users my Set is also only contains users. As stated in the Overview I have an attribute that defines the authoritative source for the objects. I’m also using that in my Set criteria.
Creating the Management Policy Rule
The MPR ties everything together. Here’s that part of the script.
Tying them all together
Here is the end to end automation, and the raw script that you could use as the basis for automating similar rule generation. The Sync Rule could easily be updated for Contacts or Groups. Remember the attributes and object classes are ‘case sensitive’.
Through the Browse for Folder dialog I created a new folder named ProvisionDevAD
I provided a Display Name for the rules
I chose the target Management Agent
The SyncRule, Workflow, Set and MPR are created. The whole thing takes seconds.
Let’s take a look at the completed objects through the MIM Portal.
The Sync Rule is present as we named it. Including the !__ prefix so it appears at the top of the list.
Outbound Sync Rule based on a MPR, Set and Workflow
The Resources will be created and if deleted de-provisioned.
And our base attribute flows.
Our Set was created.
Our naming aligns with what we input
And a Criteria based Set. As per the Overview I have an attribute populated by a Constant flow rule that I based my set on. You’ll want to update for you environment.
The Action Workflow was created
All looks great
And it applies our Sync Rule
And finally our MPR. Created as a Transition In MPR with Action Workflow
Set Transition and naming all aligned
The Transition Set configured for the Set that was created
And the Workflow configured with the Workflow that was just created
When you have a lot of Sync Rules to create, or you know you will need to re-create them numerous times, potentially in different environments automation is key. This just scratches the surface on what can be achieved, and made so much easier using the Lithnet PowerShell Modules.
Here’s is the full script. Note: You’ll need to make a couple of minor changes as indicated earlier, but you should be able to create a Provisioning Rule end to end pretty quick to validate the process. Then customize accordingly for your environment and requirements. Enjoy.
I have a complex customer environment where Microsoft Identity Manager is managing identities across three Active Directory Forests. The Forests all serve different purposes and are contained in different network zones. Accordingly there are firewalls between the zone where the MIM Sync Server is located and two of the other AD Forests as shown in the graphic below.
As part of the project the maintainers of the network infrastructure had implemented rules to allow the MIM Sync server to connect to the other two AD Forests. I had successfully been able to create the Active Directory Management Agents for each of the Forests and perform synchronization imports.
The Error ‘kerberos-no-logon-server’
Everything was going well right up to the point I went to export changes to the two AD Forests that were separated by firewalls. I received the ‘kerberos-no-logon-server’ error as shown below from the run profile output.
I started investigating the error as I hadn’t encountered this one before. There were a few posts on the possibilities mainly dealing with properties of the AD MA’s configuration. But I did stumble on a mention of kerberos being used when provisioning users to Active Directory and setting the initial password. That aligned with what I was doing. I had provided the networking engineers with my firewall port requirements. Those are (no PCNS required for this implementation) ;
389 TCP – LDAP
636 TCP – LDAPS
88 TCP – Kerberos
464 TCP/UDP – Kerberos
53 TCP – DNS
3268 TCP/UDP – Global Catalog
3269 TCP/UDP – Global Catalog
135 TCP – RPC
My old school immediate thought was to Telnet to each of the ports to see if the firewall was allowing me through. But with a couple of forests to test against and UDP ports as well, it wasn’t going to be that easy. I found a nice little Test-Port function that did both TCP and UDP. I already had an older script for testing TCP ports via PowerShell. So I combined them.
Identifying the cause
As suspected connectivity to the forest where my MIM Sync Server was located was all good. The other two, not so much. GC connectivity wouldn’t give me the Kerberos error, but not having Kerberos Port 464 certainly would.
In the backwards and forwards with the networking team I had to test connectivity many times so I added a running output as well as a summary output. The running output highlighting ports that weren’t accessible.
Here’s the raw script if you’re in a similar situation. Get the Test-Port Function from the URL in line 1 to test UDP Port connectivity. Add additional ports to the arrays if required (eg. for PCNS), and update the forest names in lines 21-23.
I’m sure this is going to become more relevant in a Cloud/Hybrid world where MIM Servers will be in Azure, Active Directory Forests will be in different networks and separated by firewalls and Network Security Groups.
One of the foundations of Identity Management is the ability to join an identity between disparate connected systems. As we extend our management of identities into cloud services this adds a few twists.
A key concept is to use an anchor that is persistent. Something that doesn’t change through a users life-cycle. A user’s Security IDentifier (SID) in Active Directory is perfect. It doesn’t change when a user or group may get renamed. What gets interesting is how the SID is represented when returned using different methods. That is what I quickly cover in this post.
The defacto method for connecting your OnPremise Active Directory to Azure Active Directory is to use Azure Active Directory Connect. AADC will synchronise users and groups SID’s to the corresponding object in AAD into the onPremisesSecurityIdentifier attribute.
When the onPremisesSecurityIdentifier attribute is retrieved via the GraphAPI the format looks like this: S-1-5-21-3878594291-2115959936-132693609-65242
Using an Active Directory Management Agent for FIM/MIM and synchronizing the objectSID from the OnPremise AD represents the value in the Metaverse in binary format which when viewed as text looks like this: 15000005210002431664623112825230126105190232781820
Translating SID formats so we can join identities
What we need to do is translate the string representation of the SID returned from the GraphAPI and AzureAD so that we have it in a binary format. Then we can then use those attributes in join rules to match users/groups between AzureAD and our OnPremise Active Directory.
On my Azure AD PSMA I have the following lines in my Import.ps1 which essentially takes the value retrieved from the GraphAPI S-1-5-21-3878594291-2115959936-132693609-65242 and converts it to a binary array that in text looks something like 15000005210002431664623112825230126105190232721825400 and stores it in the AADonPremiseSID binary attribute in the connector space.
# Create SID .NET object using SID string from AAD S-1-500-........
$sid = New-Object system.Security.Principal.SecurityIdentifier $user.onPremisesSecurityIdentifier
#Create a byte array for the length of the users SID
$BinarySid = new-object byte($sid.BinaryLength)
#Copy the binary SID into the byte array, starting at index 0
#Add the SID to the user in the connector space
This then lets me join my users (and groups using the same method) between AD and AAD. Essentially a line to put it into Security Identifier format, two lines to convert it to a binary array and a line to store it in the connector space. Simple when you don’t over think it.
I’m posting this because I know I’m going to need to do this often. Hope it helps someone else too.
This post details using these concepts together specifically for AzureAD Groups.
Read the two posts linked to above. They will detail Differential Queries and Paged Imports. My solution also utilises another of my favourite PowerShell Modules. The Lithnet MIIS Automation PowerShell Module. Download and install that on the MIM Sync Server where you be creating the MA.
What you need is the Schema and Import PowerShell Scripts. Here they are.
Two object classes on the MA as we need to have users that are members of the groups on the same MA as membership is a reference attribute. When you bring through the Groups into the MetaVerse and assuming you have an Azure AD Users MA using the same anchor attribute then you’ll get the reference link for the members and their full object details.
Here is my PSMA Import.ps1 that performs what is described in the overview. Enumerate AzureAD for Groups, import the active ones along with group membership.
This is one solution for managing a large number of Azure AD Groups with large memberships via a PS MA with paged imports showing progress thanks to differential sync which then allows for subsequent quick delta-sync run profiles.