Every now and then I like to do a little bit of bug hunting in
Grumpy Admin here. Security is not a dirty word Blackadder! I expect we have all seen cases where at some point or the other we had a script that need to do something and need Admin Credentials. Where there is a wonderful line at the start of the script saying!
This is bad, very bad! I cringe when I see this, making me super grumpy! I saw this in a script on my product system today and I was like, head hit desk… Not only were Admin Credential exposed for anyone with Notepad to see, it also showed that said password hasn’t been changed since the script was written in 2011… double face palm! Grumpy is not really the correct description for me at this stage. However, it did give me a reason to demonstrate and explain all about how credentials and [securestring] work in PowerShell. So I thought I would share some insight.
Powershell allows us store data like passwords like this in a data type called SecureString – which can then be used as part of a PSCredential Object.
I want this script to ask me for the credentials and I wanted to be able to store this securestring in a file and re-read it back at a later date.
Let’s have a quick look at this problem. First we need to get the password in to the SecureString. We can do this in a couple of ways.
The first way is using read-host and storing the results as a secure string.
For example, Powershell understand the –AsSecureString means it going to be sensitive data, so it protects the input and masks them as *. Kinda Neat
$password = Read-host -AsSecureString “Enter Password”
The second, and my preferred method is we can use the get-credential cmdlet – which displays a warmer friendly and familiar feeling to entering in a password.
This has the added bonus of encapsulating the username in it as well, handy
as you can see it is stores the Password as a securestring by default, which is good – means less typing!
Now the method Windows/Powershell uses to encode this secure string by default without specifying keys and other things like that means that only the account that created it can decrypt it! The whole thing is called the Windows Data Protection API. I will spare you this beast today! But it is worth having a look at it, seeing how it works and how you can take advantage of it!
So if I saved the output from securestring on another computer to a file and then copied that file containing the securestring , I wouldn’t be able to decode it as the user accounts are different. (effectively the key used to “secure” the securestring. This means you can’t easily without going through a few hoops, store a securestring password in a string inside your script without a bit of work.
Now we can out-file the read-host $password however, when we try to do an out-file with the get-credential method it fails
so we have actually grab the property and convert that instead because we quickly forgot that everything is an object!
$password |ConvertFrom-SecureString | out-file c:\test\Grumpy\Password\pass.txt
$password.Password |ConvertFrom-SecureString | out-file c:\test\Grumpy\Password\pass.txt
Convertto-securestring cmdlet and a get-content command – all easy stuff right?
[securestring]$testpassword =get-content .\pass.txt |ConvertTo-SecureString
That is great, we have the securestring from a file. Now we need to do some magic using the interopservices.marshal class to convert the securestring back to a plain string.
It is times like this, I really should give consideration to decent variable names!!! My lack of thinking means I have an object with the same name as a property lol and $password.password looks silly to me! But meh! Grumpy Admin is too lazy to change that now! Especially as I already done the screenshots for this post.
What happens if I copy this pass.txt file to another computer and try to decode the string like we did then -So you can see we don’t have the correct “key” to be able to decode this password and we get a sea of PowerShell red! All well and good!
This is good, means the securestring is only useful on the computer that it was generated on. (Well the way we are using securestring.
So that worked – we have a method of storing credentials in a file and reloading then as long as it is the same computer and the same user account, could be useful perhaps.
We can do other things like provide our own key to use, but I won’t go down this rabbit hole today, it’s a Friday and I’m waiting to clock out for the day.
Hang on Grumpy Admin – how do I then use this securestring. Well I guess I better show you that quickly. The most common way would be to use it as part of a PSCredential object.
So let’s do this quickly by creating a new PSCredential Object and storing the right things inside it!
$userpassword = get-credential
$credobj = new-objectSystem.Management.Automation.PSCredential($userpassword.username,$userpassword.password)
Then we can use it – for example – in this case I will use a enter-PSSession command to test the $credobject as we know it has the –credential parameter and that requires a PSCredential
Enter-PSSession -computer gridlap007 -Credential $credobj
So my advice is, don’t ever store passwords in your script. If you really really have to store a password and you don’t want to have to reenter it – store it in a file and reread it in – you can then recreate your PScredential object after that. It would stop the casual script reader seeing your password but it is as demonstrated NOT SECURE!!!!
Passwords are like underwear
- Should be changed often
- Don’t share them
- Should be mysterious
- And never leave them lying around!!!
Once you have the PSCredential object, don’t forget you can easily grab the credentials, username and password in plain text as well as the securestring version. long as you are the user or you have the correct key. This can be done using the following function
Hope this is of some use to someone out there – There lots of can do with this sort of thing, there the whole -key element to this which I won’t explore at this point.
So in summary, we looked at using get-credential / read-host to store an inputted password as a securestring. We looked at saving that securestring to a file, then reloading that file in as a securestring
We also had a quick look at how to decode a securestring to get the plain text password, followed by then creating a PSCredential Object to use the password.
And the most important lesson of all really is
DON’T STORE PASSWORDS INSIDE SCRIPTS