PDQ.com mobilePDQ.com desktop
Support

Secure Password with PowerShell: Encrypting Credentials – Part 1

Kris PowellKris Powell
·

Like many systems administrators out there, I’ve often found myself with tasks eligible for automation. Automating is great with PowerShell until you need to pass credentials into a script.

I have seen many administrators put passwords into the body of their script. For testing purposes, this could considered a forgivable offense. In production scripts, putting your passwords in plain view is not only a bad thing…it’s a terrifying thing. It should be a cardinal sin. But you can secure a password with PowerShell (or at least reduce password visibility).

First, we'll learn how to supply a credential without having to save it pants-down plain-text in your script for all the world (or your office) to see.

Get-Credential and Read-Host

You can create a PSCredential object with the Get-Credential cmdlet, and store the output into a variable. You can then pass that variable into any cmdlet that supports PSCredential objects.

$MyCredential = Get-Credential

Notice that when you access the variable $MyCredential, you are able to see the username but not the password. It only displays, "System.Security.SecureString" on the screen. This is because the password is now stored as a SecureString.

You can then use this new PSCredential object with cmdlets that support PSCredential objects. You can also individually reference the username or the password for cmdlets that don’t accept a PSCredential object but will support username and password parameters.

In those cases, you can use $MyCredential.Username and $MyCredential.Username

Or you can use Read-Host to prompt for input and store the result in a variable. This includes prompting for a SecureString (for a password).

$user = Read-Host "Enter Username"
$pass = Read-Host "Enter Password" -AsSecureString

The output is very similar to the output of the Get-Credential variable we used, $MyCredential. It shows the username as "MyUserName" and the password as "System.Security.SecureString."

This is great for manual runs of scripts as it helps to remove the password from the script, but it doesn’t really help with our automation. We’re looking for a solution that will be able to run automatically without having to constantly supply credentials via Get-Credential/Read-Host or by leaving our passwords in plain view for anybody to read.

ConvertTo-SecureString – Encrypting passwords and other strings

Use ConvertTo-SecureString to convert plain text or encrypted standard strings into a SecureString object. The SecureString object can be used with cmdlets that support parameters of type SecureString, as is the case with a PSCredential object. You can use the command to define a variable, or pipe results into the command.

Syntax:
ConvertTo-SecureString [-String] SomeString
ConvertTo-SecureString [-String] SomeString [-SecureKey SecureString]
ConvertTo-SecureString [-String] SomeString [-Key Byte[]]
ConvertTo-SecureString [-String] SomeString [-AsPlainText] [-Force]

–String String
The string to convert to a SecureString

–SecureKey SecureString
Encryption key as a SecureString.

–Key Byte[]
Encryption key as a byte array.

–AsPlainText
Tells command to treat string as plain text. The string is not encrypted when
using this command. Because of the lack of security, the -Force parameter 
is also required.

–Force
Confirms you understand the lack of security when using -AsPlainText

When you are not using the –Key or –SecureKey parameters, PowerShell uses the Windows Data Protection API (DPAPI) to encrypt/decrypt your strings. This effectively means that only the same user account on the same computer will be able to use this encrypted string. That is something to keep in mind as you attempt to automate any scripts. If you’re using a service account, you’ll need to use the –Key or -SecureKey parameters. Let’s say you want to take the text “[email protected]” and convert it to a SecureString. Since this is a plain text string, we’re going to use the –AsPlainText and –Force parameters.

"[email protected]" | ConvertTo-SecureString -AsPlainText -Force

The result is a SecureString object. Unfortunately, you cannot save a SecureString object to a file for later use. You have to convert this SecureString object to an encrypted standard string. You can do this with ConvertFrom-SecureString.

ConvertFrom-SecureString – Saving encrypted standard strings

Use ConvertFrom-SecureString to convert secure strings into encrypted standard strings. You can use the command directly or pipe results into the command.

Syntax:
ConvertFrom-SecureString [-SecureString] SecureString
ConvertFrom-SecureString [-SecureString] SecureString [-SecureKey SecureString]
ConvertFrom-SecureString [-SecureString] SecureString [-Key Byte[]]

–String String
The string to convert to a SecureString

–SecureKey SecureString
Encryption key as a SecureString.

–Key Byte[]
Encryption key as a byte array.

Following the same example above, we’ll take the output of the previous example and pipe it into the ConvertFrom-SecureString command to get an encrypted standard string.

"[email protected]" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString

The result is an encrypted standard string that you can then save for later retrieval.

Putting it all together

We now know how to convert a SecureString to an encrypted standard string. We can take any method we like to get a SecureString, convert it to a standard string and then save it to a file. Here is an example of each:

Exporting SecureString from Plain text

"[email protected]" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "C:\Temp 2\Password.txt"

Exporting SecureString from Get-Credential

(Get-Credential).Password | ConvertFrom-SecureString | Out-File "C:\Temp 2\Password.txt"

Exporting SecureString from Read-Host

Read-Host "Enter Password" -AsSecureString |  ConvertFrom-SecureString | Out-File "C:\Temp 2\Password.txt"

Any one of these examples should provide you with a Password.txt file that has an encrypted standard string the represents the password.

When you need to use this encrypted password, you simply reverse the process by importing the data from your file and use ConvertTo-SecureString. If all you need is a SecureString, you can stop there. You could even take it a step further and create a PSCredential object.

Creating SecureString object

$pass = Get-Content "C:\Temp 2\Password.txt" | ConvertTo-SecureString

Creating PSCredential object

$User = "MyUserName"
$File = "C:\Temp 2\Password.txt"
$MyCredential=New-Object -TypeName System.Management.Automation.PSCredential `
 -ArgumentList $User, (Get-Content $File | ConvertTo-SecureString)

Final Notes

This will not stop anybody who knows what they’re doing from decrypting your password or from reusing your encrypted password if they ever are able to compromise your login. The whole point of converting your password to a SecureString and storing it in a file is to keep it out of plain text in your scripts so that it’s not as easily discovered. It’s not foolproof, but it’s pretty good.

As mentioned above, when you are not specifying a key or securekey, this will only work for the same user on the same computer will be able to decrypt the encrypted string if you’re not using Keys/SecureKeys. Any process that runs under that same user account will be able to decrypt that encrypted string on that same machine.

If you want to be able to share a credential with multiple machines/logins/etc, then you’ll need to use Keys/SecureKeys. I’ll save that for another post.

***Read part 2 here***

Did you know that PDQ Deploy has a PowerShell step you can use to deploy your scripts?


This blog post is part of a series on PowerShell:

Ready to put the PowerShell scanner through its paces?

Take our 14-day Free Trial. Feel the power of the PowerShell scanner.
Start a Trial

Don't miss the next post!

May 2020 Patch Tuesday Vulnerabilities

May 2020 Patch Tuesday Updates and Vulnerabilities. This month has continued the trend of fewer issues that we have seen since February. CVE’s patched dropped from 113 all the way down to 111.