Question

PowerShell 7+ parse querystring-style strings into HashTable

I'm trying to avoid the apparent mess that is the .NET Core querystring parsing classes for now, yes.

For a given string: $data = 'id=1&name=neil&language=powershell'

I'd like to get a hashtable that looks like this:

@{
   id = 1
   name = 'neil'
   language = 'powershell'
}

I've tried this:

$data -split '&' | ConvertFrom-StringData

But I actually get an array of hashtables because ConvertFrom-StringData wants a single newline-separated string. So I tried this:

$data -replace '&','`n' | ConvertFrom-StringData

Which is yucky, but also doesn't work.

Before I end up writing a for loop, is there a more PowerShell-idiomatic way to do this?

EDIT:

While waiting I've ended up doing this, but I don't like it:

$ht = @{}
$data -split '&' |
    ForEach-Object {
        $kvp = $_ -split '='
        $ht[$kvp[0].Trim()] = if ($kvp.Length -gt 1) { $kvp[1].Trim() } else { $null }
    }

EDIT 2:

I fixed my error where I'd incorrectly put a backslash instead of backtick as my escape character. I'd done the correct thing in my actual test, but re-typed incorrectly into this question. Sorry for the confusion.

 2  40  2
1 Jan 1970

Solution

 3

So I tried this:

$data -replace '&','\n' | ConvertFrom-StringData

Which is yucky, but also doesn't work.

It doesn't work because '\n' doesn't describe a newline character. Use "`n" instead:

$data -replace '&',"`n" | ConvertFrom-StringData

Your alternative solution can also be simplified slightly - you can Trim() both the key and value strings in one go, and then use the ternary operator ?: to simplify the value assignment, like this:

$ht = [ordered]@{}
$date -split '&' |ForEach-Object {
  $k,$v = $_ -split '=',2 |ForEach-Object Trim
  $ht[$k] = $v ? $v : $null
}

The ternary expression $v ? $v : $null evaluates to $v except for when it's an empty string, in which case we assign $null

2024-07-23
Mathias R. Jessen

Solution

 1

Mathias' helpful answer explains the problem with your '\n' substitution operand well, and offers an effective solution.


However, it is easy to make your original, -split-based attempt work:

But I actually get an array of hashtables because ConvertFrom-StringData wants a single newline-separated string.

You can simply join the tokens resulting from the -split operation with newlines before passing the result to ConvertFrom-StringData, using the -join operator, so as to ensure that all key-value pairs become part of the same, single output hashtable:

$data = 'id=1&name=neil&language=powershell'

$data -split '&' -join "`n" | ConvertFrom-StringData

Note:

2024-07-23
mklement0