Modules/IdLE.Core/Private/Copy-IdleDataObject.ps1
|
function Copy-IdleDataObject { <# .SYNOPSIS Creates a deep-ish, data-only copy of an object. .DESCRIPTION This helper is used to snapshot data-like objects so that exported or executed artifacts do not retain references to caller-owned objects. NOTE: This is intentionally conservative and only supports data-like objects: - Hashtable / OrderedDictionary - PSCustomObject / NoteProperties - Arrays/lists - Primitive types ScriptBlocks and other executable objects are rejected by upstream validation. #> [CmdletBinding()] param( [Parameter()] [AllowNull()] [object] $Value ) if ($null -eq $Value) { return $null } # Primitive / immutable types should be returned as-is before property inspection. # This prevents strings from being converted to PSCustomObject with Length property. if ($Value -is [string] -or $Value -is [int] -or $Value -is [long] -or $Value -is [double] -or $Value -is [decimal] -or $Value -is [bool] -or $Value -is [datetime] -or $Value -is [guid]) { return $Value } if ($Value -is [System.Collections.IDictionary]) { $copy = @{} foreach ($k in $Value.Keys) { $copy[$k] = Copy-IdleDataObject -Value $Value[$k] } return $copy } if ($Value -is [System.Collections.IEnumerable] -and $Value -isnot [string]) { $arr = @() foreach ($item in $Value) { $arr += Copy-IdleDataObject -Value $item } return $arr } $props = @($Value.PSObject.Properties | Where-Object MemberType -in @('NoteProperty', 'Property')) if ($null -ne $props -and @($props).Count -gt 0) { $o = [ordered]@{} foreach ($p in $props) { $o[$p.Name] = Copy-IdleDataObject -Value $p.Value } return [pscustomobject]$o } return $Value } |