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 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
12.11.2023: Updated this article. The PowerShell Credentials Manager script is no longer available on the Microsoft website.
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!
05.12.2018: Additional comment added concerning the usage of plaintext passwords.
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!!!

*As was pointed out to me in one of the comments below, technically speaking using plain text passwords does have some advantages. However, looking at the overall system as a whole, taking, among other things, security into consideration, plain text passwords should be avoided as much as possible. From a security perspective, they do not hold any advantages.

Now let’s get on with the good stuff. The remainder of this article will show you a couple of ways 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.
  • The 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 then 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 create them?

The following code snippet shows 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 quite simple:

  • First, save the PowerShell script below in a PS1 file (e.g. C:\CreateSecurePassword.ps1). You can change the directory path and file 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:
https://www.virtualtothecore.com/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 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 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 then 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.
  • The biggest drawback: is 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, its 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 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 that I found very interesting, namely using the local Windows Credentials Manager to store your passwords.

The PowerShell script can be found on Github:
GitHub – davotronic5000/PowerShell_Credential_Manager: PowerShell Module to Read and Write Credentials from the Windows Credential Manager

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 that is best suited for your current situation.

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

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

  6. For plain text, you listed biggest advantages as “none”. This is incorrect. There are advantages, which is why so many people do it. I’m not saying it is *right*, I’m just saying there are advantages. For example: 1) easy, 2) works with any scripting method, 3) may be acceptable for some passwords (such as an initial temporary password that will be forced to change at first use)

  7. Pingback: Creating an ODBC Connection With PowerShell Using a Specific Account – Mark Roberts

    • Hi Gert, as explained in the article you can decrypt the password using the command Write-Host “Password is: $PasswordAsString”, but you need both the key file and the password file.

  8. Pingback: password protect powershell script - infoai.net

Leave a Reply

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

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