What do you do when you need to provide a password in a batch file or to a legacy command line application but don’t want to store the password in plain text inside of the file? As usual, it’s Powershell to the rescue.
The basic steps are:
- Create a text file that contains the encrypted version of your password
- Read that password into a variable
- Convert that password into a Credential Powershell object
- Call a method of the credentials object to pull out the plain text password
The code looks like this:
#Run one time to create the encrypted password file then remove this line Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File c:\temp\cred.txt # Read in the password file you created and convert it to a securestring $password = get-content C:\temp\cred.txt | convertto-securestring # Create a Powershell Credential object that includes this password. # Note that a username is also required but my command doesn't take a username so I just filled it something. It also can't be blank $creds = New-Object System.Management.Automation.PSCredential -argumentlist "MustHaveSomething", $password # Run the legacy command and call the GetNetworkCredential method with the password property # The application will get the password but the end user will never see it. You'd have to have administrator access to the machine and a debugger to get the password &reflectverify.exe d:\Backup\* -p $creds.GetNetworkCredential().Password
So ultimately if someone has a copy of cred.txt, they can still use it to access the resource but at least this way they don’t know what the actual password was.
I’ve spent a little more time with this concept and wanted to share my findings. The convertto-securestring cmdlet leverages the “DPAPI” or Data Protection API for Windows. This API creates a local key that is tied to the SID of the logged in user account as well as a master key file stored inside the users profile. What this means is that even if someone else gets a copy of your encrypted text file, they will NOT be able to use it. I confirmed this by loading up a new Windows 8.1 VM and trying to read the encrypted password I created on my source machine. It fails with the error “Key not valid for use in specified state.”
I then investigated a bunch of methods for backing up and restoring the key. I exported all of the keys in my certificate store on my source machine to the destination. I copied the master keys from the source at:
I used the password recovery disk and export credentials functions built in to Windows. Unfortunately (or fortunately depending on how you look at it), none of the options allowed me to run the script on the new machine.
The closest I found was this Microsoft article from 2009 that talks about exporting the DPAPI keys and making registry changes and running a command called dpaimig.exe.
None of this worked for me either.
Therefore the moral of the story appears to be this:
If you use the convertto-securestring functionality in a batch script or scheduled task, you need to be aware that validating those credentials is dependent on the user running the command being the same one that generated the key. So you’ll need to generate the initial key with your service account for example. Likewise, if you ever have a computer crash or need to migrate the computer, you’ll need to regenerate the password key file. Therefore it will be necessary to store the password somewhere else (Keepass for example) for documentation and disaster recovery purposes.
At the end of the day, it’s still an improvement over storing the password in plain text in the file!