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.
