Say I have a hashtable like this:
$headers = @{
'Content-Type'='application/json'
'Authorization'= "Api-Key 123456789"
}
When I run that, I get the hashtable placed in the $headers variable.
My question is, is there a way, using one line of code) to get it write back out like this?
@{'Content-Type'='application/json'; 'Authorization'= "Api-Key 123456789" }
The closest I can come is something like this:
$headers.GetEnumerator() | ForEach-Object{"`"$($_.Name)`" = `"$($_.Value)`";"}
But that has the output on two lines, and adds an extra ; and does not have the surrounding @{ }
CodePudding user response:
Casting a type of [PSCustomObject]
and stringifying it will give you those results:
"$([pscustomobject]$headers)"
returns:
@{Authorization=Api-Key 123456789; Content-Type=application/json}
CodePudding user response:
You lose quotes with Abraham's helpful answer. If you really need the quotes you could use something like this
($headers | ConvertTo-Json -Compress) -replace ',',';' -replace '^','@'
@{"Authorization":"Api-Key 123456789";"Content-Type":"application/json"}
CodePudding user response:
Fundamentally, converting a hashtable instance to its equivalent source-code representation only works in simple cases, such as yours.
- Converting is fundamentally limited to instance of those data types that (a) can be represented as literals and (b) whose values doesn't rely on being a specific instance of a .NET reference type.
A best-effort implementation is iRon's
ConvertTo-Expression
function, though it currently lacks a single-line output option.Ideally, PowerShell itself would provide such a command, in the form of the inverse of the
Import-PowerShellDataFile
cmdlet.- GitHub issue #2875 suggests adding a complementary
Export-PowerShellDataFile
cmdlet, and the related GitHub issue #11300 also discusses in-memory versions to complement the file-based ones.
- GitHub issue #2875 suggests adding a complementary
Here's an approximation of this functionality:
# Sample input hashtable.
$headers = [ordered] @{
'Content-Type' = 'application/json'
Authorization = "Api-Key 123456789"
AnArray = 1, 'two',3, '3" of snow'
ABool = $true
}
# Try to convert the above back into a source-code representation.
$headers.GetEnumerator() |
ForEach-Object `
-Begin { $entries = [Collections.Generic.List[string]] @() } `
-Process {
$name =
if ($_.Name -match '\W') { "'{0}'" -f ($_.Name -replace "'", "''") }
else { $_.Name }
$values =
$_.Value | ForEach-Object {
if ($_ -is [string]) { "'{0}'" -f ($_ -replace "'", "''") }
elseif ($_ -is [bool]) { '$' "$_".ToLower() }
else { $_ } # !! More work is needed here for increased type fidelity.
}
$entries.Add("$name = $($values -join ', ')")
} `
-End { '@{ ' ($entries -join '; ') ' }' }
Output:
@{ 'Content-Type'='application/json'; Authorization='Api-Key 123456789'; AnArray=1, 'two', 3, '6'' tall'; ABool=$true }
Limitations:
Type-faithful representations:
Strings are single-quoted with appropriate escaping of embedded
'
characters.Booleans are recognized and represented as
$true
or$false
.
Any other data type is represented unquoted:
- This works with numeric types only...
- ...and even there the specific input number type may be lost.
Only flat collections of values are supported, which are invariably represented as PowerShell array literals of type
[object[]]
(i.e., any specific collection type other than array and any strong array typing is lost), with each element represented according to the rules above.