Skip to content

Instantly share code, notes, and snippets.

@darrenjrobinson
Last active October 30, 2018 04:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darrenjrobinson/41838db72e5fcb27ca4bd55d036333b3 to your computer and use it in GitHub Desktop.
Save darrenjrobinson/41838db72e5fcb27ca4bd55d036333b3 to your computer and use it in GitHub Desktop.
PowerShell Azure AD B2B Microsoft Identity Manager Management Agent - Import Script. Associated Blog Post https://blog.darrenjrobinson.com/updated-azure-ad-b2b-guest-invitations-microsoft-identity-manager-management-agent/
param (
$Username,
$Password,
$Credentials,
$OperationType,
[bool] $usepagedimport,
$pagesize
)
$DebugFilePath = "C:\PROGRA~1\MICROs~2\2010\SYNCHR~1\EXTENS~2\AzureA~3\Debug\AADImport.txt"
if(!(Test-Path $DebugFilePath))
{
$DebugFile = New-Item -Path $DebugFilePath -ItemType File
}
else
{
$DebugFile = Get-Item -Path $DebugFilePath
}
"Starting Import as : " + $OperationType + (Get-Date) | Out-File $DebugFile -Append
# Adding the AD library to your PowerShell Session.
Add-Type -Path 'C:\Program Files\WindowsPowerShell\Modules\AzureADPreview\2.0.0.52\Microsoft.IdentityModel.Clients.ActiveDirectory.dll'
# This is the tenant id of you Azure AD. You can use tenant name instead if you want.
$tenantID = "mydomain.onmicrosoft.com"
$authString = "https://login.microsoftonline.com/$tenantID"
# The resource URI for your token.
$resource = "https://graph.windows.net/"
# This is the common client id.
$client_id = "1950a258-227b-4e31-a9cf-717495945fc2"
# ************** Differential Sync Settings ************************
# What Objects are we interested in. I'm expliciting calling User, Group and Contact even though they are meant to be implied (default)
# as I've read about mixed results with differential sync across different object types
#$Searchfilter ="`$filter=isof('Microsoft.DirectoryServices.User') or isof('Microsoft.DirectoryServices.Group') or isof('Microsoft.DirectoryServices.Contact')"
$Searchfilter ="`$filter=isof('Microsoft.DirectoryServices.User')"
# Object Type (eg. Users, Groups, Contacts, DirectoryObjects)
# $object = "directoryObjects"
$object = "users"
# Output Directory and file for Differential Cookie
$downloadDirectory = "C:\PROGRA~1\MICROs~2\2010\SYNCHR~1\EXTENS~2\AzureA~3"
$cookieFile = "\AADB2BDeltaCookie.txt"
$cookiefilepath = $downloadDirectory +$cookieFile
# Reset results var
$query = $null
# Read in Delta Cookie if it exists, if not create the file for storing the cookie
if(!(Test-Path $cookiefilepath))
{
$cookie = New-Item -Path $cookiefilepath -ItemType File
"Creating new Cookie File" | Out-File $DebugFile -Append
}
else
{
$cookie = Get-Item -Path $cookiefilepath
"Cookie File present" | Out-File $DebugFile -Append
}
# ********************** Authentication to Azure ***************************
# The username must be MFA disabled user Admin at least, and must not be a live id.
# Create a client credential with the above common client id, username and password from the Connectivity tab on the MA.
$creds = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" `
-ArgumentList $Username,$Password
# Create a authentication context with the above authentication string.
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" `
-ArgumentList $authString
# Acquire access token from server.
$authenticationResult = $authContext.AcquireToken($resource,$client_id,$creds)
# Use the access token to setup headers for your http request.
$authHeader = $authenticationResult.AccessTokenType + " " + $authenticationResult.AccessToken
$headers = @{"Authorization"=$authHeader; "Content-Type"="application/json"}
# **************************************************************
# Delta or Full Sync based on Run Type and Cookie File ?
if((Get-Item $cookie).length -gt 0kb -and $OperationType -eq "Delta"){
# Delta cookie value exists. Get it
$url = Get-Content $cookie.FullName
$url += '&ocp-aad-dq-include-only-changed-properties=true&api-version=1.6' -f $authenticationResult.TenantId
"Delta Import" | Out-File $DebugFile -Append
}
else
{
# no Delta Cookie, so first run OR Full Sync so return everything
$url = "https://graph.windows.net/{0}/$($object)?&$($Searchfilter)&api-version=1.6&deltaLink="
"Full Import" | Out-File $DebugFile -Append
}
# *********************** IMPORT **********************************
# Get first set of results
$users = Invoke-RestMethod -Method Get -Headers @{
Authorization = $authenticationResult.CreateAuthorizationHeader()
'Content-Type' = "application/json"
# unremark if you just want the DeltaLink from now
# 'ocp-aad-dq-include-only-delta-token' = "true"
} -Uri ($url -f $authenticationResult.TenantId)
"Retrieved Users " + $users.value.Count | Out-File $DebugFile -Append
# An Array for the retuned objects to go into
$tenantObjects = @()
# Add in our first objects
$tenantObjects += $users.value
$moreObjects = $users
$tenantObjects.count
# Get all the remaining objects in batches
if ($users.'aad.nextLink'){
$moreObjects.'aad.nextLink' = $users.'aad.nextLink'
do
{
$moreObjects = Invoke-RestMethod -Method Get -Headers @{
Authorization = $authenticationResult.CreateAuthorizationHeader()
'Content-Type' = "application/json"
} -Uri ($moreObjects.'aad.nextLink'+'&api-version=1.6' -f $authenticationResult.TenantId)
"Retrieved Users " + $moreObjects.value.count | Out-File $DebugFile -Append
$tenantObjects += $moreObjects.value
} while ($moreObjects.'aad.nextLink')
}
"Total Users " + $tenantObjects.count | Out-File $DebugFile -Append
# store the DeltaLink in a file for next time we run the MA
$moreObjects.'aad.deltaLink' | Out-File $cookie
# ********************* Process users into the MA *******************
ForEach($user in $tenantObjects)
{
if (!$user.'aad.isDeleted' -and $user.mail -and $user.'odata.type' -eq "Microsoft.DirectoryServices.User")
{
$obj = @{}
$obj.Add("ID", $user.mail)
$obj.Add("objectID", $user.objectId)
$obj.Add("objectClass", "AADUser")
$obj.Add("AADUserType", $user.userType)
$obj.Add("AADUserPrincipalName",$user.userPrincipalName)
$obj.Add("AADAccountEnabled",$user.accountEnabled)
$obj.Add("AADDisplayName",$user.displayName)
$obj.Add("AADGivenName",$user.givenName)
$obj.Add("AADImmutableId",$user.immutableId)
$obj.Add("AADMail",$user.mail)
$obj.Add("AADSurname",$user.surname)
if ($user.userType -eq "Guest"){
$obj.Add("AADGuestUser", $true)
} else {
$obj.Add("AADGuestUser", $false)
}
# B2B External User State for B2B Users from other AAD's
if ($user.creationType) {$obj.Add("B2BCreationType", $user.creationType)}
[string]$B2BUpdatedDateTime = $null
if ($user.userStateChangedOn) {$B2BUpdatedDateTime = get-date($user.userStateChangedOn); $obj.Add("B2BUpdatedDateTime", $B2BUpdatedDateTime)}
if ($user.userState) {$obj.Add("B2BExternalUserState", $user.userState)}
# Pass the User Object to the MA
$obj
}
# Refresh token if it is going to expire in the next 5 minutes
if ($authenticationResult.ExpiresOn.AddMinutes(5).ToString("G") -lt (Get-Date -format G))
{
# Acquire a new access token from server.
$authenticationResult = $authContext.AcquireToken($resource,$client_id,$creds)
# Refresh the headers
$authHeader = $authenticationResult.AccessTokenType + " " + $authenticationResult.AccessToken
$headers = @{"Authorization"=$authHeader; "Content-Type"="application/json"}
}
}
# ***********************************************************
"Finished Import as : " + $OperationType + (Get-Date) | Out-File $DebugFile -Append
#endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment