Fun with PSCredentials
Back in October of 2012, I posted Securely Storing a Password, which showed the key commands to capture a password and store it as a SecureString in a file. However, this doesn’t address using that password as a PSCredential. Let’s remedy that. Here are three functions to save the password from a PSCredential to a file, to recreate a PSCredential with that stored password, to test the PSCredential (by starting a PSSession over WinRM to the local host.)
Update: Thanks to Lee Holmes for this bit of good news from V3:
PSH> $cred = Get-Credential
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
PSH> $cred | Export-CliXml c:\temp\cred.clixml
PSH> $cred2 = Import-CliXml c:\temp\cred.clixml
function Test-PSCredential {
<#
.synopsis
Validates a PSCredential by starting a PSSession.
.description
Validates a PSCredential by starting a PSSession by default on the localhost. Specify -ComputerName to target another host, such as if localhost does not have WinRM enabled.
.parameter Credential
PSCredential to validate. Required.
.parameter ComputerName
Computer to test against. Defaults to localhost.
#>
param (
[System.Management.Automation.PSCredential]$Credential = $null,
[string]$ComputerName = $env:COMPUTERNAME
);
try {
if ($Credential) {
$session = New-PSSession -ComputerName $ComputerName -Credential $Credential -ErrorAction SilentlyContinue;
if ($session -and ((Get-PSSession -Id $session.Id).State -eq 'opened')) {
$true;
} else {
Write-Warning "Test-Credential -credential invalid";
}
} else {
Write-Warning "Test-Credential -credential not specified.";
}
} catch {
# insert error handling here
}
}
function Export-PSCredential {
<#
.synopsis
Securely save the password from a PSCredential to file.
.description
Save the password from a PSCredential to file as a SecureString. This is encrypted with keys from both the current user and the local machine, so the file will not be usable by any other user, or on any other machine.
.parameter Credential
PSCredential to store. Required.
.parameter Path
File to store the password. Defaults to "$home\<DNS domain>#<user name>.credential.dat" of the current user.
#>
param (
[System.Management.Automation.PSCredential]$Credential = $null,
[string]$Path = $null
);
if (!$Path) {
$Path = "$home\{0}.credential.dat" -f ($Credential.UserName -replace "\\", "#");
}
if ($Credential) {
$Credential.Password | ConvertFrom-SecureString | Set-Content -Encoding Ascii -Path $Path;
if (Test-Path -Path $Path) {
Get-Item $Path;
} else {
Write-Warning "Export-Credential credential for '$($Credential.UserName)' failed to save to file '$Path'."
}
} else {
Write-Warning "Export-Credential -credential not specified.";
}
}
function Import-PSCredential {
<#
.synopsis
Create a PSCredential from a password stored in a file.
.description
Create a PSCredential from a password stored in a file as a SecureString. While it can generate a PSCredential for another user, it still decrypts the SecureString in the file with keys from btoh the current user and local machine.
.parameter Path
File containing the password. Defaults to "$home\<DNS domain>#<user name>.credential.dat" for the value specified in -UserName.
.parameter UserName
Domain\User for whom to create the PSCredential. Defaults to "<DNS domain>\<user name>" of the current user.
#>
param (
[string]$Path = $null,
[string]$Username = "$($env:userDnsDomain.ToLower())\$env:UserName"
);
try {
if (!$Path) {
$Path = "$home\{0}#{1}.credential.dat" -f $env:USERDNSDOMAIN, $env:USERNAME;
}
if (Test-Path -Path $Path) {
$SecurePass = Get-Content -Path $Path | ConvertTo-SecureString -ErrorAction SilentlyContinue;
if ($SecurePass) {
New-Object System.Management.Automation.PSCredential $Username, $SecurePass
} else {
Write-Warning "Import-Credential -path '$Path' unable to be converted.";
}
} else {
Write-Warning "Import-Credential -path '$Path' not found.";
}
} catch {
# insert error handling here
}
}
Comments
- Anonymous
March 24, 2015
Really good, I need this to automate taks. Thank you.