Copy-RelyingPartyTrust.ps1


<#PSScriptInfo
 
.VERSION 1.1
 
.GUID 3e549ec2-6bd5-4ddc-833f-a4e732753bd3
 
.AUTHOR Brad.Held@Microsoft.com
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
Currently tested on ADFS 2019, but should also work for ADFS 2016
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
 Exports a Relying Party Trust from ADFS farm and allows importing into a different ADFS farm.
  
    -Example Export: Copy-RelyingPartyTrust.ps1 -sourceRPID testing:saml:com -path C:\Folder -filename SamlTest.json -import false
        Note: Based on configuration of RP may create 3-4 files - all files need to be moved to the new farm
 
 Example Import: Copy-RelyingPartyTrust.ps1 -sourceRPID testing:saml:com -path C:\Folder -filename SamlTest.json -import true
 
#>
 

Param([Parameter(Mandatory = $true)]
    [String]
    $sourceRPID,

    [Parameter(Mandatory = $true)]
    [String]
    $path,

    [Parameter(Mandatory = $true)]
    [String]
    $filename,

    [ValidateSet("true","True","false","False")]
    [Parameter(Mandatory = $false)]
    [String]
    $import = "false"
)

#Returns the identifier for the RP
function Get-sRpIdentifier {
    [string]$rpidentifier = "";
    $identifiers = Get-AdfsRelyingPartyTrust | Select-Object Identifier;

    foreach($id in $identifiers.Identifier) {
        if($id.IndexOf($sourceRPID, [System.StringComparison]::OrdinalIgnoreCase) -ge 0) {
            $rpidentifier = $id;
            break;
        }
    }

    if ($rpidentifier -eq "") {
        throw "Unable to get the ADFS source relying party trust identifier.";
    }

    return $rpidentifier;
}

#Backup Target RP
function store-RP {
    $rp = Get-AdfsRelyingPartyTrust -Identifier $(Get-sRpIdentifier);
    $rpName = $rp.Name;
    $currentpath = Resolve-Path -Path $path
    $filenameJSON = "$currentpath$filename";
    $rp | ConvertTo-Json | out-file $filenameJSON;
    Write-Host = "Completed exporting Relying PartyTrust: $filenameJSON";
    Backup-IssuanceTransformRules;
    Backup-IssuanceAuthorizationRules;
    Backup-AdditionalAuthenticationRules;
    return $rp
}

#Backup Claim Issuance rules
function Backup-IssuanceTransformRules {
    $issuanceRules = "$currentpath\Claims-$filename";
    $claims = $rp | Select-Object IssuanceTransformRules;
    $stream = [System.IO.StreamWriter] $issuanceRules
    foreach($claim in $claims.IssuanceTransformRules) {
        $stream.WriteLine($claim);
    }
    $stream.close();
    Write-Host = "Backup file with claim rules created: $issuanceRules";
    return
}

#Backup Issuance Authorization Rules
function Backup-IssuanceAuthorizationRules {
    $authRules = "$currentpath\Authorization-$filename";
    $auths = $rp | Select-Object IssuanceAuthorizationRules;
    if ($auths -ne "" -and $auths -ne $null){
        $stream = [System.IO.StreamWriter] $authRules
        foreach($auth in $auths.IssuanceAuthorizationRules) {
            $stream.WriteLine($auth);
        }
        $stream.close();
        Write-Host = "Backup file with authorization rules created: $authRules";
    }
    return
}

#Backup Additional Authentication Rules
function Backup-AdditionalAuthenticationRules {
    $addRules = "$currentpath\Additional-$filename";
    $adds = $rp | Select-Object AdditionalAuthenticationRules;
    $boolHasValue = $false;
    foreach ($add in $adds.AdditionalAuthenticationRules){
        if ($add -ne "" -and $add -ne $null){
            $boolHasValue = $true;
        }
    }
    if ($boolHasValue){
        $stream = [System.IO.StreamWriter] $addRules
        foreach($add in $adds.AdditionalAuthenticationRules) {
            $stream.WriteLine($add);
        }
        $stream.close();
        Write-Host = "Backup file with AdditionalAuthenticationRules rules created: $addRules";
    }
    return
}

