Microsoft Security Tech Accelerator
Dec 06 2023, 07:00 AM - 12:00 PM (PST)
Microsoft Tech Community

AAD Connect Config Documenter

Copper Contributor



So we've finally setup a Windows Server 2019 as staging for our AD connect synchronization. One of the steps we would like to take in order to successfully migrate to this server, is to make sure that all configurations are the same.


There was documentation from Microsoft, which leverages a script called AAD Connect Config Documenter. I've downloaded the source code from the github repository. It already included a dummy data I could run to test it, but I seem to encounter this error: "It seems you may have downloaded the source code instead of a release package", which is weird because I already download the source code from the release page.


I was wondering if anyone was able to resolve this issue?

1 Reply

Hello@Earvin !


You could use this documentation


And then use the below script to verify that the settings are correct and that Import/Export will work correctly. 


And then just set the current server in staging mode and promote the new Staging server to primary sync server by taking it out of staging mode. 


If it all goes to hell so to say, you can always roll back and change the Primary/Staging server. 




[Parameter(Mandatory=$true, HelpMessage="Must be a file generated using csexport 'Name of Connector' export.xml /f:x)")]
[Parameter(Mandatory=$false, HelpMessage="Maximum number of users per output file")][int]$batchsize=1000,
[Parameter(Mandatory=$false, HelpMessage="Show console output")][bool]$showOutput=$false

#LINQ isn't loaded automatically, so force it
[Reflection.Assembly]::Load("System.Xml.Linq, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089") | Out-Null


#XML must be generated using "csexport "Name of Connector" export.xml /f:x"
write-host "Importing XML" -ForegroundColor Yellow

#XmlReader.Create won't properly resolve the file location,
#so expand and then resolve it
$resolvedXMLtoimport=Resolve-Path -Path ([Environment]::ExpandEnvironmentVariables($xmltoimport))

#use an XmlReader to deal with even large files
$result=$reader = [System.Xml.XmlReader]::Create($resolvedXMLtoimport) 
#create the object placeholder
#adding them up here means we can enforce consistency
$objOutputUser=New-Object psobject
Add-Member -InputObject $objOutputUser -MemberType NoteProperty -Name ID -Value ""
Add-Member -InputObject $objOutputUser -MemberType NoteProperty -Name Type -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name DN -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name operation -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name UPN -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name displayName -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name sourceAnchor -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name alias -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name primarySMTP -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name onPremisesSamAccountName -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name mail -Value ""

$user = [System.Xml.Linq.XElement]::ReadFrom($reader)
if ($showOutput) {Write-Host Found an exported object... -ForegroundColor Green}

#object id
if ($showOutput) {Write-Host ID: $outID}

#object type
if ($showOutput) {Write-Host Type: $outType}

$outDN= $user.Element('unapplied-export').Element('delta').Attribute('dn').Value
if ($showOutput) {Write-Host DN: $outDN}

$outOperation= $user.Element('unapplied-export').Element('delta').Attribute('operation').Value
if ($showOutput) {Write-Host Operation: $outOperation}

#now that we have the basics, go get the details

foreach ($attr in $user.Element('unapplied-export-hologram').Element('entry').Elements("attr"))
$internalvalue= $attr.Element('value').Value

switch ($attrvalue)
if ($showOutput) {Write-Host UPN: $internalvalue}
if ($showOutput) {Write-Host displayName: $internalvalue}
if ($showOutput) {Write-Host sourceAnchor: $internalvalue}
if ($showOutput) {Write-Host alias: $internalvalue}
if ($showOutput) {Write-Host primarySMTP: ($internalvalue -replace "SMTP:","")}
$objOutputUser.primarySMTP=$internalvalue -replace "SMTP:",""

$objOutputUsers += $objOutputUser

Write-Progress -activity "Processing ${xmltoimport} in batches of ${batchsize}" -status "Batch ${outputfilecount}: " -percentComplete (($objOutputUsers.Count / $batchsize) * 100)

#every so often, dump the processed users in case we blow up somewhere
if ($count % $batchsize -eq 0)
Write-Host Hit the maximum users processed without completion... -ForegroundColor Yellow

#export the collection of users as a CSV
Write-Host Writing processedusers${outputfilecount}.csv -ForegroundColor Yellow
$objOutputUsers | Export-Csv -path processedusers${outputfilecount}.csv -NoTypeInformation

#increment the output file counter

#reset the collection and the user counter
$objOutputUsers = $null


#need to bail out of the loop if no more users to process
if ($reader.NodeType -eq [System.Xml.XmlNodeType]::EndElement)

} while ($reader.Read)

#need to write out any users that didn't get picked up in a batch of 1000
#export the collection of users as CSV
Write-Host Writing processedusers${outputfilecount}.csv -ForegroundColor Yellow
$objOutputUsers | Export-Csv -path processedusers${outputfilecount}.csv -NoTypeInformation