jhorsman
9/28/2016 - 2:34 PM

Synchronize SDL Web components with schemas using PowerShell

Synchronize SDL Web components with schemas using PowerShell

# Usage examples
#   .\item-sync.ps1 "tcm:0-5-1"                   Sync in dry-run mode, the -Update flag is needed to actually make changes to the items
#   .\item-sync.ps1 "-ItemId tcm:0-5-1"           Sync all components and pages in a publication
#   .\item-sync.ps1 "-ItemId tcm:5-32-2"          Sync all items in a folder and subfolders
#   .\item-sync.ps1 "-ItemId tcm:0-5-1 -Update"   Sync and save changes 
#   .\item-sync.ps1 "-ItemId -Verbose"

# Prerequisite: Install the tridion-powershell-modules https://github.com/pkjaer/tridion-powershell-modules

#todo implement [Switch]$Whatif for the dry-run
#todo change -Update switch to the more standard -Confirm    [switch]$confirm=$true 
param (
    [parameter(Mandatory=$true)]
    [string] $ItemId,
    [parameter(Mandatory=$false)]
    [switch] $Update
)
$ErrorActionPreference = "Stop"

function SynchronizeItem ($item, $updateAfterSynchronize)
{
    $itemId = $item.Id
    $itemTitle = $item.Title
    Write-Verbose ("Synchonizing item {0} {1}" -f $itemId, $itemTitle)

    $options = New-Object Tridion.ContentManager.CoreService.Client.SynchronizeOptions
    #The ApplyDefaultValuesForMissingOptionalFields is not used, this would add unnessesary data to the items
    $options.SynchronizeFlags = [Tridion.ContentManager.CoreService.Client.SynchronizeFlags]::FixNamespace -bor
                                [Tridion.ContentManager.CoreService.Client.SynchronizeFlags]::RemoveUnknownFields -bor 
                                [Tridion.ContentManager.CoreService.Client.SynchronizeFlags]::RemoveAdditionalValues -bor
                                [Tridion.ContentManager.CoreService.Client.SynchronizeFlags]::ApplyDefaultValuesForMissingMandatoryFields -bor
                                [Tridion.ContentManager.CoreService.Client.SynchronizeFlags]::ApplyFilterXsltToXhtmlFields -bor
                                [Tridion.ContentManager.CoreService.Client.SynchronizeFlags]::ConvertFieldType

    if ($updateAfterSynchronize)
    {
        $result = $client.SynchronizeWithSchemaAndUpdate($itemId, $options);
    }
    else
    {
        $result = $client.SynchronizeWithSchema($item, $options);
    }

    if($result.SynchronizationActions.count -eq 0) {
        Write-Verbose "no actions"
    } else {
        Write-Output ("Synchonized item {0} {1}" -f $itemId, $itemTitle)
        foreach ($action in $result.SynchronizationActions)
        {
            Write-Output ("  Field Name: {0} - Field Index: {1} - Action Taken: {2}" -f $action.FieldName, $action.FieldIndex, $action.SynchronizationActionApplied)
        }
    }
}

if($Update) {
    Write-Output "Running item-schema synchronization with update; The component and page changes will be saved"
} else {
    Write-Output "Running item-schema synchronization in dry run; No component and page changes will be s
    aved"
}

Write-Verbose "Create Core Service client"
Import-Module Tridion-CoreService -Verbose:$false
Set-TridionCoreServiceSettings -Version "2013-SP1"
$client = Get-TridionCoreServiceClient                              

#todo add options to limit amount of items, i.e. query by schema
$searchQuery = New-Object Tridion.ContentManager.CoreService.Client.SearchQueryData
$link = New-Object Tridion.ContentManager.CoreService.Client.LinkToIdentifiableObjectData
$link.IdRef = $ItemId
$searchQuery.SearchIn = $link
$searchQuery.SearchInSubtree = $true
$searchQuery.ItemTypes = [Tridion.ContentManager.CoreService.Client.ItemType]::Component, [Tridion.ContentManager.CoreService.Client.ItemType]::Page

Write-Verbose "Query components and pages"
$searchQuery.BlueprintStatus = [Tridion.ContentManager.CoreService.Client.SearchBlueprintStatus]::Local
$localItems = $client.GetSearchResults($searchQuery)
Write-Verbose ("Found {0} local items to synchronize" -f $localItems.Count)

Write-Verbose "Query components and pages"
$searchQuery.BlueprintStatus = [Tridion.ContentManager.CoreService.Client.SearchBlueprintStatus]::Localized
$localizedItems = $client.GetSearchResults($searchQuery)
Write-Verbose ("Found {0} localized items to synchronize" -f $localizedItems.Count)

$items = $localItems + $localizedItems

Write-Output ("Found {0} items to synchronize" -f $items.Count)

Write-Output "Synchronizing items"
ForEach ($item in $items)
{
    Try
    {
        if($Update)
        {
            SynchronizeItem $item $true
        }
        else
        {
           SynchronizeItem $item $false
        }
    }
    Catch {
        Write-Output ("Error syncing item {0}: {1}" -f $item.Id, $_.Exception.Message)
    }
}