function import-RP {
#Using Hashtable to collect all of the parameters and then splat them into add-adfsrelyingpartytrust
    $hashTable = @{};
    $rawRP = Get-Content -Path $path$filename | ConvertFrom-Json;
    #$issueruleset = New-AdfsClaimRuleSet -ClaimRuleFile "$path\Claims-$filename";
    $hashTable.add("Name", $rawRP.Name);
    $hashTable.add("Identifier", $rawRP.Identifier);
    #$hashTable.add("IssuanceTransformRulesFile", $issueruleset);

    #boolean values
    $hashTable.add("EncryptClaims", [System.Convert]::ToBoolean($rawRP.EncryptClaims));
    $hashTable.add("Enabled", [System.Convert]::ToBoolean($rawRP.Enabled));
    $hashTable.add("AutoUpdateEnabled", [System.Convert]::ToBoolean($rawRP.AutoUpdateEnabled));
    $hashTable.add("EncryptedNameIdRequired", [System.Convert]::ToBoolean($rawRP.EncryptedNameIdRequired));
    $hashTable.add("SignedSamlRequestsRequired", [System.Convert]::ToBoolean($rawRP.SignedSamlRequestsRequired));
    $hashTable.add("AlwaysRequireAuthentication", [System.Convert]::ToBoolean($rawRP.AlwaysRequireAuthentication));
    $hashTable.add("RequestMFAFromClaimsProviders", [System.Convert]::ToBoolean($rawRP.RequestMFAFromClaimsProviders));
    $hashTable.add("EnableJWT", [System.Convert]::ToBoolean($rawRP.EnableJWT));
    $hashTable.add("RefreshTokenProtectionEnabled", [System.Convert]::ToBoolean($rawRP.RefreshTokenProtectionEnabled));
    $hashTable.add("MonitoringEnabled", [System.Convert]::ToBoolean($rawRP.MonitoringEnabled));

    #certificate values

    #Encryption Certificate - There can only be one
    if ($rawRP.EncryptionCertificate -ne "" -and $rawRP.EncryptionCertificate -ne $null){
        $enc = [System.Security.Cryptography.X509Certificates.X509Certificate2]([System.Convert]::FromBase64String([System.Convert]::ToBase64String($rawRP.EncryptionCertificate.RawData)))
        $hashTable.add("EncryptionCertificate", $enc);
    }

    #Signing Certificates - There may be more that one configured
    if ($rawRP.RequestSigningCertificate -ne "" -and $rawRP.RequestSigningCertificate -ne $null){
        $i = 0;
        
        foreach ($signingCert in $rawRP.RequestSigningCertificate) {
            $tmpString = $signingCert.RawData;
            [byte[]]$tmpBytes = @($tmpString.Split(" "));
            if ($i -eq 0) {
                $tmpCert = [System.Security.Cryptography.X509Certificates.X509Certificate2]([System.Convert]::FromBase64String([System.Convert]::ToBase64String($tmpBytes)))
                $certs = @($tmpCert);
                $i += 1;
            }else {
                $tmpCert = [System.Security.Cryptography.X509Certificates.X509Certificate2]([System.Convert]::FromBase64String([System.Convert]::ToBase64String($tmpBytes)))
                $certs += $tmpCert;
                $i += 1;
            }
         }

        $hashTable.add("RequestSigningCertificate", $certs);
    }

    #uris
    if ($rawRP.WSFedEndPoint -ne "" -and $rawRP.WSFedEndPoint -ne $null){
        $hashTable.add("WSFedEndPoint", [System.Uri]$rawRP.WSFedEndPoint);
    }

    #text/misc values
    if ($rawRP.Notes -ne "" -and $rawRP.Notes -ne $null){
        $hashTable.add("Notes", $rawRP.Notes);
    }
    else {
        $dt = Get-Date;
        $hashTable.add("Notes", $dt);
    }
    if ($rawRP.ClaimAccepted -ne "" -and $rawRP.ClaimAccepted -ne $null){
        $hashTable.add("ClaimAccepted", $rawRP.ClaimAccepted);
    }
    if ($rawRP.TokenLifetime -ne "" -and $rawRP.TokenLifetime -ne $null){
        $hashTable.add("TokenLifetime", $rawRP.TokenLifetime);
    }   
    if ($rawRP.NotBeforeSkew -ne "" -and $rawRP.NotBeforeSkew -ne $null){
        $hashTable.add("NotBeforeSkew", $rawRP.NotBeforeSkew);
    }      
    if ($rawRP.ProtocolProfile -ne "" -and $rawRP.ProtocolProfile -ne $null){
        $hashTable.add("ProtocolProfile", $rawRP.ProtocolProfile);
    } 
    if ($rawRP.SignatureAlgorithm -ne "" -and $rawRP.SignatureAlgorithm -ne $null){
        $hashTable.add("SignatureAlgorithm", $rawRP.SignatureAlgorithm);
    }  
    if ($rawRP.SamlResponseSignature -ne "" -and $rawRP.SamlResponseSignature -ne $null){
        $hashTable.add("SamlResponseSignature", $rawRP.SamlResponseSignature);
    } 
    if ($rawRP.AllowedClientTypes -ne "" -and $rawRP.AllowedClientTypes -ne $null){
        $hashTable.add("AllowedClientTypes", $rawRP.AllowedClientTypes);
    } 
    if ($rawRP.IssueOAuthRefreshTokensTo -ne "" -and $rawRP.IssueOAuthRefreshTokensTo -ne $null){
        $hashTable.add("IssueOAuthRefreshTokensTo", $rawRP.IssueOAuthRefreshTokensTo);
    } 
    if ($rawRP.AdditionalWSFedEndpoint -ne "" -and $rawRP.AdditionalWSFedEndpoint -ne $null){
        $hashTable.add("AdditionalWSFedEndpoint", $rawRP.AdditionalWSFedEndpoint);
    }
    if ($rawRP.AllowedAuthenticationClassReferences -ne "" -and $rawRP.AllowedAuthenticationClassReferences -ne $null){
        $hashTable.add("AllowedAuthenticationClassReferences", $rawRP.AllowedAuthenticationClassReferences);
    }

    switch ($rawRP.SigningCertificateRevocationCheck){
        0 {
            $hashTable.add("SigningCertificateRevocationCheck", 'None');
        }
        1 {
            $hashTable.add("SigningCertificateRevocationCheck", 'CheckEndCert');
        }
        2 {
            $hashTable.add("SigningCertificateRevocationCheck", 'CheckEndCertCacheOnly');
        }
        3 {
            $hashTable.add("SigningCertificateRevocationCheck", 'CheckChain');
        }
        4 {
            $hashTable.add("SigningCertificateRevocationCheck", 'CheckChainCacheOnly');
        }
        5 {
            $hashTable.add("SigningCertificateRevocationCheck", 'CheckChainExcludeRoot');
        }
        6 {
            $hashTable.add("SigningCertificateRevocationCheck", 'CheckChainExcludeRootCacheOnly');
        }
    }

    switch ($rawRP.EncryptionCertificateRevocationCheck){
        0 {
            $hashTable.add("EncryptionCertificateRevocationCheck", 'None');
        }
        1 {
            $hashTable.add("EncryptionCertificateRevocationCheck", 'CheckEndCert');
        }
        2 {
            $hashTable.add("EncryptionCertificateRevocationCheck", 'CheckEndCertCacheOnly');
        }
        3 {
            $hashTable.add("EncryptionCertificateRevocationCheck", 'CheckChain');
        }
        4 {
            $hashTable.add("EncryptionCertificateRevocationCheck", 'CheckChainCacheOnly');
        }
        5 {
            $hashTable.add("EncryptionCertificateRevocationCheck", 'CheckChainExcludeRoot');
        }
        6 {
            $hashTable.add("EncryptionCertificateRevocationCheck", 'CheckChainExcludeRootCacheOnly');
        }
    }

    $newRP = Add-AdfsRelyingPartyTrust @hashTable;

    #Add SAML Endpoints if neccesary
    if ($rawRP.SamlEndpoints -ne "" -and $rawRP.SamlEndpoints -ne $null){
        $EPs = New-Object -TypeName "System.Collections.ArrayList";
        foreach ($saml in $rawRP.SamlEndpoints){
            $Binding = $saml.Binding;
            $Index = $saml.Index;
            $IsDefault = $saml.IsDefault;
            $Protocol = $saml.Protocol;
            $Uri = $saml.Location;
            
            if ($saml.ResponseLocation -ne "null") {
                $ResponseUri = $saml.ResponseLocation;
                $EP = New-AdfsSamlEndpoint -Binding $Binding -Index $Index -IsDefault $IsDefault -Protocol $Protocol -Uri $Uri -ResponseUri $ResponseUri;

            }
            else {
                $EP = New-AdfsSamlEndpoint -Binding $Binding -Index $Index -IsDefault $IsDefault -Protocol $Protocol -Uri $Uri;
                
            }
            #write-host $Uri;
            $EPs.Add($EP); 
 
        }
        Set-AdfsRelyingPartyTrust -TargetIdentifier $sourceRPID -SamlEndpoint $EPs;
    }
    #Get the claim rules/authorization/additional authentication created
    Import-Claims;

}
function Import-Claims {
    $issuanceRules = "$path\Claims-$filename";
    if (Test-Path $issuanceRules -PathType Leaf) {
        #$ruleset = New-AdfsClaimRuleSet -ClaimRuleFile $issuanceRules;
        Set-AdfsRelyingPartyTrust -TargetIdentifier $sourceRPID -IssuanceTransformRulesFile $issuanceRules;
    }

    $authorizationRules = "$path\Authorization-$filename";
    if (Test-Path $authorizationRules -PathType Leaf) {
        #$ruleset = New-AdfsClaimRuleSet -ClaimRuleFile $authorizationRules;
        Set-AdfsRelyingPartyTrust -TargetIdentifier $sourceRPID -IssuanceAuthorizationRulesFile $authorizationRules;
    }

    $additionalRules = "$path\Additional-$filename";
    if (Test-Path $additionalRules -PathType Leaf) {
        #$ruleset = New-AdfsClaimRuleSet -ClaimRuleFile $additionalRules;
        Set-AdfsRelyingPartyTrust -TargetIdentifier $sourceRPID -IssuanceAuthorizationRulesFile $additionalRules;
    }
}

function Validate-RP {
    $rp = Get-AdfsRelyingPartyTrust -Identifier $sourceRPID;
    if ($rp -ne $null) {
        throw "Relying Party Trust already exists.";
    } 
    else {
        $Result = import-RP;
        $Result;
    }       
}

switch($import){
    true{}
    True{
        Validate-RP;
        break
    }
    false{}
    False{
        $savedRP = store-RP;
        break
    }
    Default { throw "Invalid -import parameter. Use True or False";}
}