Monday, 15 November 2010

Encrypting PowerShell credential passwords

So continuing from my last post, after getting my monitoring script to work, I set about trying to introduce some semblance of security to at least partially hide the plain text password held within the script.

My initial success was through the use of the ConvertTo-SecureString and ConvertFrom-SecureString cmdlets. Essentially (or least as far as I understand it), the first of these converts some form of password string into some kind of system value, eg if you try simply outputting the contents of $password in the first script, it simply returns something like 'Secure-String', rather than a representation of the password itself. The second cmdlet converts that system value into an actual string value, though it's encrypted rather than the original ascii text as we'll see shortly.

So, my first task was to get hold of that encrypted version of the string, so I could then put that direct into the script, and use it in place of the plain text password. Using the following code I encrypted the password and then outputted it into a text file.

$password = "<password>"
$secure = ConvertTo-SecureString $password -force -asPlainText
$bytes = ConvertFrom-SecureString $secure
$bytes | out-file c:\batchscripts\securepassword.txt

Extracting the resulting string from the text file, I added it into my script, and then adjusted the ConvertTo-SecureString line to receive an encrypted string rather than a plaintext one as you can see below.

$encrypted = "01000000d0818c7a00c04fc297eb0100005facd6ca6de9cea76f00d66edd9b000200000ad8d083414008862f428071c6ae0100e0000bc55db88fe323270008f8719303e96f00000a81f1800000003660000a8000000100000009b2d8ff163728442ad93544b7dccad8500000000048000c9ddf0115d1100a000e0045dfadc703191efaac7e6000490ad18f2ced20db2ccabac0000b2b660bd2a75dc73ba7a278f448"
$username = "<username>"
$password = ConvertTo-SecureString -string $encrypted
$myCred = New-Object System.Management.Automation.PSCredential $username, $password
if (test-connection -computername <computername> -source <source> -Credential $myCred -Quiet)
{"1";exit "1"}
else {"2";exit "2"}

To my relief this then worked, exactly like the original script! Filled with joy (ok, maybe not joy, but certainly pleased with myself), I updated the monitoring system to use the new script, set it running, and can you guess what happened? Yep, it failed. I went through all the settings, they were fine. I switched back to using the old script, it worked again.

After scratching my head for a while I had an idea, possibly a crazy one, but worth a try. I set the monitoring system to execute the script that generates the encrypted password so I could see what the output would look like. It was completely different to the one outputted direct on the server! I re-ran the server version, and sure enough, it produced the same output as it did the first time.

Clearly something about the encryption process used in ConvertTo-SecureString is dependant on where it is run. I updated the script with the new string, set the monitoring system going again, and finally it worked!

So the lesson here is that if you try this yourself, what ever system you are using to call your script, you must also get it to call the encryption script as well, and use THAT output to populate your monitoring script with its password.


  1. Keith,

    You said you were able to get this to work with IPMonitor's external process monitor. I am doing something similar, but am having troubles figuring out whether to use the process' return value or compare value of environment variable. Right now I have the script set to either exit 1 (process running) and exit 2 (process not running). I have tested the script and it returns the appropriate values whether or not the script is running.

    Just looking to hear more information on what options you went with. Thanks!

    1. That should say whether or not the process (NOT SCRIPT) is running.