Public/Sync-CrmSolutionFromSource.ps1

Function Sync-CrmSolutionFromSource {
    <#
        .SYNOPSIS
            Syncs a Solution in a Dynamics Crm org against a source solution
            in another org.
     
        .DESCRIPTION
            Syncs a Solution in a Dynamics Crm org against a source solution
            in another org.
 
            Necessary parameters read from config file. File can be generated
            using the '-GenerateConfig' switch -- this will prompt you for
            the required parameters -- or via the 'New-CrmSolutionFromSourceConfig' cmdlet.
 
            If Solution does not already exist on target, it will be created. If publisher
            does not already exist on target, it will be created. All publisher info and
            solution name are assumed to be the same on source and target.
 
            If the target Solution exists and contains SolutionComponents, any
            SolutionComponents not in source Solution will be removed from
            the target Solution.
 
            If specified in config, entities with rootcomponentbehaviors of 0 will be
            changed to 1.
 
        .OUTPUTS
            -Solution on target Dynamics Crm Org.
 
            -'Errorlog.txt', if errors encountered.
 
            -'BuildCrmSolutionLog.json', contains useful information about SolutionComponents
             manipulated by the cmdlet. This includes those Added, Skipped, and comparison results.
    #>

    [cmdletbinding()]
    Param 
    (
        [Parameter(ParameterSetName = 'Cred')]
        [pscredential]$SourceCredential,
        [Parameter(ParameterSetName = 'Cred')]
        [pscredential]$TargetCredential,
        [Parameter(ParameterSetName = 'DiscreteCreds', Mandatory = $true)]
        [string]$SourceUsername,
        [Parameter(ParameterSetName = 'DiscreteCreds', Mandatory = $true)]
        [securestring]$SourcePassword,
        [Parameter(ParameterSetName = 'DiscreteCreds', Mandatory = $true)]
        [string]$TargetUsername,
        [Parameter(ParameterSetName = 'DiscreteCreds', Mandatory = $true)]
        [securestring]$TargetPassword,
        [Parameter(Mandatory = $true)]
        [string]$ConfigFilePath
    )

    $config = Get-Config -ConfigFilePath $ConfigFilePath 
    $solutionName = $config.SolutionName
    $publisher = $config.Publisher
    $usePSCred = -Not $PSBoundParameters.ContainsKey('SourcePassword')

    if ($UsePSCred) {
        $sourceConn = Get-CrmConnection -Cred $SourceCredential -Url "https://$($config.sourceOrg).crm.dynamics.com" 
        $targetConn = Get-CrmConnection -Cred $TargetCredential -Url "https://$($config.targetOrg).crm.dynamics.com"
    } else {
        $sourceConn = Get-CrmConnection -Username $SourceUsername -Password $SourcePassword -Url "https://$sourceOrg.crm.dynamics.com" 
        $targetConn = Get-CrmConnection -Username $TargetUsername -Password $TargetPassword -Url "https://$targetOrg.crm.dynamics.com"
    }

    if (-Not (Test-CrmSolutionExists -Conn $sourceConn -SolutionName $solutionName)) {
        throw "Source solution does not exist" 
    }    
    
    if (-Not (Test-CrmSolutionExists -Conn $targetConn -SolutionName $solutionName)) {
        New-CrmSolution -SolutionName $solutionName -Publisher $publisher -Conn $targetConn
    }   
    
    
    $metadata = Get-MetadataHash -TargetConn $targetConn -SourceConn $sourceConn

    if ($config.FixRootComponentBehavior) {
        $updatedRoots = Update-RootComponentBehavior -SolutionName $solutionName -Conn $sourceConn -Metadata $Metadata.Source.Attributes
    }

    $payload = Get-Payload -Metadata $metadata -TargetConn $targetConn -SourceConn $sourceConn

    if ($payload.Release) {
        Add-Component -Conn $targetConn -Component $payload.Release -SolutionName $solutionName
    }

    if ($payload.Remove) {
        Remove-Component -Component $payload.Remove -Conn $targetConn -SolutionName $solutionName | Out-Null
        $correctionPayload = Get-Payload -Metadata $metadata -TargetConn $targetConn -SourceConn $sourceConn
        Write-Verbose "Re-adding any dependencies flushed by removal process..."
        if ($correctionPayload.Release) {
            Add-Component -Conn $targetConn -Component $correctionPayload.Release -SolutionName $solutionName
        }
    }
     
    $log = @{}
    $log["Timestamp"] = (Get-Date -Format o)
    $log["Config"] = $config
    $log["Manifest"] = $payload
    $log["RootsUpdated"] = $updatedRoots
    $log["Correction"] = $correctionManifest

    ConvertTo-Json -InputObject $log -Depth 10 | Out-File -FilePath "SyncLog.json"
    Write-Verbose "Data log saved to SyncLog.json"
}