Importing and Exporting Credentials in PowerShell
One question that comes up fairly often when dealing with (or writing!) secure cmdlets is how to properly handle usernames and passwords. The solution there is to use (or make) the -Credential parameter of type PSCredential. A PSCredential object helps ensure that your password stays protected in memory, unlike cmdlets that accept a straight username / password combination.
If a parameter is of type PSCredential, PowerShell supports several types of input:
- empty: If you supply no input to a mandatory -Credential parameter, PowerShell prompts you for the username and password.
- string: If you supply a string to the -Credential parameter, PowerShell treats it as a username and prompts you for the password.
- credential: If you supply a credential object to the -Credential parameter, PowerShell accepts it as-is.
This is great for interactive use, but what if you want to write an automated script for a cmdlet that accepts a -Credential parameter? The solution lies in passing a pre-constructed PSCredential object. The solution to this is covered by recipe 16.9 in the PowerShell Cookbook:
Securely Store Credentials on Disk
Your script performs an operation that requires credentials, but you don’t want it to require user interaction when it runs.
To securely store the credential’s password to disk so that your script can load it automatically, use the ConvertFrom-SecureString and ConvertTo-SecureString cmdlets.
Save the credential’s password to disk
The first step for storing a password on disk is usually a manual one. Given a credential that you’ve stored in the $credential variable, you can safely export its password to password.txt using the following command:
PS >$credential.Password | ConvertFrom-SecureString | Set-Content c:\temp\password.txt
Recreate the credential from the password stored on disk
In the script that you want to run automatically, add the following commands:
$password = Get-Content c:\temp\password.txt | ConvertTo-SecureString $credential = New-Object System.Management.Automation.PsCredential ` "CachedUser",$password
These commands create a new credential object (for the CachedUser user) and store that object in the $credential variable.
When reading the solution, you might at first be wary of storing a password on disk. While it is natural (and prudent) to be cautious of littering your hard drive with sensitive information, the ConvertFrom-SecureString cmdlet encrypts this data using Windows’ standard Data Protection API. This ensures that only your user account can properly decrypt its contents.
While keeping a password secure is an important security feature, you may sometimes want to store a password (or other sensitive information) on disk so that other accounts have access to it anyway. This is often the case with scripts run by service accounts or scripts designed to be transferred between computers. The ConvertFrom-SecureString and ConvertTo-SecureString cmdlets support this by allowing you to specify an encryption key.
When used with a hard-coded encryption key, this technique no longer acts as a security measure. If a user can access to the content of your automated script, they have access to the encryption key. If the user has access to the encryption key, they have access to the data you were trying to protect.
Note: Due to limitations in Version 1 of PowerShell, passwords encrypted with a specific encryption key can only be successfully decrypted by the same instance of PowerShell.exe process. Trying to decrypt the passwords with a different PowerShell.exe process will not be successful. To encrypt the passwords to disk in a way that can be read by other processes, use the .NET Encryption APIs: http://poshcode.org/116.
Although the solution stores the password in a specific named file, it is more common to store the file in a more generic location—such as the directory that contains the script, or the directory that contains your profile.
To load password.txt from the same location as your profile, use the following command:
$passwordFile = Join-Path (Split-Path $profile) password.txt $password = Get-Content $passwordFile | ConvertTo-SecureString
To learn how to load it from the same location as your script, see “Find your Script’s Location.”
For more information about the
ConvertFrom-SecureString cmdlets, type Get-Help ConvertTo-SecureString or Get-Help ConvertFrom-SecureString.