Skip to content

Instantly share code, notes, and snippets.

@darrenjrobinson darrenjrobinson/Export.ps1
Last active Jan 25, 2016

What would you like to do?
$DebugFilePath = "C:\PROGRA~1\MICROS~4\2010\SYNCHR~1\EXTENS~2\Exchange\Exchange\DebugExchMA.txt"
if(!(Test-Path $DebugFilePath))
{$DebugFile = New-Item -Path $DebugFilePath -ItemType File}
{$DebugFile = Get-Item -Path $DebugFilePath}
"Starting Export : " + (Get-Date) | Out-File $DebugFile -Append
# Setup Remote Powershell Session
$server = ""
$securestring = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$securestring.AppendChar($_)}
$credential = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $username, $securestring
"Looking to see if we have an RPS Session : " | Out-File $DebugFile -Append
if ($global:session){Remove-PSSession $global:session}
"Opening a new RPS Session." | out-file $DebugFile -Append
$skipCertificate = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $server -Authentication Kerberos -Credential $credential -SessionOption $skipCertificate
$global:session = $session
Import-PSSession $global:session
"Opened a new RPS Session" | out-file $DebugFile -Append
$errorstatus = "success"
$errordetails = $null
$Identifier = $_.Identifier
$objectGuid = $_.DN
#Loop through changes and update parameters
foreach ($can in $_.ChangedAttributeNames)
$can | out-file $DebugFile -append
foreach ($ValueChange in $_.AttributeChanges[$can].ValueChanges)
if ( $can -eq 'mailNickname'){$mailNickname = $ValueChange.value}
# Export uses Remote Powershell so we don't have to install the Exchange commandlets on this MIM Server and keep them current.
if ($_.ObjectModificationType -eq 'Add')
# adds are caught by importing new objects from Active Directory (see import script)
# and joining these to existing user objects on the metaverse
throw "Add modification are not supported"
if ($_.ObjectModificationType -eq 'Delete')
# deletes are caught by importing deleted objects (isDeleted) from Active
# Directory (see import script). This way we clear up the CS
throw "Delete modification are not supported"
#Supported ChangeType is Replace
if ($_.ObjectModificationType -match 'Replace')
$errorstatus = "success"
# Lookup the object so we know it exists before we enable the user
"Get User via DirEntry" | Out-File $DebugFile -Append
$curUser = New-Object System.DirectoryServices.DirectoryEntry "LDAP://<GUID=$objectGuid>", $username, $password
if ( $curUser )
# using msExchMailboxGuid to determine if the user has a mailbox
if (!$curUser.Properties["msExchMailboxGuid"])
"No MS Exch GUID" | Out-File $DebugFile -Append
if ($mailNickname)
if ($["mailNickname"][0])
"Replace nickName $['mailNickname'][0] " | Out-File $DebugFile -Append
set-aduser -Identity $objectGuid -replace @{'mailNickname' = $mailNickname} -ErrorAction SilentlyContinue -ErrorVariable $errordetails
"Add nickName $mailNickname" | Out-File $DebugFile -Append
set-aduser -Identity $objectGuid -add @{'mailNickname' = $mailNickname} -ErrorAction SilentlyContinue -ErrorVariable $errordetails
# User isn't Mailbox enabled. Enable them
if ($mailNickname)
"Call Update-Recip" | Out-File $DebugFile -Append
Update-Recipient -Identity $mailnickname -ErrorAction SilentlyContinue -ErrorVariable $errordetails
#Return the result to the MA
$obj = @{}
if($errordetails){$obj.Add("[ErrorDetail]",$errordetails) | out-file $DebugFile -append }
Write-output "Closing RPS Session" | out-file $DebugFile -append
Remove-PSSession $global:session
Write-out "Export Finished: " + (Get-Date) | out-file $DebugFile -append
param (
[bool] $usepagedimport,
#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\Exchange\Exchange\ExchCookie.bin"
#Getting Cookie from file
If (Test-Path $CookieFile –PathType leaf) {
[byte[]] $Cookie = Get-Content -Encoding byte –Path $CookieFile
} else {
$Cookie = $null
#region User
$Properties = @("objectGuid","sAMAccountName","msExchMailboxGuid","userPrincipalName","mail","isDeleted")
#Running as FIM MA Account as passed from the MA
$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
# 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")
# we need to get the directory entry to get the additional attributes
$DirEntry = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$($entry.distinguishedName)"
# importing attribute values if they exist
if ($DirEntry.Properties["userPrincipalName"][0]){$obj.Add("upn",$DirEntry.Properties["userPrincipalName"][0])}
if ($DirEntry.Properties["msExchMailboxGuid"][0]){$obj.Add("msExchMailboxGuid",$DirEntry.Properties["msExchMailboxGuid"][0])}
if ($DirEntry.Properties["mail"][0]){$obj.Add("mail",$DirEntry.Properties["mail"][0])}
if ($DirEntry.Properties["msExchHomeServerName"][0]){$obj.Add("msExchHomeServerName",$DirEntry.Properties["msExchHomeServerName"][0])}
if ($DirEntry.Properties["homeMDB"][0]){$obj.Add("homeMDB",$DirEntry.Properties["homeMDB"][0])}
if ($DirEntry.Properties["mailNickname"][0]){$obj.Add("mailNickname",$DirEntry.Properties["mailNickname"][0])}
#Add Guid to list of processed guids to avoid duplication
$Guids += ,([GUID] $entry.Attributes["objectguid"][0]).ToString()
#Return the object to the MA
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)
# intentionally left blank
$obj = New-Object -Type PSCustomObject
$obj | Add-Member -Type NoteProperty -Name "Anchor-objectGuid|String" -Value "00000000-0000-0000-0000-000000000001"
$obj | Add-Member -Type NoteProperty -Name "objectClass|String" -Value "user"
$obj | Add-Member -Type NoteProperty -Name "accountName|String" -Value "x_mim_adma"
$obj | Add-Member -Type NoteProperty -Name "msExchMailboxGuid|Binary" -Value 0x10
$obj | Add-Member -Type NoteProperty -Name "upn|String" -Value ""
$obj | Add-Member -Type NoteProperty -Name "mail|String" -Value ""
$obj | Add-Member -Type NoteProperty -Name "mailNickname|String" -Value ""
$obj | Add-Member -Type NoteProperty -Name "msExchHomeServerName|String" -Value ""
$obj | Add-Member -Type NoteProperty -Name "homeMDB|String" -Value ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.