How to Encrypt Passwords in PowerShell

Save to My DOJO

How to Encrypt Passwords in PowerShell

As an MSP, managing passwords in PowerShell scripts can be a dicey task. There is always a risk that someone may find the password by simply peering at your code. However, certain scenarios call for “storing” a password somewhere and referencing it in a script for authentication. To do this safely, you’ll need to encrypt them, and you can do this using PowerShell. If you’re new to PowerShell, don’t worry it’s not too difficult!

Why Should I Encrypt Passwords?

As a savvy tech professional, you’re likely aware of the dangers lurking in the digital shadows, but have you considered the full extent of risks associated with unencrypted passwords in your PowerShell scripts? Let’s dive into why encrypting passwords isn’t just a good practice—it’s essential for maintaining robust security in an ever-evolving cyber landscape.

  • Protecting Sensitive Information 

First and foremost, PowerShell scripts often handle sensitive data that can range from user credentials to critical system configurations. Without encryption, these passwords are exposed in plain text, making them vulnerable to unauthorized access. Imagine if these scripts were compromised – it would be akin to leaving your house keys under the doormat. Encryption acts as a robust lock, safeguarding your sensitive information from prying eyes.

  • Compliance with Security Standards 

In the world of information security, compliance with standards and regulations is non-negotiable. Encrypting passwords in PowerShell scripts is not just a best practice; in many cases, it’s a requirement. Standards like GDPR, HIPAA, and PCI-DSS mandate stringent data protection measures. By encrypting passwords, you’re not just securing data but also aligning with these crucial regulatory frameworks, thereby avoiding potential legal and financial penalties.

  • Mitigating Insider Threats 

It’s a harsh reality, but not all security threats come from outside your organization. Insider threats, whether intentional or accidental, are a significant risk. By encrypting passwords in PowerShell, you’re putting an additional barrier between your sensitive data and any internal actors who might misuse it. This encryption ensures that even if someone has access to your scripts, they can’t misuse the passwords contained within.

  • Enhancing Security in Automation 

PowerShell is often used for automating tasks across multiple systems. When these automated scripts include plain text passwords, it’s like sending a confidential letter in a clear envelope. Encryption ensures that even if the automation process is intercepted or logs are accessed, the confidentiality of your passwords remains intact.

  • Safeguarding Against External Threats 

Cyber threats are evolving rapidly, and hackers are constantly devising new methods to breach systems. Encrypted passwords in PowerShell scripts act like a moat around your digital fortress, deterring hackers. If a cybercriminal accesses your scripts, they’ll find the passwords inaccessible, thwarting their malicious intentions and safeguarding your network.

  • Expand the Scope of Security

Beyond these fundamental reasons, encrypting passwords in PowerShell scripts also plays a pivotal role in maintaining operational integrity for MSPs. In an age where data breaches can lead to significant operational disruptions, encryption serves as a critical line of defense. It ensures continuity and reliability in your automated processes, safeguarding not just data but also the seamless functioning of your systems.

  • Future-Proofing Your Security Posture

Moreover, as technology continues to advance, so do the techniques used by cyber adversaries. Encrypting passwords is not just about addressing current threats; it’s about future-proofing your security posture. By adopting encryption today, you are preparing your systems to withstand emerging threats that might evolve tomorrow.

By now it should be common sense that you don’t “hard code” passwords into any sort of script like below:

$password = “MYPASSWORD”

Anyone can easily just open up your script file and read the password. Instead here are 3 more secure ways of passing credentials through to your PowerShell scripts

Using Task Scheduler

This is the easiest method of all. When configuring a task, Task Scheduler allows you to store your account credentials and will execute your specified script using those credentials:

This is useful when running a script that needs access to file shares or any domain authenticated endpoint. However, task scheduler will only store 1 set of credentials and uses the Windows Data Protection API to encrypt/decrypt the password. This method uses the user account login credentials sort of as a “key” to access the stored password. The con to this method is, since the login credentials are being stored locally on the server, the script can only be run on the server that has the credentials cached and the Task Scheduler configured.

Create an Encrypted Password File

Another way we can go about hiding the passwords used in our PowerShell scripts, is by creating an encrypted password file and then referencing that password file in our script. Just like Task Scheduler, this method will encrypt using the Windows Data Protection API, which also means we fall into the same limitations of only being able to access the password file with one account and only on the same device that created the password file. The user login credentials are essentially the “key” to the password file. However, this method allows us to save multiple passwords and reference them in our script.

To get started we will create the password file by inputting the following syntax into a PowerShell console. Also, note that the user account you are using to create the password file is the same account that must be used to open the password file (Windows Data Protection API remember?):

(get-credential).password | ConvertFrom-SecureString | set-content "C:\Passwords\password.txt"

You will get a prompt for the password, input the credentials that you want to save. In our example an encrypted password file will be saved to “C:\passwords\password.txt”:

When we open the file we can see that our credentials are encrypted:

