Last active
February 2, 2016 06:08
-
-
Save darrenjrobinson/eb93a53affb4601c0116 to your computer and use it in GitHub Desktop.
MIMUsrPlacementPSMA-Import
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
param ( | |
$Username, | |
$Password, | |
$OperationType, | |
[bool] $usepagedimport, | |
$pagesize | |
) | |
#Needs reference to .NET assembly used in the script. | |
Add-Type -AssemblyName System.DirectoryServices.Protocols | |
$CookieFile = "C:\PROGRA~1\MICROS~4\2010\SYNCHR~1\EXTENS~2\Placement\Placement\dn.bin" | |
$DebugFilePath = "C:\PROGRA~1\MICROS~4\2010\SYNCHR~1\EXTENS~2\Placement\Placement\DebugOUMA.txt" | |
# The OU where we land the new users. The ones that then need to be moved | |
$landingOU = "OU=MIM,OU=customer,DC=domain,DC=com,DC=au" | |
# The OU where expired users are placed before deletion | |
$expiredOU = "OU=Expired Accounts,OU=customer,DC=domain,DC=com,DC=au" | |
#Getting Cookie from file | |
If (Test-Path $CookieFile –PathType leaf) { | |
[byte[]] $Cookie = Get-Content -Encoding byte –Path $CookieFile | |
} else { | |
$Cookie = $null | |
} | |
if(!(Test-Path $DebugFilePath)) | |
{ | |
$DebugFile = New-Item -Path $DebugFilePath -ItemType File | |
} | |
else | |
{ | |
$DebugFile = Get-Item -Path $DebugFilePath | |
} | |
"Starting Import : " + (Get-Date) | Out-File $DebugFile -Append | |
#region User | |
$Properties = @("objectguid","title", "st", "distinguishedName", "sAMAccountName","isDeleted") | |
#Running as FIM MA Account | |
$Credentials = New-Object System.Net.NetworkCredential($username,$password) | |
$RootDSE = [ADSI]"LDAP://RootDSE" | |
$LDAPDirectory = New-Object System.DirectoryServices.Protocols.LdapDirectoryIdentifier($RootDSE.dnsHostName) | |
$LDAPConnection = New-Object System.DirectoryServices.Protocols.LDAPConnection($LDAPDirectory, $Credentials) | |
$Request = New-Object System.DirectoryServices.Protocols.SearchRequest($RootDSE.defaultNamingContext, "(&(objectClass=user)(sAMAccountName=u*))", "Subtree", $Properties) | |
#Defining the object type returned from searches for performance reasons. | |
[System.DirectoryServices.Protocols.SearchResultEntry]$entry = $null | |
if ($OperationType -eq "Full") | |
{ | |
$Cookie = $null | |
} | |
else | |
{ | |
# delta run and we should use the cookie we already found | |
} | |
$DirSyncRC = New-Object System.DirectoryServices.Protocols.DirSyncRequestControl($Cookie, [System.DirectoryServices.Protocols.DirectorySynchronizationOptions]::IncrementalValues, [System.Int32]::MaxValue) | |
$Request.Controls.Add($DirSyncRC) | Out-Null | |
$MoreData = $true | |
$Guids = @() | |
while ($MoreData) { | |
$Response = $LDAPConnection.SendRequest($Request) | |
ForEach($entry in $Response.Entries){ | |
#Check if this GUID already been handled to avoid adding duplicate objects | |
If($Guids -contains ([GUID] $entry.Attributes["objectguid"][0]).ToString()){continue} | |
# we always add objectGuid and objectClass to all objects | |
$obj = @{} | |
$obj.Add("objectGuid", ([GUID] $entry.Attributes["objectguid"][0]).ToString()) | |
$obj.Add("objectClass", "user") | |
if ( $entry.distinguishedName.Contains("CN=Deleted Objects")) | |
{ | |
# this is a deleted object, so we return a changeType of 'delete'; default changeType is 'Add' | |
$obj.Add("changeType", "Delete") | |
} | |
else | |
{ | |
# we need to get the directory entry to get the additional attributes since | |
$DirEntry = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$($entry.distinguishedName)" | |
$obj.Add("accountName",$DirEntry.Properties["sAMAccountName"][0]) | |
# setting the values for attributes defined in the schema | |
if ($DirEntry.Properties["title"][0]) | |
{ | |
$obj.Add("title",$DirEntry.Properties["title"][0]) | |
$searchTitle = $DirEntry.Properties["title"][0] | |
} | |
if ($DirEntry.Properties["st"][0]) | |
{ | |
$obj.Add("state",$DirEntry.Properties["st"][0]) | |
$searchState = $DirEntry.Properties["st"][0] | |
} | |
if ($DirEntry.Properties["distinguishedName"][0]) | |
{ | |
$obj.Add("distinguishedName",$DirEntry.Properties["distinguishedName"][0]) | |
} | |
if ($DirEntry.Properties["cn"][0]) | |
{ | |
$obj.Add("cn",$DirEntry.Properties["cn"][0]) | |
} | |
if ($DirEntry.Properties["userPrincipalName"][0]) | |
{ | |
$obj.Add("upn",$DirEntry.Properties["userPrincipalName"][0]) | |
} | |
# ********************************* | |
# Go out and search for existing users matching the current users Title and State. | |
$SearchProperties = @("objectguid","title", "st", "distinguishedName", "sAMAccountName","isDeleted") | |
#Running as FIM MA Account | |
$SearchCredentials = New-Object System.Net.NetworkCredential($username,$password) | |
$SearchRootDSE = [ADSI]"LDAP://RootDSE" | |
$SearchLDAPDirectory = New-Object System.DirectoryServices.Protocols.LdapDirectoryIdentifier($SearchRootDSE.dnsHostName) | |
$SearchLDAPConnection = New-Object System.DirectoryServices.Protocols.LDAPConnection($SearchLDAPDirectory, $SearchCredentials) | |
$SearchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest($SearchRootDSE.defaultNamingContext, "(&(objectClass=user)(sAMAccountName=u*)(title=$searchTitle)(st=$searchState))", "Subtree", $SearchProperties) | |
#Defining the object type returned from searches for performance reasons. | |
[System.DirectoryServices.Protocols.SearchResultEntry]$SearchEntry = $null | |
$ArrayListOU = @() | |
# Only search for users that are in the landing OU | |
if ($DirEntry.Properties["distinguishedName"][0].Contains($landingOU)) | |
{ | |
# Only Search if we have attribute vlaues to search on | |
if ($searchTitle -and $searchState) | |
{ | |
$SearchResponse = $SearchLDAPConnection.SendRequest($SearchRequest) | |
ForEach($searchEntry in $SearchResponse.Entries) | |
{ | |
$matchedUserOU = $searchEntry.DistinguishedName | ForEach-Object { | |
# drop the CN from the object to get just the OU | |
$_ -replace '^.+?(?<!\\),','' | |
# Add the OU to the array | |
$ArrayListOU += ,$matchedUserOU | |
} | |
} | |
# How many results do we have ? Must have as at least one match, as one will be out actual user | |
# if we have more than one match there we have a candidate | |
if ($ArrayListOU.Count -gt 1) | |
{ | |
# interate through the Array to exlude the LandingOU and the Expired Accounts OU | |
# Order the list by the most occurances and select the top entry | |
$targetOU = $ArrayListOU | Group-Object | Sort-Object -Descending {$_.count} | Where-Object {$_.Name -ne $landingOU} | Where-Object {$_.Name -ne $expiredOU} | Select-Object $_.Name -First 1 | |
# after filtering out and sorting do we have somewhere to place the user | |
if ($targetOU.name -match 'DC=domain,DC=com,DC=au') | |
{ | |
# We have somewhere to move out user to | |
$obj.Add("targetOU",$targetOU.name) | |
} | |
else | |
{ | |
# nowhere to put the user with similar colleages. Geography catch-all | |
switch($searchState) | |
{ | |
"NSW" {$targetOU = "OU=NSW,OU=customer,DC=domain,DC=com,DC=au"} | |
"QLD" {$targetOU = "OU=QLD,OU=customer,DC=domain,DC=com,DC=au"} | |
"VIC" {$targetOU = "OU=VIC,OU=customer,DC=domain,DC=com,DC=au"} | |
"TAS" {$targetOU = "OU=TAS,OU=customer,DC=domain,DC=com,DC=au"} | |
"ACT" {$targetOU = "OU=ACT,OU=customer,DC=domain,DC=com,DC=au"} | |
"NT" {$targetOU = "OU=NT,OU=customer,DC=domain,DC=com,DC=au"} | |
"WA" {$targetOU = "OU=WA,OU=customer,DC=domain,DC=com,DC=au"} | |
"SA" {$targetOU = "OU=SA,OU=customer,DC=domain,DC=com,DC=au"} | |
"UK" {$targetOU = "OU=UK,OU=customer,DC=domain,DC=com,DC=au"} | |
default {$targetOU = "OU=Other,OU=customer,DC=domain,DC=com,DC=au"} | |
} | |
$obj.Add("targetOU",$targetOU) | |
} | |
} | |
else | |
{ | |
#Damn the user my have a unique position within their state. | |
# Drop them in a State based OU. They can be manually moved if required | |
switch($searchState) | |
{ | |
"NSW" {$targetOU = "OU=NSW,OU=customer,DC=domain,DC=com,DC=au"} | |
"QLD" {$targetOU = "OU=QLD,OU=customer,DC=domain,DC=com,DC=au"} | |
"VIC" {$targetOU = "OU=VIC,OU=customer,DC=domain,DC=com,DC=au"} | |
"TAS" {$targetOU = "OU=TAS,OU=customer,DC=domain,DC=com,DC=au"} | |
"ACT" {$targetOU = "OU=ACT,OU=customer,DC=domain,DC=com,DC=au"} | |
"NT" {$targetOU = "OU=NT,OU=customer,DC=domain,DC=com,DC=au"} | |
"WA" {$targetOU = "OU=WA,OU=customer,DC=domain,DC=com,DC=au"} | |
"SA" {$targetOU = "OU=SA,OU=customer,DC=domain,DC=com,DC=au"} | |
"UK" {$targetOU = "OU=UK,OU=customer,DC=domain,DC=com,DC=au"} | |
default {$targetOU = "OU=Other,OU=customer,DC=domain,DC=com,DC=au"} | |
} | |
} | |
$obj.Add("targetOU",$targetOU) | |
} | |
} | |
} | |
else | |
# user has been moved or doesn't need to be moved | |
# put the current OU in the targetOU attribue so that the Placement OU Sync Rule Outbound doesn't complain about a null value. | |
{ | |
$targetOU = $DirEntry.Properties["distinguishedName"][0] | ForEach-Object { | |
$_ -replace '^.+?(?<!\\),','' | |
} | |
$obj.add("targetOU",$targetOU) | |
} | |
} | |
#Add Guid to list of processed guids to avoid duplication | |
$Guids += ,([GUID] $entry.Attributes["objectguid"][0]).ToString() | |
#Return the object to the MA | |
$obj | |
} | |
ForEach ($Control in $Response.Controls) { | |
If ($Control.GetType().Name -eq "DirSyncResponseControl") { | |
$Cookie = $Control.Cookie | |
$MoreData = $Control.MoreData | |
} | |
} | |
$DirSyncRC.Cookie = $Cookie | |
} | |
#Saving cookie file | |
Set-Content -Value $Cookie -Encoding byte –Path $CookieFile | |
$global:RunStepCustomData = [System.Convert]::ToBase64String($Cookie) | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment