Includes/PwSh.Fw.Object.Bash.psm1
|
<#
.SYNOPSIS Converts PowerShell objects to Linux shell-compatible variables .DESCRIPTION Converts any PowerShell object (hashtable, array, PSCustomObject, etc.) into Linux shell variables that can be sourced as a .rc file. Handles different data types appropriately for bash interpretation. .PARAMETER InputObject The PowerShell object to convert to shell variables .PARAMETER Prefix Optional prefix to add to all variable names .PARAMETER Export If specified, adds an 'export' line after each 'declare' line to make variables available to child processes .PARAMETER Flat If specified, flattens nested objects instead of creating separate associative arrays .PARAMETER DateTimeFormat Format for DateTime values: 'String' (default), 'Timestamp', or 'ISO' .PARAMETER Strict If specified, shows warnings when variable names are sanitized .EXAMPLE ConvertTo-LinuxShellData -InputObject $data -Prefix "PROJECT" Converts a hashtable to shell variables with PROJECT_ prefix .EXAMPLE ConvertTo-LinuxShellData -InputObject $data -Prefix "PROJECT" -Export Converts and exports variables for child processes .EXAMPLE ConvertTo-LinuxShellData -InputObject $data -Flat Flattens nested objects into single-level variables .NOTES Author: Your Name Date: 2024 #> function ConvertTo-LinuxShellData { [CmdletBinding()] [OutputType([String])] Param ( [parameter(Mandatory, ValueFromPipeline = $True)] $InputObject, [string]$Prefix = "", [switch]$Export, [switch]$Flat, [ValidateSet('String', 'Timestamp', 'ISO')] [string]$DateTimeFormat = 'String', [switch]$Strict ) Begin { # Write-EnterFunction } Process { $output = @() if ($InputObject -is [hashtable]) { $output += ConvertTo-BashHashtable -Hashtable $InputObject -Prefix $Prefix -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict } elseif ($InputObject -is [array] -or $InputObject -is [System.Collections.ArrayList]) { $varName = Sanitize-VariableName -Name (if ($Prefix) { "${Prefix}_ARRAY" } else { "ARRAY" }) -Strict:$Strict $output += ConvertTo-BashArray -Name $varName -Value $InputObject -Export:$Export } elseif ($InputObject -is [PSCustomObject]) { $output += ConvertTo-BashCustomObject -Object $InputObject -Prefix $Prefix -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict } else { $varName = Sanitize-VariableName -Name (if ($Prefix) { "${Prefix}_VALUE" } else { "VALUE" }) -Strict:$Strict $output += ConvertTo-BashVariable -Name $varName -Value $InputObject -Export:$Export -DateTimeFormat $DateTimeFormat } return $output -join "`n" } End { # Write-LeaveFunction } } <# .SYNOPSIS Sanitizes variable names for Linux shell compatibility .DESCRIPTION Converts variable names to be compatible with bash naming conventions (uppercase, underscores only, no leading numbers) .PARAMETER Name The variable name to sanitize .PARAMETER Strict If specified, shows warnings when variable names are modified .EXAMPLE Sanitize-VariableName -Name "Project-Name" Returns: PROJECT_NAME .NOTES Author: Your Name Date: 2024 #> function Sanitize-VariableName { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="Sanitize is an intuitive verb for this function.")] [CmdletBinding()] [OutputType([String])] Param ( [string]$Name, [switch]$Strict ) Begin { # Write-EnterFunction } Process { # Convert to uppercase and replace invalid characters with underscore $sanitized = $Name -replace '[^a-zA-Z0-9]', '_' $sanitized = $sanitized -replace '_+', '_' $sanitized = $sanitized -replace '^_+', '' $sanitized = $sanitized -replace '_+$', '' # If starts with number, prepend underscore if ($sanitized -match '^[0-9]') { $sanitized = "_${sanitized}" } if ($Strict -and $sanitized -ne $Name) { Write-Warning "Variable name '$Name' sanitized to '$sanitized'" } return $sanitized } End { # Write-LeaveFunction } } <# .SYNOPSIS Converts a single PowerShell value to a bash variable declaration .DESCRIPTION Converts a single value (string, int, bool, datetime, etc.) to a bash variable declaration .PARAMETER Name The variable name .PARAMETER Value The value to convert .PARAMETER Export If specified, adds an 'export' line after the declaration .PARAMETER DateTimeFormat Format for DateTime values: 'String' (default), 'Timestamp', or 'ISO' .EXAMPLE ConvertTo-BashVariable -Name "NAME" -Value "MyProject" Returns: declare NAME='MyProject' .NOTES Author: Your Name Date: 2024 #> function ConvertTo-BashVariable { [CmdletBinding()] [OutputType([String])] Param ( [string]$Name, $Value, [switch]$Export, [ValidateSet('String', 'Timestamp', 'ISO')] [string]$DateTimeFormat = 'String' ) Begin { # Write-EnterFunction } Process { $name = Sanitize-VariableName -Name $Name if ($null -eq $Value) { $output = @() $output += "declare ${name}=""" if ($Export) { $output += "export ${name}" } return $output -join "`n" } elseif ($Value -is [bool]) { $bashValue = if ($Value) { "true" } else { "false" } $output = @() $output += "declare ${name}=${bashValue}" if ($Export) { $output += "export ${name}" } return $output -join "`n" } elseif ($Value -is [int] -or $Value -is [double] -or $Value -is [decimal]) { $output = @() $output += "declare ${name}=${Value}" if ($Export) { $output += "export ${name}" } return $output -join "`n" } elseif ($Value -is [datetime]) { $output = @() switch ($DateTimeFormat) { 'Timestamp' { $output += "declare ${name}=\$(date -d '${Value}' +%s)" } 'ISO' { $output += "declare ${name}='${Value.ToString("o")}'" } default { $output += "declare ${name}='${Value.ToString("yyyy-MM-dd HH:mm:ss")}'" } } if ($Export) { $output += "export ${name}" } return $output -join "`n" } elseif ($Value -is [string]) { $output = @() $escaped = Escape-BashString -Value $Value $output += "declare ${name}='${escaped}'" if ($Export) { $output += "export ${name}" } return $output -join "`n" } elseif ($Value -is [array] -or $Value -is [System.Collections.ArrayList]) { return ConvertTo-BashArray -Name $name -Value $Value -Export:$Export } elseif ($Value -is [hashtable]) { return ConvertTo-BashAssociativeArray -Name $name -Value $Value -Export:$Export } else { $strValue = [string]$Value $output = @() $escaped = Escape-BashString -Value $strValue $output += "declare ${name}='${escaped}'" if ($Export) { $output += "export ${name}" } return $output -join "`n" } } End { # Write-LeaveFunction } } <# .SYNOPSIS Converts a PowerShell array to a bash indexed array .DESCRIPTION Converts a PowerShell array to a bash indexed array declaration with proper escaping .PARAMETER Name The array variable name .PARAMETER Value The array to convert .PARAMETER Export If specified, adds an 'export' line after the declaration .EXAMPLE ConvertTo-BashArray -Name "ITEMS" -Value @("a", "b", "c") Returns: declare -a ITEMS=([0]='a' [1]='b' [2]='c') .NOTES Author: Your Name Date: 2024 #> function ConvertTo-BashArray { [CmdletBinding()] [OutputType([String])] Param ( [string]$Name, [array]$Value, [switch]$Export ) Begin { # Write-EnterFunction } Process { $name = Sanitize-VariableName -Name $Name # Write-Devel "name = $name" if ($Value.Count -eq 0) { $output = @() $output += "declare -a ${name}=()" if ($Export) { $output += "export ${name}" } return $output -join "`n" } $elements = @() $i=0 foreach ($item in $Value) { # Write-Devel "item = $item" $element = "[$(($i++))]=" if ($null -eq $item) { $element += '""' } elseif ($item -is [int]) { $element += "${item}" } elseif ($item -is [string]) { $escaped = Escape-BashString -Value $item $element += "'${escaped}'" } else { $strItem = [string]$item $escaped = Escape-BashString -Value $strItem $element += "'${escaped}'" } $elements += $element # Write-Devel "escaped = $escaped" } $output = @() $output += "declare -a ${name}=($($elements -join ' '))" if ($Export) { $output += "export ${name}" } return $output -join "`n" } End { # Write-LeaveFunction } } <# .SYNOPSIS Converts a PowerShell hashtable to a bash associative array .DESCRIPTION Converts a PowerShell hashtable to a bash associative array declaration with proper escaping .PARAMETER Name The associative array variable name .PARAMETER Value The hashtable to convert .PARAMETER Export If specified, adds an 'export' line after the declaration .EXAMPLE ConvertTo-BashAssociativeArray -Name "CONFIG" -Value @{Port=8080; Host="localhost"} Returns: declare -A CONFIG=('Port'=8080 'Host'='localhost') .NOTES Author: Your Name Date: 2024 #> function ConvertTo-BashAssociativeArray { [CmdletBinding()] [OutputType([String])] Param ( [string]$Name, [hashtable]$Value, [switch]$Export ) Begin { # Write-EnterFunction } Process { $name = Sanitize-VariableName -Name $Name # Write-Devel "name = $name" if ($Value.Count -eq 0) { $output = @() $output += "declare -A ${name}=()" if ($Export) { $output += "export ${name}" } return $output -join "`n" } $pairs = @() foreach ($key in $Value.Keys) { # Write-Devel "key = $key" $keyEscaped = Escape-BashString -Value $key $val = $Value[$key] if ($null -eq $val) { $valEscaped = '""' } elseif ($val -is [int]) { $valEscaped = [string]${val} } elseif ($val -is [string]) { $valEscaped = "'$(Escape-BashString -Value $val)'" } else { $valEscaped = "'$(Escape-BashString -Value ([string]$val))'" } # Write-Devel "valEscaped = $valEscaped" $pairs += "'${keyEscaped}'=${valEscaped}" } $output = @() $output += "declare -A ${name}=($($pairs -join ' '))" if ($Export) { $output += "export ${name}" } return $output -join "`n" } End { # Write-LeaveFunction } } <# .SYNOPSIS Converts a PowerShell hashtable to bash variables .DESCRIPTION Converts a hashtable to multiple bash variable declarations, handling nested objects recursively .PARAMETER Hashtable The hashtable to convert .PARAMETER Prefix Optional prefix to add to all variable names .PARAMETER Export If specified, adds 'export' lines after declarations .PARAMETER Flat If specified, flattens nested objects instead of creating separate associative arrays .PARAMETER DateTimeFormat Format for DateTime values: 'String' (default), 'Timestamp', or 'ISO' .PARAMETER Strict If specified, shows warnings when variable names are sanitized .EXAMPLE ConvertTo-BashHashtable -Hashtable $data -Prefix "PROJECT" .NOTES Author: Your Name Date: 2024 #> function ConvertTo-BashHashtable { [CmdletBinding()] [OutputType([String])] Param ( [hashtable]$Hashtable, [string]$Prefix, [switch]$Export, [switch]$Flat, [ValidateSet('String', 'Timestamp', 'ISO')] [string]$DateTimeFormat = 'String', [switch]$Strict ) Begin { # Write-EnterFunction } Process { $output = @() foreach ($key in $Hashtable.Keys) { $varName = Sanitize-VariableName -Name $(if ($Prefix) { "${Prefix}_${key}" } else { $key }) -Strict:$Strict $value = $Hashtable[$key] if ($value -is [hashtable] -or $value -is [PSCustomObject]) { if ($Flat) { # Flatten nested objects $output += ConvertTo-BashHashtable -Hashtable $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict } else { # Create separate associative array if ($value -is [hashtable]) { $output += ConvertTo-BashAssociativeArray -Name $varName -Value $value -Export:$Export } else { $output += ConvertTo-BashCustomObject -Object $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict } } } else { $output += ConvertTo-BashVariable -Name $varName -Value $value -Export:$Export -DateTimeFormat $DateTimeFormat } } return $output } End { # Write-LeaveFunction } } <# .SYNOPSIS Converts a PSCustomObject to bash variables .DESCRIPTION Converts a PSCustomObject to multiple bash variable declarations, handling nested objects recursively .PARAMETER Object The PSCustomObject to convert .PARAMETER Prefix Optional prefix to add to all variable names .PARAMETER Export If specified, adds 'export' lines after declarations .PARAMETER Flat If specified, flattens nested objects instead of creating separate associative arrays .PARAMETER DateTimeFormat Format for DateTime values: 'String' (default), 'Timestamp', or 'ISO' .PARAMETER Strict If specified, shows warnings when variable names are sanitized .EXAMPLE ConvertTo-BashCustomObject -Object $project -Prefix "APP" .NOTES Author: Your Name Date: 2024 #> function ConvertTo-BashCustomObject { [CmdletBinding()] [OutputType([String])] Param ( [PSCustomObject]$Object, [string]$Prefix, [switch]$Export, [switch]$Flat, [ValidateSet('String', 'Timestamp', 'ISO')] [string]$DateTimeFormat = 'String', [switch]$Strict ) Begin { # Write-EnterFunction } Process { $output = @() foreach ($prop in $Object.PSObject.Properties) { $varName = Sanitize-VariableName -Name (if ($Prefix) { "${Prefix}_${prop.Name}" } else { $prop.Name }) -Strict:$Strict $value = $prop.Value if ($value -is [hashtable] -or $value -is [PSCustomObject]) { if ($Flat) { if ($value -is [hashtable]) { $output += ConvertTo-BashHashtable -Hashtable $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict } else { $output += ConvertTo-BashCustomObject -Object $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict } } else { if ($value -is [hashtable]) { $output += ConvertTo-BashAssociativeArray -Name $varName -Value $value -Export:$Export } else { $output += ConvertTo-BashCustomObject -Object $value -Prefix $varName -Export:$Export -Flat:$Flat -DateTimeFormat $DateTimeFormat -Strict:$Strict } } } else { $output += ConvertTo-BashVariable -Name $varName -Value $value -Export:$Export -DateTimeFormat $DateTimeFormat } } return $output } End { # Write-LeaveFunction } } <# .SYNOPSIS Escapes a string for safe use in bash single-quoted strings .DESCRIPTION Escapes special characters in a string to make it safe for use in bash single-quoted strings .PARAMETER Value The string to escape .EXAMPLE Escape-BashString -Value "It's a test" Returns: It'\''s a test .NOTES Author: Your Name Date: 2024 #> function Escape-BashString { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="Escape is an intuitive verb for this function.")] [CmdletBinding()] [OutputType([String])] Param ( [string]$Value ) Begin { # Write-EnterFunction } Process { if ($null -eq $Value) { return "" } # Escape single quotes for single-quoted strings $escaped = $Value -replace "'", "'" # Escape special characters $escaped = $escaped -replace "`n", '\n' $escaped = $escaped -replace "`r", '\r' $escaped = $escaped -replace "`t", '\t' $escaped = $escaped -replace "```$", '\$' # $escaped = $escaped -replace "\\", '\\\\' return $escaped } End { # Write-LeaveFunction } } |