Skip to content

How to encrypt credentials & secure passwords with PowerShell

Andrew Pla
Andrew Pla|February 18, 2025
Illustration of Power(turtle)Shell
Illustration of Power(turtle)Shell

Automating with PowerShell is great ... until you need to pass credentials into a script. Many administrators put passwords into the body of their scripts. For testing purposes, this could be considered a forgivable offense. But in production scripts, putting your passwords in plain view is not only a bad thing — it’s downright terrifying. Thankfully, you can secure a password with PowerShell (or at least reduce password visibility).

What are PowerShell SecureStrings?

PowerShell SecureStrings are objects designed to store sensitive data securely, using encryption to reduce the risk of exposing that data during script execution.

Syntax

ConvertTo-SecureString [-String] SomeString ConvertTo-SecureString [-String] SomeString [-SecureKey SecureString] ConvertTo-SecureString [-String] SomeString [-Key Byte[]] ConvertTo-SecureString [-String] SomeString [-AsPlainText] [-Force] 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.

SecureStrings isn't the only way to manage your secrets. 🤫

You can also learn how to manage PowerShell secrets with the SecretsManagement module.

Store the credential as a SecureString

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
Powershell   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 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
Powershell   Read Host

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 since 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 can 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.

Encrypt passwords and other strings

ConvertTo-SecureString

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 to encrypt/decrypt your strings. This effectively means that only the same user account on the same computer can 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 “P@ssword1” and convert it to a SecureString. Since this is a plain text string, we’re going to use the –AsPlainText and –Force parameters.

"P@ssword1" | ConvertTo-SecureString -AsPlainText -Force
secureString

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.

Save encrypted standard strings

ConvertFrom-SecureString

Use ConvertFrom-SecureString to convert SecureStrings 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.

"P@ssword1" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString
convertTo

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

SecureString examples

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. This won't stop anybody who knows what they’re doing from decrypting the password or reusing the encrypted password if they ever 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.

When you're not specifying a key or SecureKey, this only works for the same user on the same computer can decrypt the encrypted string. Any process running under that user account on the same machine can also decrypt it.

Here is an example of each:

Export SecureString from plain text with Out-File

"P@ssword1" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "C:\Temp 2\Password.txt"

Export SecureString from Get-Credential

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

Export 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.

Create SecureString object Get-Content and ConvertTo-SecureString

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

Create 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)
ConnectIcon CTA

Easily run PowerShell scripts on remote devices

Need to run your awesome PowerShell scripts on remote devices? PDQ Connect can easily execute PowerShell scripts on any managed device with an active internet connection. 

Share credentials across machines or users

When you use ConvertTo-SecureString and ConvertFrom-SecureString without a Key or SecureKey, Powershell uses Windows Data Protection API (DPAPI) to encrypt/decrypt your strings. This means that it only works for the same user on the same computer.

When you use a Key/SecureKey, the Advanced Encryption Standard (AES) encryption algorithm is used. You are able to use the stored credential from any machine with any user as long as you know the AES Key that was used.

Using no Key/SecureKey

First, let’s show an example of what you'll see if you try to create a credential from one machine (Machine 1) and then access it from another machine (Machine 2) without providing a key.

Encrypting a password without a key and saving it to file from Machine 1

This creates the file Password.txt with an encrypted standard string representing the password. It uses DPAPI.

$File = "\\Machine1\SharedPath\Password.txt" $Password = "P@ssword1" | ConvertTo-SecureString -AsPlainText -Force $Password | ConvertFrom-SecureString | Out-File $File

Accessing the encrypted password file from Machine 1

This successfully gets the encrypted standard string using Get-Content and converts it to a SecureString.

$File = "\\Machine1\SharedPath\Password.txt" Get-Content $File | ConvertTo-SecureString
Administrator: Windows PowerShell

Accessing the encrypted password file from Machine 2

This fails with an error indicating that the key is invalid. Example below:

