FIMDelta is a great tool for comparing 2 configurations and showing the differences so you can pick and choose the differences. However, extracting the configurations and putting them into the correct folders so that FIMDelta can make a comparison is cumbersome. So in true ninja fashion I have automated it! The following script extracts the configurations, creates folders and places the configs appropriately. It then downloads a copy of FIMDelta and places it in each folder, all you have to do is run FIMDelta!
$schemaFiles = @{} $schemaFiles.Add("http://dev.mim.ninja:5725/ResourceManagementService","dev.xml") $schemaFiles.Add("http://prod.mim.ninja:5725/ResourceManagementService","prod.xml") $folder = (Get-Item -Path ".\" -Verbose).FullName New-Item "$folder\Schema" -ItemType directory New-Item "$folder\Policy" -ItemType directory $creds = Get-Credential if(@(get-pssnapin | where-object {$_.Name -eq "FIMAutomation"} ).count -eq 0) {add-pssnapin FIMAutomation} foreach($schemaFile in $schemaFiles.GetEnumerator()) { $schema_filename = "$folder\Schema\$($schemaFile.Value)" Write-Host "Exporting configuration objects from pilot." # Please note that SynchronizationFilter Resources inform the FIM MA. $schema = Export-FIMConfig -schemaConfig -customConfig "/SynchronizationFilter" -Uri $schemaFile.Name -Credential $creds if ($schema -eq $null) { Write-Host "Export did not successfully retrieve configuration from FIM. Please review any error messages and ensure that the arguments to Export-FIMConfig are correct." } else { Write-Host "Exported " $schema.Count " objects." $schema | ConvertFrom-FIMResource -file $schema_filename Write-Host "Schema file is saved as " $schema_filename "." } } foreach($schemaFile in $schemaFiles.GetEnumerator()) { $policy_filename = "$folder\Policy\$($schemaFile.Value)" Write-Host "Exporting configuration objects from pilot." # In many production environments, some Set resources are larger than the default message size of 10 MB. $policy = Export-FIMConfig -policyConfig -portalConfig -MessageSize 9999999 -Uri $schemaFile.Name -Credential $creds if ($policy -eq $null) { Write-Host "Export did not successfully retrieve configuration from FIM. Please review any error messages and ensure that the arguments to Export-FIMConfig are correct." } else { Write-Host "Exported $($policy.Count) objects from pilot." $policy | ConvertFrom-FIMResource -file $policy_filename Write-Host "Policy file is saved as " $policy_filename "." } } #######SYNC SCHEMA########### $pilot_filename = "$folder\Schema\dev.xml" $production_filename = "$folder\Schema\prod.xml" $changes_filename = "$folder\Schema\changes.xml" $joinrules = @{ # === Schema configuration === # This is based on the system names of attributes and objects # Notice that BindingDescription is joined using its reference attributes. ObjectTypeDescription = "Name"; AttributeTypeDescription = "Name"; BindingDescription = "BoundObjectType BoundAttributeType"; } Write-Host "Loading production file " $production_filename "." $production = ConvertTo-FIMResource -file $production_filename if($production -eq $null) { throw (new-object NullReferenceException -ArgumentList "Production Schema is null. Check that the production file has data.") } Write-Host "Loaded file " $production_filename "." $production.Count " objects loaded." Write-Host "Loading pilot file " $pilot_filename "." $pilot = ConvertTo-FIMResource -file $pilot_filename if($pilot -eq $null) { throw (new-object NullReferenceException -ArgumentList "Pilot Schema is null. Check that the pilot file has data.") } Write-Host "Loaded file " $pilot_filename "." $pilot.Count " objects loaded." Write-Host Write-Host "Executing join between pilot and production." Write-Host $matches = Join-FIMConfig -source $pilot -target $production -join $joinrules -defaultJoin DisplayName if($matches -eq $null) { throw (new-object NullReferenceException -ArgumentList "Matches is null. Check that the join succeeded and join criteria is correct for your environment.") } Write-Host "Executing compare between matched objects in pilot and production." $changes = $matches | Compare-FIMConfig if($changes -eq $null) { throw (new-object NullReferenceException -ArgumentList "Changes is null. Check that no errors occurred while generating changes.") } Write-Host "Identified " $changes.Count " changes to apply to production." Write-Host "Saving changes to " $changes_filename "." $changes | ConvertFrom-FIMResource -file $changes_filename Write-Host Write-Host "Sync Schema complete.." #################SYNC POLICY####################### $pilot_filename = "$folder\Policy\dev.xml" $production_filename = "$folder\Policy\prod.xml" $changes_filename = "$folder\Policy\changes.xml" $joinrules = @{ # === Customer-dependent join rules === # Person and Group objects are not configuration will not be migrated. # However, some configuration objects like Sets may refer to these objects. # For this reason, we need to know how to join Person objects between # systems so that configuration objects have the same semantic meaning. Person = "MailNickname DisplayName"; Group = "DisplayName"; # === Policy configuration === # Sets, MPRs, Workflow Definitions, and so on. are best identified by DisplayName # DisplayName is set as the default join criteria and applied to all object # types not listed here. # === Schema configuration === # This is based on the system names of attributes and objects # Notice that BindingDescription is joined using its reference attributes. ObjectTypeDescription = "Name"; AttributeTypeDescription = "Name"; BindingDescription = "BoundObjectType BoundAttributeType"; # === Portal configuration === ConstantSpecifier = "BoundObjectType BoundAttributeType ConstantValueKey"; SearchScopeConfiguration = "DisplayName SearchScopeResultObjectType Order"; ObjectVisualizationConfiguration = "DisplayName AppliesToCreate AppliesToEdit AppliesToView" } Write-Host "Loading production file " $production_filename "." $production = ConvertTo-FIMResource -file $production_filename if($production -eq $null) { throw (new-object NullReferenceException -ArgumentList "Production Schema is null. Check that the production file has data.") } Write-Host "Loaded file " $production_filename "." $production.Count " objects loaded." Write-Host "Loading pilot file " $pilot_filename "." $pilot = ConvertTo-FIMResource -file $pilot_filename if($pilot -eq $null) { throw (new-object NullReferenceException -ArgumentList "Pilot Schema is null. Check that the pilot file has data.") } Write-Host "Loaded file " $pilot_filename "." $pilot.Count " objects loaded." Write-Host Write-Host "Executing join between pilot and production." Write-Host $matches = Join-FIMConfig -source $pilot -target $production -join $joinrules -defaultJoin DisplayName if($matches -eq $null) { throw (new-object NullReferenceException -ArgumentList "Matches is null. Check that the join succeeded and join criteria is correct for your environment.") } Write-Host "Executing compare between matched objects in pilot and production." $changes = $matches | Compare-FIMConfig if($changes -eq $null) { throw (new-object NullReferenceException -ArgumentList "Changes is null. Check that no errors occurred while generating changes.") } Write-Host "Identified " $changes.Count " changes to apply to production." Write-Host "Saving changes to " $changes_filename "." $changes | ConvertFrom-FIMResource -file $changes_filename Write-Host Write-Host "Policy Sync complete. ....." Write-Host "Sync and Policy export and comparison complete....Will download FIMDELTA if required" ##Download FIMDELTA and copy to both folders $url = "https://github.com/pieceofsummer/FIMDelta/raw/master/build/FimDelta.exe" if(-not(Test-Path "$folder\Schema\FimDelta.exe")) { Write-Host "Starting download of FIMDELTA......" Start-BitsTransfer -Source $url -Destination "$folder\Schema\FimDelta.exe" Copy-Item -Path "$folder\Schema\FimDelta.exe" -Destination "$folder\Policy\FimDelta.exe" Write-Host "Download succesfull......Script End" } else { Write-Host "FIMDELTA already present aborting........" }
The astute of you will notice its mostly just a butcher of the existing sync scripts with a little bit of ninjaness added.