Encrypting passwords in a PowerShell script

Encrypting passwords in a PowerShell script remains a bit of a hot and tricky topic. There are various ways how to parse a password. The golden rule is that you do not want anyone to be able to read passwords in your scripts. This means that you should refrain from using plaintext passwords!

Change Log
03.07.2018: I discovered a mega stupid error in the script to create a 256-bit AES key and password file. This has now been corrected. My apologies to anyone who had an issue with it. Thanks to my colleague and PowerShell guru Markus Kausl for his assistance!
Table of Contents

Using plaintext passwords (not recommended!)

In case you do want to use a plaintext password (for testing purposes for example), use the following PowerShell command to create the PSCredential object (called $DatabaseCredentials in the example below):

The PSCredential object is a combination of the user account and the password. In the last line in the example above, you can see that the PowerShell variables $Account and $AccountPassword are both required to populate the variable $DatabaseCredentials.

TRY TO REFRAIN FROM USING PLAINTEXT PASSWORDS IN SCRIPTS.

There, I said it. My apologies for "shouting", but plaintext passwords can get you in all sorts of trouble.

Conclusion:

  • Biggest advantages: none
  • Biggest drawback: 100% INSECURE!!!

Now let's get on with the good stuff. The remainder of this article will show you a couple of ways how to securely use passwords in a PowerShell script.

Enter the password interactively (Read-Host)

This is the easiest method of them all, but this method is only suitable for scripts that run interactively.

In the plaintext example above, we entered the password directly in the script. We only need to replace the second line in the script to achieve our goal of entering the password interactively:

The second line contains the Read-Host cmdlet. When you run this PowerShell script interactively, you are required to enter the password in the PowerShell window.

Note: how to run a PowerShell script interactively?

  • Save the PowerShell code to a *.PS1 file (e.g. C:\MyScript.ps1)
  • Open Windows Explorer
  • Select the PowerShell file
  • With a right-mouse click select 'Run with PowerShell'

The AsSecureString parameter turns your string into a secure string. The PSCredential object only accepts secure strings.  You can try it yourself. Simply remove the AsSecureString parameter, execute the script once again, enter your password and see what happens. The PSCredential object will throw an error.

Conclusion:

  • Biggest advantages: easy to implement and 100% secure.
  • Biggest drawback: can only be used when running the PowerShell script interactively.

Using a 256-bit AES key file and a password file

When you use this method you will generate two files: a 256-bit AES key file and a password file. These files can than be used in your PowerShell scripts on local and remote computers.

How does this work?

The idea is that you create a 256-bit AES key file and one file which contains your password. The password in the password file is encrypted by the 256-bit AES key file. Confused? Don't be. All will be explained in a moment.

Here is an example of the key file and the password file.

  • "C:\AES_KEY_FILE.key"
  • "C:\AES_PASSWORD_FILE.txt"

Encrypting passwords in a PowerShell script - AES keyFile and password file

You can open these files in an editor such as Notepad, but you will only see gibberish. Once you have created the two files you can keep them on the local computer or copy them to a network share. Copying these files on a network drive means that you can use the same files on multiple computers.

Note:
Please be aware that anyone with access to the key file can retrieve the password stored in the password file (the file AES_PASSWORD_FILE.txt in our example). Therefore, make sure that you configure NTFS permissions to prevent unauthorized access to this share!

So how do you use these files once you created them?

The following code snippet show you how the PSCredential object retrieves the content from the password file (C:\AES_PASSWORD_FILE.txt), using the AES key in the key file (C:\AES_KEY_FILE.key).

This is all great, but how to create these files?

I have prepared a PowerShell script that you can use for this purpose. It is really quite simple:

  • First, save the PowerShell script below in a PS1 file (e.g. C:\CreateSecurePassword.ps1). You can change the directory path and files names in lines 17 to 19. By default the default directory is C:\. The file names are AES_KEY_FILE.key and AES_PASSWORD_FILE.txt.
  • Secondly, run the PowerShell script interactively. The following window is displayed:
    Encrypting passwords in a PowerShell script - Execute PowerShell script to create key and password file
  • Enter your password and click ENTER.
  • The files will now be created. In case of an error, the error description is displayed in the PowerShell window.
Note: how to run a PowerShell script interactively?

  • Save the PowerShell code to a *.PS1 file (e.g. C:\MyScript.ps1)
  • Open Windows Explorer
  • Select the PowerShell file
  • With a right-mouse click select 'Run with PowerShell'

I wrote this paragraph based on the following excellent article by Luca Dell'Oca:
http://www.virtualtothecore.com/en/encrypt-passwords-in-powershell-scripts.

This method works fine when you want to parse a secure password to a PSCredential object. However, in some rare cases you may actually need to parse a plain-text password. Not to worry, you can decrypt a secure password to a plain-text password in memory.

The key/password file method described in this section ensures that you do not need to enter any plain-text password directly in your script. After creating both files you copy them to a directory on the local server or on a network share. After that, you only need four additional lines of PowerShell code to read the secure password from the password file and to decrypt it to a normal readable plaint-text string.