$File = "\\Machine1\SharedPath\Password.txt" Get-Content $File | ConvertTo-SecureString
Administrator: Windows PowerShell

Using Key/SecureKey

Now, let's show a simple example of creating an encrypted standard string with the use of a key. AES encryption only supports 128-bit (16 bytes), 192-bit (24 bytes) or 256-bit key (32 bytes) lengths, so we'll need to create or generate an appropriate key. For simplicity, let's create a simple byte array of ascending numbers. We'll use a 128-bit key, so we'll need a 16-byte array.

Long way

[Byte[]] $key = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)

Short way

[Byte[]] $key = (1..16)

Encrypting a password and saving it to file from Machine 1

This creates the file (with Out-File) Password.txt with an encrypted standard string representing the password. It uses AES.

$File = "\\Machine1\SharedPath\Password.txt" [Byte[]] $key = (1..16) $Password = "P@ssword1" | ConvertTo-SecureString -AsPlainText -Force $Password | ConvertFrom-SecureString -key $key | Out-File $File

Accessing the encrypted password file from Machine 1

This successfully gets the encrypted standard string and converts it to a SecureString. It uses the AES key that we provided earlier.

$File = "\\Machine1\SharedPath\Password.txt" [Byte[]] $key = (1..16) Get-Content $File | ConvertTo-SecureString -Key $key
Administrator: Windows PowerShell

Accessing the encrypted password file from Machine 2

This successfully gets the encrypted standard string and converts it to a SecureString by using the AES key.

$File = "\\Machine1\SharedPath\Password.txt" [Byte[]] $key = (1..16) Get-Content $File | ConvertTo-SecureString -Key $key
Administrator: Windows PowerShelll

AES key examples

Now that you know how to use an AES key to make SecureStrings created by different user accounts and workstations, you have to protect that key as best as you can. That's because anybody who has that AES key can now decrypt the protected data.

In my previous example, I used a very simple 16-byte array that is stored in the body of the script itself. This is not a good practice and is essentially the same as if you were to write the password in clear text. Alternatively, you could create/generate a key beforehand in a separate script.

As an example, I have built a small script to generate a random 16-byte array. I have used the System.Security.Cryptography.RNGCryptoServiceProvider class to fill a byte array with randomly-generated data.

Create AES key with random data and export to file

$KeyFile = "\\Machine1\SharedPath\AES.key" $Key = New-Object Byte[] 16 # You can use 16, 24, or 32 for AES [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key) $Key | out-file $KeyFile

Create SecureString object

$PasswordFile = "\\Machine1\SharedPath\Password.txt" $KeyFile = "\\Machine1\SharedPath\AES.key" $Key = Get-Content $KeyFile $Password = "P@ssword1" | ConvertTo-SecureString -AsPlainText -Force $Password | ConvertFrom-SecureString -key $Key | Out-File $PasswordFile

Create PSCredential object

$User = "MyUserName" $PasswordFile = "\\Machine1\SharedPath\Password.txt" $KeyFile = "\\Machine1\SharedPath\AES.key" $key = Get-Content $KeyFile $MyCredential = New-Object -TypeName System.Management.Automation.PSCredential ` -ArgumentList $User, (Get-Content $PasswordFile | ConvertTo-SecureString -Key $key)

That’s it! You can use the key file to decrypt the password file from any machine with any user.

Be sure to protect that AES key as if it were your password. Anybody who can read the AES key can decrypt anything that was encrypted with it.

At the very least, you should implement strict NTFS access controls for both your password and key files. This should keep out most prying eyes. Additionally, you may consider storing the data in a database with strict access controls or even implementing public-key (asymmetric) cryptography for additional control.

In any case, you should be good to use AES keys with your SecureStrings now.

Andrew Pla
Andrew Pla

Andrew loves automation, PowerShell, and building tools that last. He has spent nearly a decade in IT with a focus on automation, infrastructure, and toolmaking. He has a passion for sharing knowledge and prefers humans to computers, and is a host of the PowerShell Podcast and a Microsoft MVP.

Related articles