Tuesday, September 10, 2019

Have PowerShell Keep Your Confidential Information … Confidential!


As an IT professional, you have no doubt needed to run processes with elevated privileges. PowerShell makes it quite easy with the Get-Credential cmdlet:
$creds = Get-Credential
This pops up a window for you to securely enter your credentials:


You can then use the credentials in cmdlets that support the -Credential parameter. So, if I wanted to connect to a DDC to get a list of all Citrix sessions, I might do something similar to the following:
$sessions = Invoke-Command -ComputerName CitrixDDC01 -Credential $creds -ScriptBlock {
       Add-PSSnapin Citrix*
       @(Get-BrokerSession)
}

What if I wanted to create an automated script to retrieve sessions multiple times during the day (and maybe night)? I may not want to remain up until 3 AM to run the above script. PowerShell’s got you covered there, as well, with a way to securely save your credentials.
# Securely store user credentials
$creds = Get-Credential
$pwLocation = "C:\PowerShell\Credentials\securePW.txt"
$creds.Password | ConvertFrom-SecureString | Set-Content $pwLocation

The above snippet will securely encrypt your password and store it in the specified location. This only needs to be done once, and then the above credentials can be used in any number of scripts by simply adding the following:

$userName = "username specified above"
$pwLocation = "C:\PowerShell\Credentials\securePW.txt"
$securePW = Get-Content $pwLocation | ConvertTo-SecureString
$creds        = New-object System.Management.Automation.PSCredential($userName,$securePW)

Now, if you’re a Network Security admin, you may be wondering “How secure is that? What happens if someone gets hold of the file with the encrypted password? They now have the keys to all your scripts!” Not to worry. The file is encrypted using your security context. This simply means that only you can decrypt the secure file. If someone else tries to copy and use the file, it would be totally useless.

It’s not just for passwords anymore!

I am constantly giving demos of PowerShell scripts, and some of them, in addition to passwords, may contain other confidential information. For example, database connection strings, or even the names of servers, such as the DDC in the example above. Get-Credential can be used for these as well.

# Securely store DDC name
$SecureDDC = Get-Credential
$ddcLocation = "C:\PowerShell\Credentials\secureDDC.txt"
$SecureDDC.Password | ConvertFrom-SecureString | Set-Content $ddcLocation



Again, the above need only be done once. I can then securely retrieve the name of my DDC without showing it in scripts with the following:

$DDCName = "SecureDDC"
$ddcLocation = "C:\PowerShell\Credentials\secureDDC.txt"
$encryptedDDC = Get-Content $ddcLocation | ConvertTo-SecureString
$secureDDC  = New-object System.Management.Automation.PSCredential($DDCName,$encryptedDDC)
$DDC  = $secureDDC.GetNetworkCredential().Password

$sessions = Invoke-Command -ComputerName $DDC -Credential $creds …

If you plan to use Task Scheduler to run your script, make sure that you run the task under the same context used to create the encrypted string. Otherwise, the secured string returned will be blank!