Last active
June 9, 2025 10:36
-
-
Save MartinMiles/d0367398247cbbd280386998f750efdd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Lists every item (and its template's Standard Values) that actually has | |
presentation details (shared and/or final layouts) beneath a chosen site root. | |
.PARAMETER SiteRoot | |
The content path to start from. Defaults to "/sitecore/content/Zont/Habitat/Home". | |
.PARAMETER DatabaseName | |
The Sitecore database to query (master/web/old/etc.). Defaults to "master". | |
#> | |
param( | |
[string]$SiteRoot = "/sitecore/content/Zont/Habitat/Home", | |
[string]$DatabaseName = "master" | |
) | |
# --------------------------------------------------------------------------- | |
# Safety first | |
# --------------------------------------------------------------------------- | |
$ErrorActionPreference = 'Stop' | |
# --------------------------------------------------------------------------- | |
# Ensure the drive for the requested database exists | |
# --------------------------------------------------------------------------- | |
if (-not (Get-PSDrive -Name $DatabaseName -ErrorAction SilentlyContinue)) { | |
New-PSDrive -Name $DatabaseName -PSProvider Sitecore -Root "/" -Database $DatabaseName -ErrorAction Stop | Out-Null | |
} | |
$rootPath = "${DatabaseName}:$SiteRoot" | |
if (-not (Test-Path $rootPath -ErrorAction SilentlyContinue)) { | |
throw "Site root '$SiteRoot' not found in database '$DatabaseName'." | |
} | |
# Helper – true if either shared OR final layout XML is present | |
function Test-Presentation { | |
param([string]$layoutFieldValue) | |
if ([string]::IsNullOrWhiteSpace($layoutFieldValue)) { return $false } | |
$parts = $layoutFieldValue -split '¤', 2 | |
$sharedXml = $parts[0] | |
$finalXml = if ($parts.Length -gt 1) { $parts[1] } else { "" } | |
return -not [string]::IsNullOrWhiteSpace($sharedXml) -or | |
-not [string]::IsNullOrWhiteSpace($finalXml) | |
} | |
# --------------------------------------------------------------------------- | |
# Gather all items with presentation and their Standard Values (if any) | |
# --------------------------------------------------------------------------- | |
$results = @() | |
$allItems = Get-ChildItem -Path $rootPath -Recurse -ErrorAction Stop | |
$index = 0 | |
$total = $allItems.Count | |
foreach ($item in $allItems) { | |
$index++ | |
Write-Progress -Activity "Scanning presentation" ` | |
-Status "$index of $total items" ` | |
-PercentComplete (($index / $total) * 100) | |
$rawLayout = $item["__Renderings"] | |
if (Test-Presentation $rawLayout) { | |
# Record the page item itself | |
$results += [PSCustomObject]@{ | |
ItemPath = $item.Paths.Path | |
ItemID = $item.ID.Guid.ToString("B").ToUpper() | |
Kind = "Page" | |
SharedLayout = (-not [string]::IsNullOrWhiteSpace(($rawLayout -split '¤',2)[0])) | |
FinalLayout = (($rawLayout -split '¤',2).Length -gt 1) -and | |
(-not [string]::IsNullOrWhiteSpace(($rawLayout -split '¤',2)[1])) | |
} | |
# Now inspect the template's Standard Values (only once per template) | |
$stdItem = $item.Template.StandardValues | |
if ($stdItem -and -not ($results | Where-Object { $_.ItemID -eq $stdItem.ID.Guid.ToString("B").ToUpper() })) { | |
$stdLayout = $stdItem["__Renderings"] | |
if (Test-Presentation $stdLayout) { | |
$results += [PSCustomObject]@{ | |
ItemPath = $stdItem.Paths.Path | |
ItemID = $stdItem.ID.Guid.ToString("B").ToUpper() | |
Kind = "Standard Values" | |
SharedLayout = (-not [string]::IsNullOrWhiteSpace(($stdLayout -split '¤',2)[0])) | |
FinalLayout = (($stdLayout -split '¤',2).Length -gt 1) -and | |
(-not [string]::IsNullOrWhiteSpace(($stdLayout -split '¤',2)[1])) | |
} | |
} | |
} | |
} | |
} | |
Write-Progress -Activity "Scanning presentation" -Completed -Status "Done" | |
# --------------------------------------------------------------------------- | |
# Present the findings | |
# --------------------------------------------------------------------------- | |
if ($results.Count -eq 0) { | |
Write-Warning "No items under '$SiteRoot' have presentation in database '$DatabaseName'." | |
} else { | |
$results | | |
Sort-Object -Property ItemPath, Kind | | |
Format-Table -Property ItemPath, Kind, SharedLayout, FinalLayout -AutoSize | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
Script: Replace Multiple Placeholders Across Entire Site | |
Site root: default "/sitecore/content/Zont/Habitat" | |
DB: master | |
- Processes every page item under site root and each template’s __Standard Values. | |
- Updates Shared (__Renderings) and Final (__Final Renderings) layouts. | |
- Swaps three placeholder names. | |
- Logs all changes in a summary table. | |
#> | |
param( | |
[string] $SiteRoot = "/sitecore/content/Zont/Habitat", | |
[string] $OldPlaceholder1 = "page-layout", | |
[string] $NewPlaceholder1 = "headless-main", | |
[string] $OldPlaceholder2 = "header-top", | |
[string] $NewPlaceholder2 = "headless-header", | |
[string] $OldPlaceholder3 = "footer", | |
[string] $NewPlaceholder3 = "headless-footer" | |
) | |
# 1) Mount master: if absent | |
if (-not (Get-PSDrive -Name master -ErrorAction SilentlyContinue)) { | |
New-PSDrive -Name master -PSProvider Sitecore -Root "/" -Database "master" -ErrorAction Stop | Out-Null | |
} | |
# 2) Get master database | |
$db = [Sitecore.Configuration.Factory]::GetDatabase("master") | |
if (-not $db) { throw "Cannot load master database." } | |
# 3) Prepare global log | |
$script:logEntries = New-Object System.Collections.ArrayList | |
# 4) Function: parse layout XML & swap placeholders | |
function Replace-PlaceholdersInLayout { | |
param( | |
[string] $layoutXml, | |
[string] $contextItemID, | |
[string] $contextName, | |
[string] $languageName | |
) | |
$layoutDef = [Sitecore.Layouts.LayoutDefinition]::Parse($layoutXml) | |
$changed = $false | |
# mapping pairs | |
$mappings = @( | |
@{ Old = $OldPlaceholder1; New = $NewPlaceholder1 }, | |
@{ Old = $OldPlaceholder2; New = $NewPlaceholder2 }, | |
@{ Old = $OldPlaceholder3; New = $NewPlaceholder3 } | |
) | |
foreach ($devDef in $layoutDef.Devices) { | |
$deviceName = $devDef.Name | |
foreach ($rendDef in $devDef.Renderings) { | |
$oldPh = $rendDef.Placeholder | |
if ([string]::IsNullOrEmpty($oldPh)) { continue } | |
$newPh = $null | |
foreach ($map in $mappings) { | |
if ($oldPh -eq $map.Old) { | |
$newPh = $map.New; break | |
} | |
$prefix = "/$($map.Old)/" | |
if ($oldPh.StartsWith($prefix)) { | |
$suffix = $oldPh.Substring($prefix.Length) | |
$newPh = "/$($map.New)/$suffix"; break | |
} | |
} | |
if ($newPh -and $newPh -ne $oldPh) { | |
$rendDef.Placeholder = $newPh | |
$changed = $true | |
$entry = [PSCustomObject]@{ | |
ItemID = $contextItemID | |
Context = $contextName | |
Language = $languageName | |
Device = $deviceName | |
RenderingID = $rendDef.RenderingID | |
OldPlaceholder = $oldPh | |
NewPlaceholder = $newPh | |
} | |
$null = $script:logEntries.Add($entry) | |
} | |
} | |
} | |
if ($changed) { | |
return $layoutDef.ToXml() | |
} | |
else { | |
return $null | |
} | |
} | |
# 5) Load all page items under site root | |
$siteRootItem = $db.GetItem($SiteRoot) | |
if (-not $siteRootItem) { | |
throw "Site root not found at path: $SiteRoot" | |
} | |
$allItems = @( $siteRootItem ) + ( Get-ChildItem -Path "master:$SiteRoot" -Recurse ) | |
# 6) Process Standard Values for every unique template | |
$allItems | | |
Select-Object -ExpandProperty TemplateID -Unique | | |
ForEach-Object { | |
$tplId = $_.ToString() | |
$templateItem = $db.GetItem($tplId) | |
if (-not $templateItem) { | |
Write-Warning "Template not found: $tplId. Skipping Standard Values." | |
return | |
} | |
$std = $templateItem.Children | Where-Object Name -EQ "__Standard Values" | |
if (-not $std) { | |
Write-Host "ℹ️ No __Standard Values under template: $($templateItem.Name)" | |
return | |
} | |
# Shared Layout | |
$fld = $std.Fields["__Renderings"] | |
if ($fld -and $fld.Value.Trim()) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $fld.Value ` | |
-contextItemID $std.ID.ToString() ` | |
-contextName "Standard Values Shared" ` | |
-languageName "" | |
if ($newXml) { | |
$std.Editing.BeginEdit() | |
try { $fld.Value = $newXml; Write-Host "✅ Updated Standard Values Shared for $($templateItem.Name)" } | |
finally { $std.Editing.EndEdit() } | |
} | |
} | |
# Final Layout | |
$fld2 = $std.Fields["__Final Renderings"] | |
if ($fld2 -and $fld2.Value.Trim()) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $fld2.Value ` | |
-contextItemID $std.ID.ToString() ` | |
-contextName "Standard Values Final" ` | |
-languageName "" | |
if ($newXml) { | |
$std.Editing.BeginEdit() | |
try { $fld2.Value = $newXml; Write-Host "✅ Updated Standard Values Final for $($templateItem.Name)" } | |
finally { $std.Editing.EndEdit() } | |
} | |
} | |
} | |
# 7) Process each page item × each language | |
foreach ($item in $allItems) { | |
foreach ($lang in $item.Languages) { | |
$ver = $db.GetItem($item.ID, $lang) | |
if (-not $ver) { | |
Write-Host "⚠️ $($item.Paths.FullPath) missing in $($lang.Name). Skipping." | |
continue | |
} | |
# Shared (__Renderings) | |
$f = $ver.Fields["__Renderings"] | |
if ($f -and $f.Value.Trim()) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $f.Value ` | |
-contextItemID $ver.ID.ToString() ` | |
-contextName "Shared Layout" ` | |
-languageName $lang.Name | |
if ($newXml) { | |
$ver.Editing.BeginEdit() | |
try { $f.Value = $newXml; Write-Host "✅ [$($lang.Name)] Shared updated: $($ver.Paths.FullPath)" } | |
finally { $ver.Editing.EndEdit() } | |
} | |
} | |
# Final (__Final Renderings) | |
$f2 = $ver.Fields["__Final Renderings"] | |
if ($f2 -and $f2.Value.Trim()) { | |
$newXml = Replace-PlaceholdersInLayout ` | |
-layoutXml $f2.Value ` | |
-contextItemID $ver.ID.ToString() ` | |
-contextName "Final Layout" ` | |
-languageName $lang.Name | |
if ($newXml) { | |
$ver.Editing.BeginEdit() | |
try { $f2.Value = $newXml; Write-Host "✅ [$($lang.Name)] Final updated: $($ver.Paths.FullPath)" } | |
finally { $ver.Editing.EndEdit() } | |
} | |
} | |
} | |
} | |
# 8) Summary log | |
if ($script:logEntries.Count -gt 0) { | |
Write-Host "`n===== Placeholder Replacement Log =====`n" | |
$script:logEntries | | |
Sort-Object Context, Language, Device | | |
Format-Table ` | |
@{Label="Item ID"; Expression={$_.ItemID}}, ` | |
@{Label="Context"; Expression={$_.Context}}, ` | |
@{Label="Language"; Expression={$_.Language}}, ` | |
@{Label="Device"; Expression={$_.Device}}, ` | |
@{Label="Rendering ID"; Expression={$_.RenderingID}}, ` | |
@{Label="Old Placeholder";Expression={$_.OldPlaceholder}}, ` | |
@{Label="New Placeholder";Expression={$_.NewPlaceholder}} ` | |
-AutoSize | |
Write-Host "`nTotal changes: $($script:logEntries.Count)" | |
} | |
else { | |
Write-Host "`n✅ No matching placeholders found across the site. No updates made." | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Set-Location -Path $PSScriptRoot | |
# Load connection settings | |
$config = Get-Content -Raw -Path ./config.LOCAL.json | ConvertFrom-Json | |
# Import SPE and start a remote session | |
Import-Module -Name SPE | |
$session = New-ScriptSession -ConnectionUri $config.connectionUri ` | |
-Username $config.username ` | |
-SharedSecret $config.SPE_REMOTING_SECRET | |
Invoke-RemoteScript -Session $session -ScriptBlock { | |
[string]$SiteRoot = "/sitecore/content/Zont/Habitat/Home"; | |
[string]$LayoutItemPath = "/sitecore/layout/Layouts/Foundation/JSS Experience Accelerator/Presentation/JSS Layout"; | |
[string]$DatabaseName = "master"; | |
$ErrorActionPreference = 'Stop' # fail fast, full trace | |
# ------------------------------------------------------------------------------ | |
# 1) Ensure the requested Sitecore drive exists | |
# ------------------------------------------------------------------------------ | |
if (-not (Get-PSDrive -Name $DatabaseName -ErrorAction SilentlyContinue)) { | |
New-PSDrive -Name $DatabaseName -PSProvider Sitecore -Root "/" -Database $DatabaseName -ErrorAction Stop | Out-Null | |
} | |
# 2) Get the database object | |
$db = [Sitecore.Configuration.Factory]::GetDatabase($DatabaseName) | |
if ($null -eq $db) { throw "Cannot retrieve Sitecore database '$DatabaseName'." } | |
# 3) Resolve the target layout item once | |
$layoutItem = Get-Item -Path ("${DatabaseName}:" + $LayoutItemPath) -ErrorAction Stop | |
$layoutGuid = $layoutItem.ID.Guid.ToString("B").ToUpper() | |
# 4) Helper – returns $true if Shared or Final layout XML exists | |
function Test-Presentation { | |
param([string]$layoutFieldValue) | |
if ([string]::IsNullOrWhiteSpace($layoutFieldValue)) { return $false } | |
$parts = $layoutFieldValue -split '¤', 2 | |
return (-not [string]::IsNullOrWhiteSpace($parts[0])) -or | |
(($parts.Length -gt 1) -and -not [string]::IsNullOrWhiteSpace($parts[1])) | |
} | |
# 5) Gather pages + template Standard Values with presentation | |
$rootPath = "${DatabaseName}:$SiteRoot" | |
if (-not (Test-Path $rootPath)) { throw "Site root '$SiteRoot' not found in '$DatabaseName'." } | |
$itemsToProcess = @() | |
$templateHandled = @{} | |
foreach ($item in Get-ChildItem -Path $rootPath -Recurse -ErrorAction Stop) { | |
if (Test-Presentation $item["__Renderings"]) { | |
$itemsToProcess += $item | |
# Also process template’s Standard Values (once per template) | |
$std = $item.Template.StandardValues | |
if ($std -and -not $templateHandled.ContainsKey($std.ID)) { | |
if (Test-Presentation $std["__Renderings"]) { | |
$itemsToProcess += $std | |
} | |
$templateHandled[$std.ID] = $true | |
} | |
} | |
} | |
if ($itemsToProcess.Count -eq 0) { | |
Write-Warning "No presentation found under '$SiteRoot'. Nothing to update." | |
return | |
} | |
# 6) Replace Shared Layout for a single item | |
function Set-SharedLayout { | |
param( | |
[Sitecore.Data.Items.Item]$TargetItem, | |
[string]$NewLayoutGuid | |
) | |
$sharedXml = $TargetItem.Fields[[Sitecore.FieldIDs]::LayoutField].Value | |
# Load or create <r> root | |
[xml]$xmlDoc = New-Object System.Xml.XmlDocument | |
if ([string]::IsNullOrWhiteSpace($sharedXml)) { | |
$xmlDoc.LoadXml('<r xmlns:p="p" xmlns:s="s" p:p="1"><d/></r>') | |
} else { | |
$xmlDoc.LoadXml($sharedXml) | |
} | |
$root = $xmlDoc.DocumentElement | |
$nsP = $root.GetNamespaceOfPrefix("p") | |
$nsS = $root.GetNamespaceOfPrefix("s") | |
$dNode = $xmlDoc.SelectSingleNode("/r/d") | |
if ($null -eq $dNode) { throw "Item $($TargetItem.Paths.Path) has no <d> node." } | |
$dNode.SetAttribute("l", $nsS, $NewLayoutGuid) # set layout | |
$dNode.SetAttribute("before",$nsP, "*") # keep renderings | |
$TargetItem.Editing.BeginEdit() | |
$TargetItem.Fields[[Sitecore.FieldIDs]::LayoutField].Value = $root.OuterXml | |
$TargetItem.Editing.EndEdit() | |
} | |
# 7) Loop through all collected items and update their Shared Layout | |
$processed = 0 | |
foreach ($itm in $itemsToProcess) { | |
try { | |
Set-SharedLayout -TargetItem $itm -NewLayoutGuid $layoutGuid | |
Write-Host "? Updated: $($itm.Paths.Path)" | |
$processed++ | |
} | |
catch { | |
if ($itm -and $itm.Editing.IsEditing) { $itm.Editing.CancelEdit() } | |
Write-Error "? Failed on $($itm.Paths.Path): $_" | |
throw # stop on first error | |
} | |
} | |
Write-Host "?? Finished. Updated $processed item(s). New Shared Layout > $LayoutItemPath" | |
} | |
# Tear down session | |
Stop-ScriptSession -Session $session |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
• Scans all items beneath a site root (plus each template’s Standard Values) | |
to find those that already contain presentation details. | |
• For every such item it rewrites the Shared Layout to point to a | |
specific layout item – preserving all renderings and leaving the | |
Final Layout untouched. | |
• Stops on the first error and surfaces the full exception. | |
.PARAMETER SiteRoot | |
The starting content path. Default: "/sitecore/content/Zont/Habitat/Home". | |
.PARAMETER LayoutItemPath | |
The layout item that must replace the current Shared Layout. | |
Default: "/sitecore/layout/Layouts/Foundation/JSS Experience Accelerator/Presentation/JSS Layout". | |
.PARAMETER DatabaseName | |
Which Sitecore database to work in (master/web/old/etc.). Default: "master". | |
#> | |
param( | |
[string]$SiteRoot = "/sitecore/content/Zont/Habitat/Home", | |
[string]$LayoutItemPath = "/sitecore/layout/Layouts/Foundation/JSS Experience Accelerator/Presentation/JSS Layout", | |
[string]$DatabaseName = "master" | |
) | |
$ErrorActionPreference = 'Stop' # fail fast, surface all details | |
# ───────────────────────────────────────────────────────────────────── | |
# 1) Ensure the requested Sitecore drive exists | |
# ───────────────────────────────────────────────────────────────────── | |
if (-not (Get-PSDrive -Name $DatabaseName -ErrorAction SilentlyContinue)) { | |
New-PSDrive -Name $DatabaseName -PSProvider Sitecore -Root "/" -Database $DatabaseName -ErrorAction Stop | Out-Null | |
} | |
# 2) Grab the database object once | |
$db = [Sitecore.Configuration.Factory]::GetDatabase($DatabaseName) | |
if ($null -eq $db) { throw "Cannot retrieve Sitecore database '$DatabaseName'." } | |
# 3) Resolve the layout item just once (throw if missing) | |
$layoutItem = Get-Item -Path ("${DatabaseName}:" + $LayoutItemPath) -ErrorAction Stop | |
$layoutGuid = $layoutItem.ID.Guid.ToString("B").ToUpper() | |
# 4) Helper – detect any presentation in the Shared or Final XML | |
function Test-Presentation { | |
param([string]$layoutFieldValue) | |
if ([string]::IsNullOrWhiteSpace($layoutFieldValue)) { return $false } | |
$parts = $layoutFieldValue -split '¤', 2 | |
$sharedXml = $parts[0] | |
$finalXml = if ($parts.Length -gt 1) { $parts[1] } else { "" } | |
return -not [string]::IsNullOrWhiteSpace($sharedXml) -or | |
-not [string]::IsNullOrWhiteSpace($finalXml) | |
} | |
# 5) Collect *pages* under the site root + each template’s Standard Values | |
$rootPath = "${DatabaseName}:$SiteRoot" | |
if (-not (Test-Path $rootPath)) { throw "Site root '$SiteRoot' not found in '$DatabaseName'." } | |
$itemsToProcess = @() | |
$templateDone = @{} | |
$allItems = Get-ChildItem -Path $rootPath -Recurse -ErrorAction Stop | |
$total = $allItems.Count | |
$index = 0 | |
foreach ($item in $allItems) { | |
$index++ | |
Write-Progress -Activity "Scanning for presentation" ` | |
-Status "$index / $total" ` | |
-PercentComplete (($index/$total)*100) | |
if (Test-Presentation $item["__Renderings"]) { | |
$itemsToProcess += $item | |
# also queue the template's Standard Values (once) | |
$std = $item.Template.StandardValues | |
if ($std -and -not $templateDone.ContainsKey($std.ID)) { | |
if (Test-Presentation $std["__Renderings"]) { | |
$itemsToProcess += $std | |
} | |
$templateDone[$std.ID] = $true | |
} | |
} | |
} | |
Write-Progress -Activity "Scanning for presentation" -Completed -Status "Done" | |
if ($itemsToProcess.Count -eq 0) { | |
Write-Warning "Nothing under '$SiteRoot' has presentation. No layout updates performed." | |
return | |
} | |
# 6) Function to replace Shared Layout on a single item | |
function Set-SharedLayout { | |
param( | |
[Sitecore.Data.Items.Item]$TargetItem, | |
[string]$NewLayoutGuid | |
) | |
# a) Read shared layout XML | |
$sharedXml = $TargetItem.Fields[[Sitecore.FieldIDs]::LayoutField].Value | |
# b) Load or create the <r> document | |
[xml]$xmlDoc = $null | |
if ([string]::IsNullOrWhiteSpace($sharedXml)) { | |
$xmlDoc = New-Object System.Xml.XmlDocument | |
$root = $xmlDoc.CreateElement("r") | |
$root.SetAttribute("xmlns:p","p") | |
$root.SetAttribute("xmlns:s","s") | |
$root.SetAttribute("p:p","1") | |
$xmlDoc.AppendChild($root) | Out-Null | |
} else { | |
$xmlDoc = New-Object System.Xml.XmlDocument | |
$xmlDoc.LoadXml($sharedXml) | |
} | |
$root = $xmlDoc.DocumentElement | |
$nsP = $root.GetNamespaceOfPrefix("p") | |
$nsS = $root.GetNamespaceOfPrefix("s") | |
$dNode = $xmlDoc.SelectSingleNode("/r/d") | |
if ($null -eq $dNode) { throw "No <d> device node found under <r> for item $($TargetItem.Paths.Path)." } | |
# c) Overwrite s:l and p:before attributes | |
$dNode.SetAttribute("l", $nsS, $NewLayoutGuid) | |
$dNode.SetAttribute("before", $nsP, "*") | |
# d) Write back | |
$TargetItem.Editing.BeginEdit() | |
$TargetItem.Fields[[Sitecore.FieldIDs]::LayoutField].Value = $root.OuterXml | |
$TargetItem.Editing.EndEdit() | |
} | |
# 7) Loop through every collected item and replace its Shared Layout | |
$processed = 0 | |
foreach ($itm in $itemsToProcess) { | |
$processed++ | |
Write-Progress -Activity "Updating layouts" ` | |
-Status "$processed / $($itemsToProcess.Count) : $($itm.Paths.Path)" ` | |
-PercentComplete (($processed/$itemsToProcess.Count)*100) | |
try { | |
Set-SharedLayout -TargetItem $itm -NewLayoutGuid $layoutGuid | |
Write-Host "✅ Updated: $($itm.Paths.Path)" | |
} | |
catch { | |
if ($itm -and $itm.Editing.IsEditing) { $itm.Editing.CancelEdit() } | |
Write-Error "❌ Failed on $($itm.Paths.Path): $_" | |
throw # stop on first error as requested | |
} | |
} | |
Write-Progress -Activity "Updating layouts" -Completed -Status "Done" | |
Write-Host "`n🎉 Finished. Updated $processed item(s). New Shared Layout → $LayoutItemPath (ID $layoutGuid)." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Get-ItemsWithPresentation outputs:
