Private/Shared/ConvertTo-SafeJson.ps1
| function ConvertTo-SafeJson { <# .SYNOPSIS Converts an object to JSON while masking sensitive properties to prevent them from appearing in logs. .DESCRIPTION This function creates a safe copy of an object and masks sensitive properties before converting to JSON. It's designed to prevent sensitive information like tokens, passwords, and secrets from being exposed in logs. .PARAMETER InputObject The object to convert to JSON. .PARAMETER Depth The maximum depth of the JSON conversion. .PARAMETER SensitiveProperties Array of property name patterns that should be masked. Supports wildcard matching. .EXAMPLE ConvertTo-SafeJson $inputConfig -Depth 100 .EXAMPLE ConvertTo-SafeJson $parameters -SensitiveProperties @('token', 'password', 'secret') #> param( [Parameter(Mandatory = $true)] [AllowNull()] [object] $InputObject, [Parameter(Mandatory = $false)] [int] $Depth = 100, [Parameter(Mandatory = $false)] [string[]] $SensitiveProperties = @('github_token', 'githubToken', 'token', 'password', 'secret', 'key', 'credential', 'auth') ) if ($null -eq $InputObject) { return "null" } # Create a deep copy of the object to avoid modifying the original try { $jsonString = $InputObject | ConvertTo-Json -Depth $Depth -ErrorAction Stop $safeCopy = $jsonString | ConvertFrom-Json -ErrorAction Stop } catch { # If JSON conversion fails, return a safe string representation return "Unable to convert object to JSON: $($_.Exception.Message)" } # Function to recursively mask sensitive properties function Hide-SensitiveProperty { param([object] $obj) if ($null -eq $obj) { return } if ($obj -is [PSCustomObject]) { $obj.PSObject.Properties | ForEach-Object { $propertyName = $_.Name $propertyValue = $_.Value # Check if this property name contains sensitive information $isSensitive = $false foreach ($sensitivePattern in $SensitiveProperties) { if ($propertyName -like "*$sensitivePattern*") { $isSensitive = $true break } } if ($isSensitive -and $null -ne $propertyValue -and $propertyValue -ne "") { # Check if it's a nested object with Value property (like inputConfig structure) if ($propertyValue -is [PSCustomObject] -and $propertyValue.PSObject.Properties['Value']) { if ($null -ne $propertyValue.Value -and $propertyValue.Value -ne "") { $propertyValue.Value = "***MASKED***" } } else { # Direct property assignment $obj.$propertyName = "***MASKED***" } } elseif ($propertyValue -is [PSCustomObject] -or $propertyValue -is [array]) { # Recursively process nested objects if ($propertyValue -is [array]) { $propertyValue | ForEach-Object { Hide-SensitiveProperty $_ } } else { Hide-SensitiveProperty $propertyValue } } } } elseif ($obj -is [hashtable]) { $keysToMask = @() foreach ($key in $obj.Keys) { $isSensitive = $false foreach ($sensitivePattern in $SensitiveProperties) { if ($key -like "*$sensitivePattern*") { $isSensitive = $true break } } if ($isSensitive) { $keysToMask += $key } elseif ($obj[$key] -is [PSCustomObject] -or $obj[$key] -is [hashtable] -or $obj[$key] -is [array]) { Hide-SensitiveProperty $obj[$key] } } $keysToMask | ForEach-Object { if ($null -ne $obj[$_] -and $obj[$_] -ne "") { $obj[$_] = "***MASKED***" } } } } # Mask sensitive properties in the copy Hide-SensitiveProperty $safeCopy # Convert back to JSON try { return ($safeCopy | ConvertTo-Json -Depth $Depth) } catch { return "Unable to convert masked object to JSON: $($_.Exception.Message)" } } |