Secure Credentials in PowerShell Scripts

The scripts that I write occasionally need access to specific user account credentials in order to do their work, so I wanted to write a quick note about how to securely store those credentials for scripts (especially if they're going to be run as a scheduled task)!  It all revolves around the get-credential cmdlet.

The get-credential cmdlet is made for this; by default, the object that it creates is encrypted to the account that executed it as a secure powershell object.  This means that you can easily save those credentials to a secure file with these two commands:

$creds = get-credential -message "Enter credentials"

$creds | export-clixml $credsFile

Many PowerShell cmdlets can take credentials in the form of a credentials object (frequently with the "-credential $creds" syntax), but even when you need to supply a username and password, they're really easy to get out of that $creds object:

$creds.UserName

$creds.GetNetworkCredential().password

If some other user attempts to import the xml password object, they'll get an error that reads "import-clixml : Key not valid for use in specified state."  If you just open the XML file directly, you can plainly see the password property... and that it's nice and encrypted!  So, only the account that ran the get-credential cmdlet can access the password stored in the XML file that we can generate from that object.  How's the easiest way to use this in our scripts?  If it's a script that people will be executing, I like to put it in a Try/Catch block like this:

try {

$creds = import-clixml $credsFile

}

catch {

$creds = get-credential -message "Enter credentials"

$creds | export-clixml $credsFile

}

The script will try to import the credentials in the specified file and, if that fails, will prompt the user for credentials and then save them in the file.  In practice, this means that the first time a given user runs the script, they'll need to enter their credentials, but after that they're saved in a file that only that user account can access.  But what do you do if you're preparing this script to run as a scheduled task?  Well, our old friend "runas.exe" comes in handy there!

runas.exe /user:domain\serviceAccount powershell.exe

The easiest way to create the credentials object for the account that'll be running the scheduled task is to just open up a PowerShell prompt as that user.  So, you can fire off that above command to give you such a window, and from there you can do the whole "get-credential | export-clixml $credsFile" process to pre-seed the credentials XML file for the service account!

Comments

  1. Might also check out the SecretManagement module which is cross-platform
    https://github.com/powershell/secretmanagement

    ReplyDelete

Post a Comment

Sorry guys, I've been getting a lot of spam recently, so I've had to turn on comment moderation. I'll do my best to moderate them swiftly after they're submitted,

Popular posts from this blog

PowerShell Sorting by Multiple Columns

Clone a Standard vSwitch from one ESXi Host to Another

Deleting Orphaned (AKA Zombie) VMDK Files