2

Encrypting Passwords in Scripts: The Ultimate Best Practice Guide for Powershell

Unencrypted passwords in Scripts?  We all know that it’s a huge security risk and an overall big no no to have your passwords in plain text.  Sometimes we want to run Scheduled tasks without the need to be standing by to enter in the appropriate credentials.  Or if you’re like me you have the need to connect to Azure or Exchange Online 50 million times a day, but don’t like having the session or Powershell Window open when not needed. So what are the best practices to having your passwords in your scripts to automatically connect to services?  We’ll go over that next.

 

Passwords in Scripts for Powershell

Here is my process for when I want to have my passwords in my scripts. The following we’ll only need to do one time every 3 months or when I change my password.

First we need to get our Credentials.


$Creds = Get-Credential

Then I create an obscure random folder and export the credentials to that folder via the Export-Clixml cmdlet. So for example I’ll pick C:\Windows\System32\WindowsPowerShell\v1.0\Modules\SomeFakeModule and export the ps1xml file there.


$Creds | Export-Clixml C:\Windows\System32\WindowsPowerShell\v1.0\Modules\SomeFakeModule\SomeRandomFilename.ps1xml

Now there should be a file SomeRandomFilename.ps1xml in the C:\Windows\System32\WindowsPowerShell\v1.0\Modules\SomeFakeModule folder. Next I’ll convert that path to a secure string and convert it back from a secure string to get a long random hex character string. That would look something like this..


'C:\Windows\System32\WindowsPowerShell\v1.0\Modules\SomeFakeModule\SomeRandomFilename.ps1xml' | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File C:\_Scripts\SomeOtherDirectory\AnotherRandomFilename.ps1xml

The AnotherRandomFilename.ps1xml should contain something like this.


01000000d08c9ddf0115d1118c7a00c04fc297eb010000004af7b54b56de384793f6556f9f497f240000000002000000000003660000c0000000100000001a2e14d11a0435bb980161d9141109be0000000004800000a0000000100000008686204fd145b3cb74dbf328cf3dc19d60000000836224a5abf022bff65da641f93be649c221418303c626e626ee299eea9af9028308041a1f364a6294d8c31a8060dd19156f48b8df58f060f5b1025070946d1e390005ef0c0ece3f9127a7830711da7d54665d87f

The above is the only part you need to do every time you change your password.

 

The Code to have in your Scripts.

Below is the part you need to have in your script where you run the script. So for example if i wanted to connect to Azure I would create an Connect-Azure.ps1 script with the following:


$Module = Get-Content C:\Scripts\SomeOtherDirectory\AnotherRandomFilename.ps1xml | ConvertTo-SecureString
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Module)

Connect-MsolService -Credential ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) | Import-Clixml)

This should allow you to connect with your ‘password’ in the script. I know, it’s confusing as hell but it’s that way by design. You can probably get away with the Export-Clixml and Import-Clixml cmdlets since Powershell can only decrypt the credentials from the same user and computer accounts. In other words, if another user on that same computer tried to import the exported credentials, it will fail. Alternatively, if the same user tried to import the credentials from another computer, it will also fail. Sometimes however, a little extra confusion only makes it harder to reverse engineer what someone is trying to do.

Now you can import the clixml in whatever script you wish. If you want to learn more with online video, take a look at our Youtube Channel

4.9/5 - (10 votes)

Paul Contreras

Hi, my name is Paul and I am a Sysadmin who enjoys working on various technologies from Microsoft, VMWare, Cisco and many others. Join me as I document my trials and tribulations of the daily grind of System Administration.

2 Comments

  1. This is super funny since powershell is open source, a script.
    So having the password encrypted in some file and decrypting it into a string in the script itself, whoever wants to get it just needs to edit the script and echo the variable in the script itself instead of just passing it, unless you encrypt the script itself which i havent seen done since its open source.
    The best solution would be to not store passwords in any open source easily edited script.
    It should be coded in c++ or something similar and than encrypted in case you must have the password passed in plain text.
    Will be harder for the attacker to obtain.

    • @Pepo

      Except that the password is stored as a secure string (In this case, generated by Get-Credential) which can only be decoded by the Windows account that made it (So you need the secure string, access to his account, and I may be wrong on this part, but the computer it was created on).

      Hence why he says he has to regenerate it every 3 months when he changes his password.

      While you definitely, wouldn’t opt for something like this in a corporate environment (You would go with more secure methods like certificates for example) this isn’t a terrible way for people at home who want to run some scheduled scripts that require credentials while avoiding plain text.

Leave a Reply

Your email address will not be published. Required fields are marked *