Saving Passwords (and preventing other processes from decrypting them)

This question is nothing new: “How do I save credentials in PowerShell so I don’t have to enter a password every time the script runs?” An answer to that question has been in PowerShell for a very long time: you use the ConvertFrom-SecureString cmdlet to encrypt your password, save the resulting encrypted string to disk, and then later reverse the process with ConvertTo-SecureString. (Alternatively, you can use Export-CliXml, which encrypts the SecureString the same way.) For example:

The ConvertFrom-SecureString and ConvertTo-SecureString cmdlets, when you don’t use their -Key, -SecureKey, or -AsPlainText switches, use DPAPI to encrypt / decrypt your secret data. When it comes to storing secrets with software alone (and without requiring a user to enter a password), DPAPI’s security is about as good as it gets. It’s not unbreakable – all of the encryption keys are there to be compromised by someone with Administrator access to the computer – but it’s pretty good.

You can see the details on how DPAPI works in the linked article, but here’s the long and short of it: By default, only the same user account (and on the same computer) is able to decrypt the protected data. However, there’s a catch: any process running under that user account can freely decrypt the data. DPAPI addresses this by allowing you to send it some optional, secondary entropy information to be used in the encryption and decryption process. This is like a second key that is specific to your program or script; so long as other processes don’t know what that entropy value is, they can’t read your data. (In theory, now you have a problem with protecting your entropy value, but this at least adds an extra layer that a malicious program needs to get around.) Here’s an excerpt from the article:

A small drawback to using the logon password is that all applications running under the same user can access any protected data that they know about. Of course, because applications must store their own protected data, gaining access to the data could be somewhat difficult for other applications, but certainly not impossible. To counteract this, DPAPI allows an application to use an additional secret when protecting data. This additional secret is then required to unprotect the data.

Technically, this “secret” should be called secondary entropy. It is secondary because, while it doesn’t strengthen the key used to encrypt the data, it does increase the difficulty of one application, running under the same user, to compromise another application’s encryption key. Applications should be careful about how they use and store this entropy. If it is simply saved to a file unprotected, then adversaries could access the entropy and use it to unprotect an application’s data.

Unfortunately, the ConvertFrom-SecureString and ConvertTo-SecureString cmdlets don’t allow you to specify this secondary entropy; they always pass in a Null value. For that reason, I’m putting together a small PowerShell script module to add this functionality. It can be downloaded from the TechNet repository. It adds an optional -Entropy parameter to both ConvertFrom-SecureString and ConvertTo-SecureString.

Since I was tinkering with those commands anyway, I also added an -AsPlainText switch to the ConvertFrom-SecureString command, in case you want to get the plain text back. This saves you the couple of extra commands to set up a PSCredential object and call the GetNetworkCredential() method, or make the necessary calls to the Marshal class yourself.

10 thoughts on “Saving Passwords (and preventing other processes from decrypting them)

  1. GS

    If this is available only from the same account, then how do you use this if you want to write a script to say authenticate to remote file server and run as scheduled task under network service account

    1. Dave Wyatt Post author

      Hi GS,

      If you’ll be scheduling your script to run as the Network Service account, then you’ll also need to create the encrypted password file using that same account (if you’re using the ConvertFrom / ConvertTo-SecureString cmdlets and DPAPI.) Network Service has a user profile of its own in C:\Windows\ServiceProfiles\NetworkService , and I assume it has its own DPAPI master keys as well, though I haven’t tested this functionality for something running as Network Service myself.

      In this case, you can probably also avoid the need to store credentials at all. When something runs as Network Service and needs to contact a remote computer, it authenticates using your computer’s Active Directory account, which can be added to Security groups or granted permissions the same as any User account. You could also just schedule the task to run as a user who has permissions to the remote file server; either way, the script can authenticate as the user who ran it, rather than having to specify alternate credentials.

  2. Pingback: Zajímavé novinky ze svÄ›ta IT z 48. týdne 2013 | Igorovo

  3. Pingback: Revisited: PowerShell and Encryption |

  4. Pingback: Episode 257 – PowerScripting Podcast – PowerShell Hero Dave Wyatt on Error Handling |

  5. Pingback: Quick hits: Credentials and Dynamic Parameters | rambling cookie monster

  6. Pingback: Running a BODS (data services) job using windows powershell | Nagaraj Gadiraju's Blog

  7. Pingback: Storing Secure Values | Lost In The Shell

  8. Pingback: Saving Passwords (and preventing other processes from decrypting them) | Password Security

Comments are closed.