6
$Variable = Read-Host "Enter thing" -AsSecureString

Will prompt you for input and save it as a secure string to variable. How do I decrypt a secure string variable?

PS C:\Users\Todd> $Variable
System.Security.SecureString
  • 1
    I see that this question has already two (good) answers but I think it is actually a duplicate with at least [Get SecureString as a Plain Text Parameter](https://stackoverflow.com/a/54371160/1701026) and [Convert a secure string to plain text](https://stackoverflow.com/a/28353003/1701026) – iRon Jun 28 '20 at 08:46

2 Answers2

17

A security warning first:

Converting a secure string to a regular [string] instance defeats the very purpose of using [securestring] (System.Security.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.

Also, note that secure strings are generally not recommended for use in new code anymore: they offer only limited protection on Windows, and virtually none on Unix-like platforms, where they aren't even encrypted.


PowerShell v7+ now offers ConvertFrom-SecureString -AsPlainText to convert a secure string to its - unsecured - plain-text representation:

# PowerShell 7.0 or higher.
$password = Read-Host "Enter password" -AsSecureString
$plainTextPassword = ConvertFrom-SecureString -AsPlainText $password

In PowerShell v6- (including Windows PowerShell), you can use the following:

$password = Read-Host "Enter password" -AsSecureString
$plainTextPassword = [Net.NetworkCredential]::new('', $password).Password
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    +1 for new PS 7 implementation, question: If you are using the built in PowerShell encryption, is it really intended to be secure or just secure enough that it satisfies the casual users? – Nico Nekoru Jun 28 '20 at 03:08
  • @NekoMusume No, it isn't secure: any method, whatever it is, that results in a plain-text representation of a secret is by definition not secure. The methods shown in this answer are simply more convenient than the `[Runtime.InteropServices.Marshal]`-based approach from your own answer; btw, can you please fix your answer based on the suggestions in my comment? – mklement0 Jun 28 '20 at 03:18
  • Ok, one more thing, your comment talks about `[Runtime.InteropServices.Marshal]::ZeroFreeBSTR()` but if I run `[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($Password)` it has an error ```Cannot convert argument "s", with value: "Test", for "ZeroFreeBSTR" to type "System.IntPtr": "Cannot convert the "Test" value of type "System.String" to type "System.IntPtr"."``` is this intended? – Nico Nekoru Jun 28 '20 at 03:22
  • @NekoMusume Thanks for updating. You must call `ZeroFreeBSTR()` on whatever the `SecureStringToBSTR` call returned; here's a full example: `$secure = Read-Host -AsSecureString 'Enter password'; $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure); $plaintext = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr); [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($secure)` – mklement0 Jun 28 '20 at 12:08
3
$password = Read-Host "Enter password" -AsSecureString
$password = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
$password = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($password)
echo $password
pause

To convert Read-Host SecureStrings to normal strings, you use

$NewVaraible = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($ReadVariable)
$NewNewVariable = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($NewVariable)

Or you could just update the existing variable:

$ReadVaraible = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($ReadVariable)
$ReadVariable = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($ReadVariable)

Thank you @mklement0 for your insightful comments; updated answer accordingly to mklement0's comment
Nico Nekoru
  • 2,840
  • 2
  • 17
  • 38
  • 2
    I know that use of `PtrToStringAuto()` is very common, but it is conceptually flawed and breaks on Unix-like platforms; use `PtrToStringBSTR()` instead - see [this answer](https://stackoverflow.com/a/60406968/45375). Also - again something that is commonly missing - you should call `[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($NewVariable)` afterward, to zero out and free the BSTR. – mklement0 Jun 28 '20 at 02:59