Now, how do we retrieve these credentials? Easy, if we ever need to retrieve these we include the following syntax in our scripts to provide the creds:

$password = Get-Content "C:\Passwords\password.txt" | ConvertTo-SecureString 
$credential = New-Object System.Management.Automation.PsCredential("Luke",$password)

Then just pass $credential to whatever cmdlets need a pscredential to authenticate. If we look at what’s in the $credential variable we can see our username and its encrypted password:

As I said before, you still fall under the limitation of requiring the same user account to run the script and only on the same machine that you created the password file. Thankfully, there is a 3rd option that allows us to get around this.

Creating a Key File and Password File

With PowerShell, we can generate a 256-bit AES encryption key and use that key to access our password file. First, we input the following syntax to create our key file. You could take this key and put it on a network share and only give specific users access to the key along with the password file. But, in this example we will just save it to C:\passwords with our password file:

$Key = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
$Key | out-file C:\passwords\aes.key

If we open the aes.key in notepad we can see our key is now generated:

Now, we create a password file just like the one above. However, we use the -key parameter to specify that we want to use a key and input the location of the key file. Then, we create the password file. In this example, we’ll output the password file to our C:\passwords directory:

(get-credential).Password | ConvertFrom-SecureString -key (get-content C:\passwords\aes.key) | set-content "C:\Passwords\password.txt"

Now that we have our password file and our key file. We can simply recall our password from any script by including the following syntax in the script:

$password = Get-Content C:\Passwords\password.txt | ConvertTo-SecureString -Key (Get-Content C:\Passwords\aes.key)
$credential = New-Object System.Management.Automation.PsCredential("Luke",$password)

When we look at the data inside the $credential variable we can see that we have the username and password now.

Wrap-Up

Each method has its own pros and cons. However, keep in mind that all of these ways are not 100% foolproof. So, I would not advise doing this with a domain administrator account. Just enough access (JEA) is the way to do it, so I would recommend creating an account with just enough access to do what it needs to do.

How about you? What interesting ways have you used to get around the issue of storing credentials in plaintext?

More articles about how MSPs can make the most out of PowerShell in their operations:

Using SFTP

Working with REST APIs

HTML Tables for Reporting

Altaro O365 Backup for MSPs
Share this post

Not a DOJO Member yet?

Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!

