There are times when you might find yourself needing to migrate a relying party (RP) from one AD FS implementation to another. Unfortunately, at the moment there do not seem to be existing tools to do this. So, we offer the following rather quick and dirty approach. There might be better ways, but this gets the job done.
First, export all the relying party trusts that need migrating to XML files using the below export-rps.ps1 PowerShell script. The output from the script will be a file with a file name based on the relying party identifier. For example:
- urn-federation-identifier.example.com
- https—identifier.example.com
In the following PowerShell script, edit the value $filePathBase as appropriate for your environment.
export-rps.ps1
# Load the ADFS PowerShell snap-in
Add-PSSnapin Microsoft.Adfs.PowerShell
# The directory where the relying parties should be extracted
$filePathBase = "C:\extract-rp\"
$AdfsRelyingPartyTrusts = Get-AdfsRelyingPartyTrust
foreach ($AdfsRelyingPartyTrust in $AdfsRelyingPartyTrusts)
{
# The identifier is actually an array of identifiers, we will just use the first one
$rpIdentifier = $AdfsRelyingPartyTrust.Identifier[0]
# We want a filename for this so we will try to make the identifier safe
# Replace all of the following characters with a -
# : " / \ | ? *
$fileNameSafeIdentifier = $rpIdentifier `
-replace '', '-' `
-replace ':', '-' `
-replace '"', '-' `
-replace '/', '-' `
-replace '\\', '-' `
-replace '\|', '-' `
-replace '\?', '-' `
-replace '\*', '-'
# Create the filename of the XML file we will export
$filePath = $filePathBase + $fileNameSafeIdentifier + '.xml'
# Use Export-Clixml to export the object to an XML file
$AdfsRelyingPartyTrust | Export-Clixml $filePath
}
After generating the export files, copy the XML files to the new AD FS server and import them one at a time as relying party trusts using the below import-an-rp.ps1 PowerShell script.
In the following PowerShell script, edit the value $rpIdentifier to specify which relying party you want to import and the value $filePathBase as appropriate for your environment.
import-an-rp.ps1
# Load the ADFS PowerShell snap-in
Add-PSSnapin Microsoft.Adfs.PowerShell
# location where the extracted XML files can be found
$filePathBase = "C:\extract-rp\"
# Identifier of the Relying Party (RP) we want to import
#$rpIdentifier = "urn:federation:identifier.example.com"
$rpIdentifier = "https://identifier.example.com"
# We want the name we created during extract for this so we will try to make the identifier safe
# Replace all of the following characters with a -
# : " / \ | ? *
$directoryNameSafeIdentifier = $rpIdentifier `
-replace '', '-' `
-replace ':', '-' `
-replace '"', '-' `
-replace '/', '-' `
-replace '\\', '-' `
-replace '\|', '-' `
-replace '\?', '-' `
-replace '\*', '-'
$xmlFile = $filePathBase + $directoryNameSafeIdentifier + ".xml"
if (!(Test-Path -path $xmlFile))
{
"File not found" + $xmlFile
}
else
{
$ADFSRelyingPartyTrust = Import-clixml $xmlFile
$NewADFSRelyingPartyTrust = Add-ADFSRelyingPartyTrust -Identifier $rpIdentifier `
-Name $ADFSRelyingPartyTrust.Name
$rpIdentifierUri = $NewADFSRelyingPartyTrust.Identifier
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-AutoUpdateEnabled $ADFSRelyingPartyTrust.AutoUpdateEnabled
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-DelegationAuthorizationRules $ADFSRelyingPartyTrust.DelegationAuthorizationRules
# note we need to do a ToString to not just get the enum number
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-EncryptionCertificateRevocationCheck `
$ADFSRelyingPartyTrust.EncryptionCertificateRevocationCheck.ToString()
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-IssuanceAuthorizationRules $ADFSRelyingPartyTrust.IssuanceAuthorizationRules
# note we need to do a ToString to not just get the enum number
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-SigningCertificateRevocationCheck `
$ADFSRelyingPartyTrust.SigningCertificateRevocationCheck.ToString()
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-WSFedEndpoint $ADFSRelyingPartyTrust.WSFedEndpoint
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-IssuanceTransformRules $ADFSRelyingPartyTrust.IssuanceTransformRules
# Note ClaimAccepted vs ClaimsAccepted (plural)
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-ClaimAccepted $ADFSRelyingPartyTrust.ClaimsAccepted
### NOTE this does not get imported
#$ADFSRelyingPartyTrust.ConflictWithPublishedPolicy
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-EncryptClaims $ADFSRelyingPartyTrust.EncryptClaims
### NOTE this does not get imported
#$ADFSRelyingPartyTrust.Enabled
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-EncryptionCertificate $ADFSRelyingPartyTrust.EncryptionCertificate
# Identifier is actually an array but you can't add it when
# using Set-ADFSRelyingPartyTrust -TargetIdentifier
# so we use -TargetRelyingParty instead
$targetADFSRelyingPartyTrust = Get-ADFSRelyingPartyTrust -Identifier $rpIdentifier
Set-ADFSRelyingPartyTrust -TargetRelyingParty $targetADFSRelyingPartyTrust `
-Identifier $ADFSRelyingPartyTrust.Identifier
# SKIP we don't need to import these
# $ADFSRelyingPartyTrust.LastMonitoredTime
# $ADFSRelyingPartyTrust.LastPublishedPolicyCheckSuccessful
# $ADFSRelyingPartyTrust.LastUpdateTime
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-MetadataUrl $ADFSRelyingPartyTrust.MetadataUrl
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-MonitoringEnabled $ADFSRelyingPartyTrust.MonitoringEnabled
# Name is already done
#Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
# -Name $ADFSRelyingPartyTrust.Name
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-NotBeforeSkew $ADFSRelyingPartyTrust.NotBeforeSkew
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-Notes "$ADFSRelyingPartyTrust.Notes"
### NOTE this does not get imported
#$ADFSRelyingPartyTrust.OrganizationInfo
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-ImpersonationAuthorizationRules $ADFSRelyingPartyTrust.ImpersonationAuthorizationRules
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-ProtocolProfile $ADFSRelyingPartyTrust.ProtocolProfile
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-RequestSigningCertificate $ADFSRelyingPartyTrust.RequestSigningCertificate
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-EncryptedNameIdRequired $ADFSRelyingPartyTrust.EncryptedNameIdRequired
# Note RequireSignedSamlRequests vs SignedSamlRequestsRequired,
#Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
# -RequireSignedSamlRequests $ADFSRelyingPartyTrust.SignedSamlRequestsRequired
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-SignedSamlRequestsRequired $ADFSRelyingPartyTrust.SignedSamlRequestsRequired
# Note SamlEndpoint vs SamlEndpoints (plural)
# The object comes back as a
# [Deserialized.Microsoft.IdentityServer.PowerShell.Resources.SamlEndpoint]
# so we will reconstitute
# create a new empty array
$newSamlEndPoints = @()
foreach ($SamlEndpoint in $ADFSRelyingPartyTrust.SamlEndpoints)
{
# Is ResponseLocation defined?
if ($SamlEndpoint.ResponseLocation)
{
# ResponseLocation is not null or empty
$newSamlEndPoint = New-ADFSSamlEndpoint -Binding $SamlEndpoint.Binding `
-Protocol $SamlEndpoint.Protocol `
-Uri $SamlEndpoint.Location -Index $SamlEndpoint.Index `
-IsDefault $SamlEndpoint.IsDefault
}
else
{
$newSamlEndPoint = New-ADFSSamlEndpoint -Binding $SamlEndpoint.Binding `
-Protocol $SamlEndpoint.Protocol `
-Uri $SamlEndpoint.Location -Index $SamlEndpoint.Index `
-IsDefault $SamlEndpoint.IsDefault `
-ResponseUri $SamlEndpoint.ResponseLocation
}
$newSamlEndPoints += $newSamlEndPoint
}
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-SamlEndpoint $newSamlEndPoints
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-SamlResponseSignature $ADFSRelyingPartyTrust.SamlResponseSignature
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-SignatureAlgorithm $ADFSRelyingPartyTrust.SignatureAlgorithm
Set-ADFSRelyingPartyTrust -TargetIdentifier $rpIdentifier `
-TokenLifetime $ADFSRelyingPartyTrust.TokenLifetime
}
# For comparison testing you can uncomment these lines
# to export your new import as a ___.XML.new file
# $targetADFSRelyingPartyTrust = Get-ADFSRelyingPartyTrust -Identifier $rpIdentifier
# $filePath = $xmlFile + ".new"
# $AdfsRelyingPartyTrust | Export-Clixml $filePath
Many thanks to Doug McDorman for allowing us to post his script for general use.