valkyrie
valkyrie

Reputation: 61

UTF8 Encoding changes data Format

I'm trying to get the output of a command in PowerShell and encode it and then decode it again to receive the results of the said command as shown.

$enc = [system.Text.Encoding]::UTF8
$bytes = $enc.GetBytes((Invoke-Expression "net users"))
$enc.GetString($bytes)

However, the result comes out malformed as opposed to the original net users command. I've tried changing the encodings to ASCII and Unicode and still the result is malformed.

Any ideas on how to maintain the formatting?

Upvotes: 2

Views: 1315

Answers (2)

mklement0
mklement0

Reputation: 437363

To complement Ansgar Wiechers' helpful answer:

Invoking an external command returns the output lines as an array of strings.

Because Encoding.GetBytes() expects a single string as input, the array was implicitly coerced to a single string, in which case PowerShell joins the array elements using the space character, so the original line formatting was lost; e.g.:

PS> [string] 1, 2, 3
1 2 3   # single string containing the array elements joined with spaces

Piping to Out-String, as in Ansgar's answer, prevents creation of the array and returns the external command output as a single string.

PS> (1, 2, 3 | Out-String | Measure-Object).Count
1          # Out-String output a single string

Another option would be to join the array elements with newlines on demand (you won't see the difference in the console, but you do get a single, multi-line output string with this technique):

PS> (net users) -join "`n"            # or, more robustly: [environment]::NewLine

Note: With this technique, the output string will not have a trailing newline, unlike when you use Out-String.
Out-String always appends a trailing newline, which can be undesired.


Alternatively, you can tell PowerShell what encoding to expect from an external command by setting [Console]::OutputEncoding (temporarily):

However, that is only necessary if you know the external utility to use an output encoding other than the default (your system's active OEM code page) - and I doubt that that's necessary for net users; that said, here's how it would work:

$prevEnc = [Console]::OutputEncoding 
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding
$str = net users | Out-String  # `net users` output is now properly decoded as UTF-8
[Console]::OutputEncoding = $prevEnc

Upvotes: 1

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200233

The problem isn't caused by the encoding, but because PowerShell will mangle the command output unless you force it into a string:

$bytes = $enc.GetBytes((Invoke-Expression "net users" | Out-String))

You don't need Invoke-Expression BTW. This will work as well:

$bytes = $enc.GetBytes((net users | Out-String))

Upvotes: 4

Related Questions