ConvertToPsd1.psm1
function ConvertTo-Psd1 { <# .SYNOPSIS Converts objects into psd1 string. .DESCRIPTION Converts objects into psd1 string. .PARAMETER InputObject The item(s) to convert .PARAMETER Depth How deeply nested information will be picked up. This command will automatically prevent infinite recursion, even without the -Depth parameter. .PARAMETER WriteError If the object in the input file has any issues, should an error be generated? Otherwise, just a warning will be given. Note: ErrorAction stop will always lead to terminating errors in case of parsing issues. .EXAMPLE PS C:\> Get-ChildItem | ConvertTo-Psd1 Converts all files & folders in the current path to a psd1-string representing its contents. Each file processed separately. #> [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [object[]] $InputObject, [int] $Depth, [switch] $WriteError ) begin { $converter = [converter]::new($PSCmdlet, $WriteError, ($ErrorActionPreference -eq 'Stop'), $Depth) } process { foreach ($item in $InputObject) { $converter.Convert($item) } } } function ConvertTo-Psd1File { <# .SYNOPSIS Converts json files to psd1. .DESCRIPTION Converts json files to psd1. The psd1 file will be placed in the same path under the same name with just the extension updated. .PARAMETER Path Path to the files to convert. .PARAMETER OutPath Path where the resultant file should be placed. By default, it will be placed in the same path as the source file. .PARAMETER Depth How deeply nested information will be picked up. This command will automatically prevent infinite recursion, even without the -Depth parameter. .PARAMETER WriteError If the object in the input file has any issues, should an error be generated? Otherwise, just a warning will be given. Note: ErrorAction stop will always lead to terminating errors in case of parsing issues. .EXAMPLE PS C:\> Get-ChildItem -Path . -Filter *.json | ConvertTo-Psd1File Converts all json files in the current directory to psd1. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('FullName')] [string[]] $Path, [string] $OutPath, [int] $Depth, [switch] $WriteError ) begin { $converter = [converter]::new($PSCmdlet, $WriteError, ($ErrorActionPreference -eq 'Stop'), $Depth) } process { foreach ($filePath in $Path) { $item = Get-Item -Path $filePath $data = Get-Content -LiteralPath $item.FullName | ConvertFrom-Json $lines = foreach ($entry in $data) { $converter.Convert($entry) } if ($OutPath) { $exportPath = Join-Path -Path $OutPath -ChildPath "$($item.BaseName).psd1" } else { $exportPath = Join-Path -Path $item.DirectoryName -ChildPath "$($item.BaseName).psd1" } $lines | Set-Content -LiteralPath $exportPath } } } class Converter { [object] $Cmdlet [bool] $ThrowOnUnknown [bool] $Terminate [int] $Depth Converter([object]$Cmdlet, [bool] $ThrowOnUnknown, [bool] $Terminate, [int]$Depth) { $this.Cmdlet = $Cmdlet $this.ThrowOnUnknown = $ThrowOnUnknown $this.Terminate = $Terminate $this.Depth = $Depth } [string] ConvertValue([object] $Value, [object[]]$Parents, [int]$Depth) { # Those number-thingies if ($Value -is [int] -or $Value -is [long] -or $Value -is [double]) { return '{0}' -f $Value } # Case: Bool if ($Value -is [bool] -or $Value -is [System.Management.Automation.SwitchParameter]) { return '${0}' -f $Value } # Case: Null if ($null -eq $Value -or $Value -is [System.DBNull]) { return '$null' } # Case: DateTime if ($Value -is [datetime]) { return "'{0:yyyy-MM-dd HH:mm:ss.fffff zzz}'" -f $Value.ToUniversalTime() } # Case: Guid if ($Value -is [guid]) { return "'$Value'" } # Case: Version if ($Value -is [version]) { return "'$Value'" } # Case: String if ($Value -is [string] -or $Value -is [char] -or $Value -is [System.Uri]) { return '''{0}''' -f ([System.Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($Value)) } # Case: Hashtable if ($Value -is [System.Collections.IDictionary]) { return $this.ConvertHashtable($Value, $Parents, $Depth) } # Case: IEnumerable if ($Value -is [System.Collections.IEnumerable]) { $oldIndent = ' ' * $Depth $newIndent = ' ' * ($Depth + 1) $newParent = @($Parents) + ,$Value $pieces = @("@(") foreach ($entry in $Value) { $pieces += $newIndent + $this.ConvertValue($entry, $newParent, $Depth) } $pieces += "$oldIndent)" return $pieces -join "`n" } # Case: Enum if ($Value -is [enum]) { return "'{0}'" -f ([System.Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($Value)) } # Case: Assembly if ($Value -is [System.Reflection.Assembly] -or $Value -is [System.Reflection.TypeInfo]) { return "'{0}'" -f $Value.FullName } if ($Value -is [System.Management.Automation.ProviderInfo] -or $Value -is [System.Management.Automation.PSDriveInfo]) { return "'{0}'" -f $Value.Name } # Case: PSCustomObject if ($Value -is [PSCustomObject] -or $Value.PSObject.Properties.Count -gt 0) { return $this.ConvertPSCustomObject($Value, $Parents, $Depth) } $message = "Unexpected data entry: $Value ($($Value.GetType().FullName))" if ($this.ThrowOnUnknown -or $this.Terminate) { if ($null -eq $this.Cmdlet) { throw $message } $record = [System.Management.Automation.ErrorRecord]::new( [System.Management.Automation.ParseException]::new($message), 'BadData', [System.Management.Automation.ErrorCategory]::ParserError, $Value ) if ($this.Terminate) { $this.Cmdlet.ThrowTerminatingError($record) } $this.Cmdlet.WriteError($record) } $this.Cmdlet.WriteWarning($message) return "'{0}'" -f ("$Value" -replace "'", "''") } [string] ConvertHashtable([System.Collections.IDictionary]$Value, [object[]]$Parents, [int]$Depth) { if ($Value -in $Parents) { return "'System.Collections.Hashtable (recursed)'" } $newDepth = $Depth + 1 if ($this.Depth -gt 0 -and $newDepth -gt $this.Depth) { return "'System.Collections.Hashtable'" } $oldIndent = ' ' * $Depth $newIndent = ' ' * $newDepth $newParents = @($Parents) + $Value $lines = @("$oldIndent@{") foreach ($entry in $Value.GetEnumerator()) { if ($Parents[-1] -is [System.IO.FileSystemInfo] -and $entry.Key -in 'Root', 'Parent', 'Directory') { $lines += '{2}{0} = ''{1}''' -f $entry.Key, $entry.Value, $newIndent continue } $lines += '{2}{0} = {1}' -f $entry.Key, $this.ConvertValue($entry.Value, $newParents, $newDepth), $newIndent } $lines += "$oldIndent}" return $lines -join "`n" } [string] ConvertPSCustomObject([object]$Value, [object[]]$Parents, [int]$Depth) { if ($Value -in $Parents) { return "'$($Value.GetType().FullName) (recursed)'" } if ($this.Depth -gt 0 -and $Depth -ge $this.Depth) { return "'$($Value.GetType().FullName)'" } $newParents = @($Parents) + $Value $hash = [ordered]@{} foreach ($property in $Value.PSObject.Properties) { $hash[$property.Name] = $property.Value } return $this.ConvertHashtable($hash, $newParents, $Depth) } [string] Convert([object]$Value) { if ($Value -is [System.Collections.IDictionary]) { return $this.ConvertHashtable($Value, @(), 0) } if ($Value -isnot [PSCustomObject]) { return $this.ConvertValue($Value, @(), 0) } return $this.ConvertPSCustomObject($Value, @(), 0) } } |