Note that [securestring]
is not recommended for new code anymore.
While on Windows secure strings offer limited protection – by storing the string encrypted in memory – via the DPAPI – and by shortening the window during which the plain-text representation is held in memory, no encryption at all is used on Unix-like platforms.[1]
The only way around this I have found is to use
PtrToStringBSTR
.
That is not only a way around the problem, PtrToStringBSTR
is the method that should have been used to begin with, given that the input string is a BSTR
.[2]
Do note that converting a secure string to and from a regular [string]
instance defeats the very purpose of using [securestring]
to begin with: you’ll end up with a plain-text representation of your sensitive data in your process’ memory whose lifetime you cannot control.
If you really want to do this, a simpler, cross-platform-compatible approach is:
[System.Net.NetworkCredential]::new('dummy', $string).Password
[1] This is especially problematic when you save a secure string in a file, via ConvertFrom-SecureString
or Export-CliXml
– see this answer.
[2] The Auto
in PtrToStringAuto()
means that the unmanaged input string is assumed to use a platform-appropriate character encoding, whereas BSTR
is
a “Unicode” (UTF-16) string on all platforms. On Windows, an unmanaged string is assumed to have UTF-16 encoding (which is why the code works), whereas on Unix-like platforms it is UTF-8 since .NET Core 3.0 (PowerShell [Core] 7.0 is based on .NET Core 3.1), which explains your symptoms: the NUL
chars. in the BSTR
instance’s UTF-16 code units are interpreted as characters in their own right when (mis)interpreted as UTF-8. Note that .NET Core 2.x (which is what PowerShell [Core] 6.x is based on) (inappropriately) defaulted to UTF-16, which this PR fixed, amounting to a breaking change.