Home > front end >  Script out a hashtable with PowerShell
Script out a hashtable with PowerShell

Time:08-30

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.

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.

  • Related