In the above code we use the Marshal class to write the secure password to unmanaged memory. We than read this unmanaged memory and store the password in the variable $PasswordAsString. You can test if this variable contains the correct password by adding a simple write-host command:

Conclusion:

  • Biggest advantage: can be used in multiple scripts on remote computers.
  • Biggest drawback: not 100% secure. The AES key file can be used to decrypt the password and therefore requires additional (NTFS) protection from unauthorized access.

Using an SCCM collection variable

For those of you who use PowerShell scripts in SCCM applications and packages, a good way of dealing with passwords is to use a collection variable.

When creating a collection variable, make sure that the tick box Do not display this value in the Configuration Manager console is marked. This makes the variable "secure". Secure in this case means that the variable is stored in the SCCM SQL database.

Encrypting passwords in a PowerShell script - Add password to SCCM variable

You can use the following code snippet in an SCCM package to retrieve the MyPassword collection variable:

The first step is to connect to the Microsoft.SMS.TSEnvironment COM object. Please be aware that the SCCM package runs as a 32-bit process. However, the PowerShell script needs to run as a 64-bit process, otherwise loading the Microsoft.SMS.TSEnvironment COM object ends in an error. The command in your SCCM program should be something like this:

%WinDir%\Sysnative\WindowsPowershell\v1.0\powershell.exe -executionpolicy unrestricted -file MyScript.ps1

The variable sysnative will redirect the 32-bit process to the 64-bit subsystem and, in our example, will start the 64-bit PowerShell executable (instead of the 32-bit one).

Encrypting passwords in a PowerShell script - Use sysnative in the SCCM program properties

The next step in the script is to retrieve all task sequence and collection variables. When the variable name is MyPassword, it's value is read and stored in the PowerShell variable $AccountPassword.

After that, the PSCredential object is created using the user name stored in the variable $Account and the password stored in the collection variable MyPassword.

For more information on how to create a PowerShell script in an SCCM package please see the following two articles:

One last tip; make sure to watch out when writing the variables to a log file. You do not want to write your password to your log file in plaintext!

Conclusion:

  • Biggest advantage: relatively secure (but definitely not 100%!).
  • Biggest drawbacks: the SCCM collection variable cannot be shared among other collections. The password variable needs to be set on each collection that requires it. Also, retrieving the password using the Microsoft.SMS.TSEnvironment COM object is relatively complex.

PowerShell Credentials Manager

Finally, I want to present to you another approach which I found very interesting, namely using the local Windows Credentials Manager to store your passwords.

The PowerShell script can be found in the Microsoft Script Center Gallery:
https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Credentials-d44c3cde

Please be aware that this script has not been tested on newer operating systems such as Windows 10 and Windows Server 2016. Also, this script only works on the local server. The Win32 API CredMan cannot connect to remote computers.

Conclusion:

  • Biggest advantage: 100% secure.
  • Biggest drawback: can only be used locally and the automation is complex.

All-in-all, none of the methods presented in this article are perfect. There simply is no 100% perfect solution. Each method has some advantages and some drawbacks, but these methods are all that exist (at least to my knowledge). You need to choose the one which is best suited for your current situation.

I hope this article gave you some insights in the world of passwords and PowerShell. Happy scripting!

Share this post:
Dennis Span on EmailDennis Span on LinkedinDennis Span on Twitter
Dennis Span
Dennis Span
Dennis Span works as a Senior Citrix Architect for a large insurance company in Vienna, Austria. He holds multiple certifications such as CCE-V, CCIA and CCEA. In 2017, Dennis became a Citrix Technology Advocate (CTA). Besides his interest in virtualization technologies and blogging, he loves spending time with his family as well as snowboarding, playing basketball and rowing. He is fluent in Dutch, English, German and Slovak and speaks some Spanish.

7 thoughts on “Encrypting passwords in a PowerShell script

  1. Pingback: Citrix Delivery Controller unattended installation with PowerShell and SCCM - Dennisspan.com

  2. Pingback: Citrix App Layering Agent unattended installation - Dennis Span

  3. "The following code snippet show you how the PSCredential object retrieves the content from the password file (C:\AES_KEY_FILE.key), using the AES key in the key file (C:\AES_PASSWORD_FILE.txt)."

    It appears you accidentally flipped the file names (stating that the password file is entitled "key" and that the key file is entitled "password").

  4. Pingback: Citrix Application Probe Agent unattended installation - Dennis Span

  5. Thank you for the excellent breakdown of options for creating secure credentials for use in PS scripts. I am new to PS and trying to understand the best way to apply these stored credentials to an exe file in a PS script that is using switches to supply username and password to the exe. There seems to be a lot of posts out there about using stored credentials with PS cmdlts but little to nothing about exe. I am trying to convert a batch file with clear text credentials to a more secure powershell script.

Leave a Reply

Your email address will not be published.

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.