PowerShell tips and tricks – Decoding SecureString
Introduction
It is quite common to get across SecureString type in PowerShell. If you ever needed to supply a credential object, at example to the Invoke-RestMethod cmdlet, then you for sure came across a SecureString. I will describe a couple of “tricks” that can be useful meanwhile working with SecureString objects.
Creating a SecureString
This is one of the most common cases. If you are constructing your System.Management.Automation.PSCredential object instance you need to provide a SecureString for the password argument in the constructor of just mentioned class. This implies that you need to transform your string to a SecureString. Luckily this is a trivial task since we have a cmdlet that can help us with that.
$securePassword = ConvertTo-SecureString –String $password -AsPlainText -Force
ConvertTo-SecureString will do just that. Be aware that you need to set two parameters in order to process your plain string correctly, and those are AsPlainText and Force.
AsPlainText indicates that you are providing a plain text as the input and that variable is not protected. With Force parameter you just confirm that you understand the implications of using the AsPlainText parameter and still want to use it.
Another way of creating a SecureString is to interactively prompt a user for information. You can achieve that in the following way.
$securePassword = Read-Host "Please enter the password" -AsSecureString
This is a indicated way of retrieving sensitive data if user interaction is required. Also you could request it through well known authentication dialog and retrieve the above mentioned PSCredential object. This object does expose a property called Password which is of type SecureString.
$credential = Get-Credential
As you can see, I used a Get-Credential cmdlet to trigger the authentication dialog.
If you need to persist your sensitive data in a text file or in a database, you can leverage ConvertFrom-SecureString cmdlet to transform your SecureString value into an encrypted string. Consider the following code:
ConvertFrom-SecureString $securePassword | Out-File C:\tmppassword.txt
Once stored, you can retrieve it again by
ConvertTo-SecureString -String (Get-Content C:\tmppassword.txt)
For using a custom key for the AES algorithm that is used for encryption by the ConvertFrom-SecureString cmdlet, you can specify it via a Key or SecureKey parameter. More info about this you can get directly on Technet site ConvertFrom-SecureString.
If no key is specified, the Windows Data Protection API (DPAPI) is used to encrypt the standard string representation.
Back to the string
We saw till now that we are able to create a SecureString from a plain text, express it as encoded string, and load it back to the SecureString object. What about getting a plain text out of our SecureString?
This is not an easy task to achieve. Luckily I came across the following article on MSDN which shows the right way to achieve this and translated it to PowerShell cmdlet. Next step was translating the shown code into PowerShell and encapsulating it in a cmdlet. This is the outcome.
function Get-PlainText() { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.Security.SecureString]$SecureString ) BEGIN { } PROCESS { $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString); try { return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr); } finally { [Runtime.InteropServices.Marshal]::FreeBSTR($bstr); } } END { } }
Now it is sufficient to pass your secure string as a parameter and you will retrieve the plain text behind it.
You may ask yourself, why? When can this be handy? It happened to me to be in need to construct an Authentication Header for Basic access authentication.
What is expected by the server is a header in your http request that equals to Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
where the last string is a Base64 encoded string called token and it is composed of the username and password in the following disposition “username:password”. All of my authentication methods are using System.Management.Automation.PSCredential object to express and move credentials. This is where decoding a secure string was important.
For completeness I’ll show you other cmdlets I wrote to accomplish this task.
function Get-AuthenticationToken() { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.Management.Automation.PSCredential]$Credential ) BEGIN { } PROCESS { $password = Get-PlainText $Credential.Password; $key = [string]::Format("{0}:{1}", $Credential.UserName, $password) return [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($key)) } END { } }
As you can see, I do get a PSCredential object as a parameter, I decode the password, compose the token string and at the end create a Base64 representation of it.
That’s about it.
How do you intend to use this tip?
UPDATE
Lately I came to know about another way of decoding a SecureString object and that is via the PSCredential object itself. In the above case we could do the following to retrieve the decrypted password:
$Credential.GetNetworkCredential().password
Meanwhile you can create the PSCredential object like this:
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "dummyUsername", $securePassword
You can read more about this method at Decrypt PowerShell Secure String Password.