FilterBox/Write-SRxJsonCustomization.ps1
|
<# ================================================================================ Write-SRxJsonCustomization.ps1 (save-conflict fix) ----------------------------------------------------------------------------- DIRECT single-term JSON customization writer. Host resolution mirrors CustomizationWriter.setProvisioningBlock, but drops -IncludeChildTerms, the per-term 5s sleep, and the CustomizationWriter constructor DB reload. SAVE-CONFLICT FIX: * NEW container -> Add-PnPTermToTerm -CustomProperties (ATOMIC create+props, single server call => no "save conflict", no retry backoff). * EXISTING -> re-fetch the term fresh by Id, then SetCustomProperty + Invoke-PnPQuery (fresh version avoids conflict). * REMOVE -> Remove-PnPTerm. Requires SRxCustomizationJson.psm1 (Split-SRxJsonProperty). Get-SRxHostingTerm / Set-SRxTermDesign come from SRxCore. ================================================================================ #> function Write-SRxJsonCustomization { [CmdletBinding()] param( [Parameter(Mandatory)] $Connection, [Parameter(Mandatory)] [int]$Scope, [Parameter(Mandatory=$false)] [int]$Optype = -1, [Parameter(Mandatory=$false)] [string]$Environment = '', [Parameter(Mandatory=$false)] [string]$Design = '', [Parameter(Mandatory=$false)] [string]$TermID = '', [Parameter(Mandatory)] [string]$ContainerName, [Parameter(Mandatory)] [string]$Operation, # 'add' | 'remove' [Parameter(Mandatory=$false)] [hashtable]$Props = @{} ) $result = [pscustomobject]@{ Success=$false; Error=$null; ContainerId=$null; CustomizationsId=$null } try { # ---------- 1) hosting term = the pack's TermID (we already have it) ---------- if ([string]::IsNullOrEmpty($TermID)) { throw "TermID is required for JSON write (scope $Scope)." } $siteTerm = Get-PnPTerm -Identity ([GUID]$TermID) -Connection $Connection -ErrorAction SilentlyContinue if ($null -eq $siteTerm) { throw "Hosting term $TermID not found (scope $Scope)." } Get-PnPProperty -ClientObject $siteTerm -Property CustomProperties -Connection $Connection | Out-Null # ---------- 2) find/create the Customizations child term ---------- $custId = $null try { $custId = $siteTerm.CustomProperties['ts_ProvisioningTemplate'] } catch {} $customizations = $null if ($custId) { $customizations = Get-PnPTerm -Identity ([GUID]$custId) -Connection $Connection -ErrorAction SilentlyContinue } if ($null -eq $customizations) { # not yet present -> create under the hosting term, atomically record the pointer $customizations = Add-PnPTermToTerm -ParentTerm $siteTerm.Id -Name 'Customizations' -Connection $Connection $fresh = Get-PnPTerm -Identity $siteTerm.Id -Connection $Connection $fresh.SetCustomProperty('ts_ProvisioningTemplate', [string]$customizations.Id) Invoke-PnPQuery -RetryCount 5 -Connection $Connection } if ($null -eq $customizations) { throw "Could not resolve/create Customizations host under term $TermID." } $result.CustomizationsId = [string]$customizations.Id # ---------- 3) find the C_<hash> container child (ONE shallow level) ---------- Get-PnPProperty -ClientObject $customizations -Property Terms -Connection $Connection | Out-Null $container = $null foreach ($t in $customizations.Terms) { if ([string]$t.Name -eq $ContainerName) { $container = $t; break } } # ---------- 4) remove ---------- if ($Operation -eq 'remove') { if ($container) { Remove-PnPTerm -Identity $container.Id -Force -Connection $Connection } $result.Success = $true return $result } # ---------- 4b) flatten + chunk props into a single hashtable ---------- $flat = @{} foreach ($k in @($Props.Keys)) { $v = [string]$Props[$k] if ($k -eq 'ts_CustomizationJson') { $chunked = Split-SRxJsonProperty -BaseKey 'ts_CustomizationJson' -Value $v foreach ($ck in $chunked.Keys) { $flat[[string]$ck] = [string]$chunked[$ck] } } else { $flat[[string]$k] = $v } } if (-not $container) { # ATOMIC create WITH properties -> single server call -> no save conflict $container = Add-PnPTermToTerm -ParentTerm $customizations.Id -Name $ContainerName -CustomProperties $flat -Connection $Connection $result.ContainerId = [string]$container.Id $result.Success = $true return $result } else { # EXISTING: re-fetch fresh to get a clean version, then update $fresh = Get-PnPTerm -Identity $container.Id -Connection $Connection foreach ($k in $flat.Keys) { $fresh.SetCustomProperty([string]$k, [string]$flat[$k]) } Invoke-PnPQuery -RetryCount 5 -Connection $Connection $result.ContainerId = [string]$fresh.Id $result.Success = $true return $result } } catch { $result.Error = $_.Exception.Message return $result } } |