309 thoughts on "How to Encrypt Passwords in PowerShell"

  • Marcos says:

    Thank for the information provide about Encrypt Passwords

    very clear steps

  • Eric says:

    Very Nice!

  • Casey says:

    I’m curious, how does this provide extra security? If someone can access files and see a plain text pw in a script, they could just as easily access they key and password files and unencrypt them. Or am I misunderstanding something here?

    • That’s a good question! In this solution you would use NTFS permissions to lock down the folder that contains the password file and key so that only the accounts that are given permission to this folder will have the ability to retrieve the password when the script is ran.

      • Mr. Peanut Butter and Jelly Sandwhich says:

        Why not just store the script with the plain text pw in the locked down folder?

        • Adds another layer of security. If the contents of the folder get compromised through the numerous security vulnerabilities out there, then we have another security measure in place.

  • Santosh says:

    If password consist $ it gives error how to handle it?

    • You may be using single quotations somewhere and need to be using Double Quotations to mask the $. If that’s not the case, paste in your code and I’ll take a look at what could be causing the error.

  • Ouida says:

    Magnificent website. Plenty of helpful info here. I am sending
    it to some pals ans also sharing in delicious.

    And naturally, thanks for your effort!

  • BROUSSEY says:

    Thanks for this great information.
    Just one question : how can I use only the password not all the credentials.
    I have a script that doesn’t support -credentials but -u user -p password so I tried this syntax:
    $password = Get-Content C:\Passwords\password.txt | ConvertTo-SecureString -Key (Get-Content C:\Passwords\aes.key)
    and then use this as :
    Invoke-Expression “$Rvtools -u $User -p $password -s $VCenter1 -c $ExportType -d $Directory -f $FileNameSite1”

    but that doesn’t work

    Thanks a lot

    • You’ll want to retrive the credentials and then convert them from “securestring” over to clear text. So instead of $credentials.password you can use: ($credentials.GetNetworkCredential()).Password

      • Andy says:

        I was having getting the $credentials.GetNetworkCredential()).Password to work until I changed it to $credential.GetNetworkCredential()).Password

        My only problem is how to encrypt the username too. With (get-credential).Password it appears to prompt and save both the username and password but in your example you’re still specifying the username in plain text (Luke).

        I’m guessing I’d need: $username = ($credential.GetNetworkCredential()).Username but I don’t know what to put in place of Luke.

        • Hi Andy,

          With a pscredential object, the username will still be in plain text, only the password is in secure string format. So no need to use $credential.GetNetworkCredential(). You can just use $credential.username.

  • Aditya says:

    Hi Luke,
    I tried your second and third method. I was able to encrypt the password successfully but while using it in script, I was getting access denied everytime. But when I used the user name and password explicitly, it worked without any issues. Could you please guide me what could be the possible issue?
    When I specified username and password directly, it worked

    Add-Type -Path “C:\Program Files (x86)\WinSCP\WinSCPnet.dll”
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp
    HostName = “abc.xyz.com”
    PortNumber = 222
    UserName = “username”
    Password = “password”
    SshHostKeyFingerprint = “xxxxxx=”
    }

    But when I tried your method:

    Add-Type -Path “C:\Program Files (x86)\WinSCP\WinSCPnet.dll”
    #$password = Get-Content C:\password\password.txt | ConvertTo-SecureString -Key (Get-Content C:\password\aes.key)
    #$credential = New-Object System.Management.Automation.PsCredential(“username”,$password)

    # Set up session options
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp
    HostName = “abc.xyz.com”
    PortNumber = 222
    UserName = “$credential.UserName”
    Password = “$credential.Password”
    SshHostKeyFingerprint = “xxxxxx=”
    }
    I get the following error:

    Exception calling “Open” with “1” argument(s): “Connection has been unexpectedly closed. Server sent command exit status 0.
    Authentication log (see session log for details):
    Using username “System.Management.Automation.PSCredential.UserName”.
    Access denied.
    Authentication failed.”

    • $credential.password is going to be encrypted since it is a “securestring”. You will want to replace that with this which will decrypt the string and input the password as clear text: ($credentials.GetNetworkCredential()).Password

  • ctmax says:

    cool and good reference..

  • Sean says:

    Hi Luke, thank you for this great article.
    im having issues using the PSCredential object with the command: send-mailmessage.

    this is what i have:
    $Key = New-Object Byte[] 32
    [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
    $Key | out-file C:\temp\aes.key

    (get-credential).Password | ConvertFrom-SecureString -key (get-content C:\temp\aes.key) | set-content “C:\temp\password.txt”

    $password = Get-Content C:\temp\password.txt | ConvertTo-SecureString -Key (Get-Content C:\temp\aes.key)
    $credential = New-Object System.Management.Automation.PsCredential(“user1”,$password)

    then i use the $credential object like so:
    Send-MailMessage -To “[email protected]” -From “[email protected]” -Subject “test” -Body “test” -SmtpServer “smtpserver” -Credential $credential

    but i keep getting: “The server response was: 5.7.1 Client was not authenticated”

    if i enter the creds manually using -credential (get-credential) with same creds it works…

    Thanks,
    Sean

    • Hi Sean,

      First verify that your $credential variable contains the correct password that you need by running: ($credential.GetNetworkCredential()).password this should display your password in plaintext. I would start there to make sure that your pulling the proper credentials.

    • AndrewS says:

      Hi, Sean.
      Perhaps you need to specify additional authentication parameters on the smtp server, for example, the port and the need to use the SSL(TLS) protocol.
      Send-MailMessage -To “[email protected]” -From “[email protected]” -Subject “test” -Body “test” -SmtpServer “smtpserver” -Credential $credential -Port 587 -UseSSL

  • Tony says:

    Thanks for your great post. I followed the steps correctly, but for options 2 & 3, when i issue $credential, i get only the username and not the password string like you had in option 2. Am i doing something wrong?

    Can the password be created in any directory or does it have to be only in the C:? i tried several different locations and still cannot get the password. When i try running my script, it still asks for username and password.

    Appreciate any assistance.

  • Saber Ali says:

    i changed the password of the server , the script dose not work again, what may spouse to do ?

    • Hello,

      You will need to update the credentials to reflect the new password. You could create a script that changes the password of the server and then updates the encrypted credential file.

  • Dan Apprentice says:

    Luke, really appreciated this article. I have a situation I’m wondering if I can use any of your suggestions above towards.
    I have 10 windows 10 pc’s in a workgroup (not joined to a domain). They all have set up an admin account with same username (Star1) and password.
    I want the main script to be able to read from user.csv file and use a foreach loop to create 2-3 users.
    How do I handle the password portion in the csv? Create from the actual password a SecureString, using code such as:
    $SecureStringAsPlainText = $SecurePassword | ConvertFrom-SecureString

    Then past that long encrypted string in the password section of the csv?

    If I do this, can I then create these users from that script on the usb by either: (1) going to each machine with the usb drive and running the script OR (2) PSremoting to the remote machines using this script?

    Either way, how would I do this? If there is a better more efficient manner, please share.

    I hope what I’m asking is clear and you have enough information to go on. If not, please let me know.

    Thanks in advance for whatever help you (or anyone else) can give.
    Right now, I’m stumped.

  • Shreyas Partake says:

    Hey Luke,

    I have been looking for this for a few days. Finally, I got your blog and the purpose is fulfilled. 2nd method worked for me. Thank you so much for this information!

Leave a comment

Your email address will not be published. Required fields are marked *