Powershell: How to encrypt and store credentials securely for use with automation scripts.

8
Jul 2013

Powershell: How to encrypt and store credentials securely for use with automation scripts.

comment icon9 comment(s) |

I recently worked on a quick and dirty Powershell script to send me email notifications when content on a web page changed. To send the email, I also went for the quick and dirty method and just used SMTP with my Gmail account. After I finished this dirty masterpiece, I couldn't handle seeing my password sitting in plain text, and I knew something had to be done. Here is how I solved this dilemma:

Step 1: Create your encrypted password file.

First you need a standalone .ps1 script to generate your password file. The following code will achieve this:

<# Set and encrypt credentials to file using default method #>

$credential = Get-Credential
$credential.Password | ConvertFrom-SecureString | Set-Content c:\scripts\encrypted_password1.txt

Run this script in Powershell, remember to set the execution policy appropriately, and Windows will prompt you for a username and password. Username isn't important since we are just storing the password, but go ahead and enter it anyway. This will create a text file in the specified location with a hash of your password. They "key" to this...Wah wah...is your Windows account. If you don't specify a Key or SecureKey parameter, the default is to use the Windows Data Protection API. Basically, that means using your Windows profile as the key. Note that it's also specifc to the machine where you encrypted it. So, you can't decrypt with the same account from another machine. For more information check out this long boring article: http://msdn.microsoft.com/en-us/library/ms995355.aspx. Why wouldn't I specify a key? Laziness mostly, and I like methods that integrate with Windows authentication. More importantly, I didn't see an obvious way of making the the key secure and accessible. In a production environment, I would recommend a service account used solely for creating and running the encryption and automation scripts.

Step 2: Use the encrypted password file in your automation scripts.

Here is a simplified snippet of code using the encrypted password:

<# 
    Set some variables
    ...
#>
$emailusername = "myemail"
$encrypted = Get-Content c:\scripts\encrypted_password.txt | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($emailusername, $encrypted)

if($something = $somethingElse)
{
    <#
        Do some stuff
        ...
    #>

    $EmailFrom = "myemail@gmail.com"
    $EmailTo = "myemail+alerts@gmail.com"
    $Subject = "I did some stuff!" 
    $Body = "This is a notification from Powershell." 
    $SMTPServer = "smtp.gmail.com" 
    $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587) 
    $SMTPClient.EnableSsl = $true 
    $SMTPClient.Credentials = $credential;
    $SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
}

Note the secret sauce that imports the password on lines 6 and 7. We don't specify any parameters with the ConvertTo-SecureString method because we want it to use the Windows account running the script for decryption, exactly like we did with the ConvertFrom-SecureString for the encryption. After that we can use that credential object willy nilly, example on line 23.

I hope this has been helpful in showing that with a small amount of effort you can get away from storing passwords in plain text in your Powershell scripts.

Comments

July 12, 2013

Chris

Stored Credentials

This is a very common problem and you can also use the Credential Manager built in to Windows to store those credentials and access them from Powershell.

http://www.automatedops.com/blog/2013/06/07/get-storedcredentials-module/

July 15, 2013

trhymer

Thanks for the comment Chris.

Thanks for the comment Chris. I didn't think to store credentials like that. That would definitely make this easier to manage, rather than a bunch of text files. But again this was just a quick and dirty way to get the job done. I guess SEO hadn't settled in on your post or I might have come across it while I was working this :).

October 7, 2013

Kevin

SQL and encrypted pwd

Your script on stroing encrypted creds works great. I have SQL code accessing a database. I have been passing the read-only creds in the script itself. I tried your script but it won't work as the COnnection string wants an UNencrypted pwd. ANy ideas how I might do this?

October 30, 2013

trhymer

MSSQL?

Is this MSSQL? If so can you use integrated security instead?

July 21, 2013

Trite

Also works with Export-CliXml

Definitely a good read, didn't realize it could be stored that way. Personally I export credentials using Export-CliXml, it makes importing a bit simpler and you get back an entire PSCredential object rather than just the password. It still uses the same Windows Data Protection API.

Always nice to know more ways to get the job done though!

October 17, 2013

Marc

Gmail with encrypted password

The encryption do well but when i do try to pass the credential with your code , i always have the follwing error

The SMTP server requires a secure connection or the client was not authenticated.

Any idea what's wrong?

October 30, 2013

trhymer

Does it work if you don't

Does it work if you don't encrypt the credentials?

March 7, 2014

Anonymous

thank you

This simple thing really helped me out. I'm new to PowerShell and when it actually worked, I felt like I could take on the world lol.

March 18, 2014

Geoffrey Rance

How would you use this

How would you use this functionality for the purposes of an FTP script? To pass it as one line, you have, in the script ftp://username:password@ftp.site.com. Replacing the username:password with $credential doesn't work. How do you format that?

Search