FilterBox/SRxCustomizationJson.psm1
|
$script:SRxJsonChunkSize = 9000 function Compress-SRxText { [CmdletBinding()] param([Parameter(Mandatory)][AllowEmptyString()][string]$Text) if ([string]::IsNullOrEmpty($Text)) { return '' } $bytes = [System.Text.Encoding]::UTF8.GetBytes($Text) $ms = New-Object System.IO.MemoryStream $gz = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Compress) $gz.Write($bytes, 0, $bytes.Length) $gz.Close() $out = [Convert]::ToBase64String($ms.ToArray()) $ms.Dispose() return $out } function Expand-SRxText { [CmdletBinding()] param([Parameter(Mandatory)][AllowEmptyString()][string]$Base64) if ([string]::IsNullOrEmpty($Base64)) { return '' } $data = [Convert]::FromBase64String($Base64) $ms = New-Object System.IO.MemoryStream(,$data) $gz = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress) $sr = New-Object System.IO.StreamReader($gz, [System.Text.Encoding]::UTF8) $out = $sr.ReadToEnd() $sr.Close(); $gz.Dispose(); $ms.Dispose() return $out } function Split-SRxJsonProperty { [CmdletBinding()] param([Parameter(Mandatory)][string]$BaseKey, [Parameter(Mandatory)][AllowEmptyString()][string]$Value, [int]$ChunkSize = $script:SRxJsonChunkSize) $out = @{} if ($Value.Length -le $ChunkSize) { $out[$BaseKey] = $Value; return $out } $parts = @($Value -split ("(.{$ChunkSize})") | Where-Object { $_ }) for ([int]$i = 0; $i -lt $parts.Count; $i++) { $out["$($BaseKey)_$($i)"] = $parts[$i] } return $out } function Join-SRxJsonProperty { [CmdletBinding()] param([Parameter(Mandatory)]$Properties, [string]$BaseKey = 'ts_CustomizationJson') $map = @{} if ($Properties -is [hashtable]) { foreach ($k in $Properties.Keys) { $map[[string]$k] = [string]$Properties[$k] } } else { foreach ($p in @($Properties)) { if ($null -eq $p) { continue } $k = if ($p.PSObject.Properties['Key']) { [string]$p.Key } else { $null } if ($null -ne $k) { $map[$k] = [string]$p.Value } } } if ($map.ContainsKey($BaseKey)) { return [string]$map[$BaseKey] } $chunkKeys = @($map.Keys | Where-Object { $_ -match ("^" + [regex]::Escape($BaseKey) + "_\d+$") } | Sort-Object { [int]($_ -replace ("^" + [regex]::Escape($BaseKey) + "_"), '') }) if ($chunkKeys.Count -eq 0) { return $null } $sb = New-Object System.Text.StringBuilder foreach ($ck in $chunkKeys) { [void]$sb.Append($map[$ck]) } return $sb.ToString() } function Get-SRxCustomizationKey { [CmdletBinding()] param([Parameter(Mandatory)][AllowEmptyString()][string]$LeafXPath, [int]$Optype = -1, [int]$Scope = -1) return ("{0}|{1}|{2}" -f $LeafXPath, $Optype, $Scope) } function Get-SRxShortHash { [CmdletBinding()] param([Parameter(Mandatory)][string]$Text) $md5 = [System.Security.Cryptography.MD5]::Create() $bytes = $md5.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Text)) $md5.Dispose() return (($bytes | ForEach-Object { $_.ToString('x2') }) -join '').Substring(0, 8) } function ConvertTo-SRxAttrHash { param($Attributes) $h = @{} if ($Attributes -is [hashtable]) { foreach ($k in $Attributes.Keys) { $h[[string]$k] = [string]$Attributes[$k] } } elseif ($null -ne $Attributes) { foreach ($p in $Attributes.PSObject.Properties) { $h[$p.Name] = [string]$p.Value } } return $h } function ConvertTo-SRxCustomizationSubtree { [CmdletBinding()] param([Parameter(Mandatory)]$Branch) $arr = @($Branch) if ($arr.Count -eq 0) { return $null } $node = $null for ([int]$i = 0; $i -lt $arr.Count; $i++) { $d = $arr[$i] $attrs = ConvertTo-SRxAttrHash $d.Attributes $isDep = $false if ($attrs.ContainsKey('ts_Deprecated')) { $isDep = ([string]$attrs['ts_Deprecated'] -ieq 'true') } $cp = @() foreach ($k in ($attrs.Keys | Sort-Object)) { $cp += [pscustomobject]@{ Key = [string]$k; Value = [string]$attrs[$k] } } $newNode = [pscustomobject]@{ Name = [string]$d.Name IsDeprecated = [bool]$isDep CustomProperties = $cp Terms = @() } if ($null -ne $node) { $newNode.Terms = @($node) } $node = $newNode } return $node } function Repair-SRxSubtree { [CmdletBinding()] param([Parameter(Mandatory)]$Node) if ($null -eq $Node) { return $null } $cp = @() if ($Node.PSObject.Properties['CustomProperties'] -and $null -ne $Node.CustomProperties) { foreach ($p in @($Node.CustomProperties)) { if ($null -eq $p) { continue } $cp += [pscustomobject]@{ Key = [string]$p.Key; Value = [string]$p.Value } } } $terms = @() if ($Node.PSObject.Properties['Terms'] -and $null -ne $Node.Terms) { foreach ($t in @($Node.Terms)) { $rt = Repair-SRxSubtree -Node $t; if ($rt) { $terms += $rt } } } $isDep = $false if ($Node.PSObject.Properties['IsDeprecated']) { $isDep = [bool]$Node.IsDeprecated } return [pscustomobject]@{ Name = [string]$Node.Name IsDeprecated = [bool]$isDep CustomProperties = $cp Terms = $terms } } function Expand-SRxJsonCustomization { [CmdletBinding()] param([Parameter(Mandatory)]$Term) try { $props = if ($Term.PSObject.Properties['CustomProperties']) { $Term.CustomProperties } else { @() } $payload = Join-SRxJsonProperty -Properties $props -BaseKey 'ts_CustomizationJson' if ([string]::IsNullOrEmpty($payload)) { return $null } $json = Expand-SRxText -Base64 $payload if ([string]::IsNullOrEmpty($json)) { return $null } $obj = $json | ConvertFrom-Json return (Repair-SRxSubtree -Node $obj) } catch { Write-Host "Expand-SRxJsonCustomization - $($_.Exception.Message)"; return $null } } function New-SRxJsonContainerTerm { [CmdletBinding()] param([Parameter(Mandatory)]$Pack, [Parameter(Mandatory)][string]$Operation) $branch = $Pack.Branch $leafX = '' if (@($branch).Count -gt 0) { $leafX = [string](@($branch)[0].XPath) } $optype = -1 if ($Pack.PSObject.Properties['Optype'] -and $null -ne $Pack.Optype) { $optype = [int]$Pack.Optype } $scope = -1 if ($Pack.PSObject.Properties['Scope'] -and $null -ne $Pack.Scope) { $scope = [int]$Pack.Scope } $key = Get-SRxCustomizationKey -LeafXPath $leafX -Optype $optype -Scope $scope $name = 'C_' + (Get-SRxShortHash $key) $attrs = @{ 'ts_ProvisioningActivity' = 'Optimize-SiteTemplate' 'ts_CustomizationFormat' = 'JSON' 'ts_CustomizationKey' = $key } if ($Operation -ne 'remove') { $subtree = ConvertTo-SRxCustomizationSubtree -Branch $branch $json = $subtree | ConvertTo-Json -Depth 60 -Compress $attrs['ts_CustomizationJson'] = (Compress-SRxText -Text $json) } return [pscustomobject]@{ Name = $name Attributes = $attrs Scope = $scope xPath = $leafX Operation = $Operation optype = $optype Key = $key } } Export-ModuleMember -Function ` Compress-SRxText, Expand-SRxText, ` Split-SRxJsonProperty, Join-SRxJsonProperty, ` Get-SRxCustomizationKey, Get-SRxShortHash, ` ConvertTo-SRxAttrHash, ConvertTo-SRxCustomizationSubtree, Repair-SRxSubtree, ` Expand-SRxJsonCustomization, New-SRxJsonContainerTerm |