Credentials and Dynamic Parameters

Everyone has their preferred way to simplify credential handling in PowerShell.  Here are some of my favorites.  Before using these, consider your security policies and posture.

Import and Export PSCredentials

Many functions and examples out there simply serialize the encrypted password to disk, leaving you to handle the username.  Years ago, Hal Rottenberg wrote two handy functions that serialize and deserialize both the username and password; Import-PSCredential and Export-PSCredential.  The links are to very slightly modified functions.

Export-PSCredential -Path "D:\$ENV:COMPUTERNAME.$ENV:USERNAME.contoso.cmonster.crd" 

$credCMonsterContoso = Import-PSCredential -Path "D:\$ENV:COMPUTERNAME.$ENV:USERNAME.contoso.cmonster.crd"

Wait, isn’t that insecure?

There are a few considerations to take into account, but this isn’t as risky as you might expect.  Serializing the password to disk uses the Windows DPAPI to encrypt your password, limiting decryption to your account, on the computer you encrypted the password from.  Here are two considerations that immediately come to mind:

  • I don’t know of any exploits that can decrypt these files.  Might these already exist?  Might we find a vulnerability and see exploits down the line?  Perhaps.  This risk should be acceptable in most organizations, given password entropy, compensating controls over where these credentials are stored, and other factors.
  • Other processes on this system running as your account could access these credentials.  Dave Wyatt discusses a workaround using secondary entropy.

I’m personally comfortable using methods Lee Holmes describes in PowerShell Security Best Practices.  If in doubt, consult your security team.

Dynamic parameters

Dynamic parameters are parameters that are generated at runtime.  They can be both handy and painful.  The basic idea is that you can dynamically generate parameters depending on the runtime environment.  A few quick resources:

Why are we talking about dynamic parameters?  How are these related to credentials?

Serializing and deserializing credentials to disk is quite handy, but we can take this a step further.  If you don’t have a password management solution with an API, working with passwords can be quite tedious.  We’re going to devise a system where you keep PSCredentials stored in variables, with simplified copy-to-clipboard access via dynamic parameters.

Wait, isn’t that insecure?

Yes.  Copying any confidential data to the clipboard is risky.  Much riskier than relying on the DPAPI.  That being said, information security is about managing risk, not completely eliminating it.  Perhaps you would consider using this on a secured system where you don’t do much day-to-day browsing or other risky activities, and with a certain class of accounts.

Simplified credential management

We’re going to cover three steps; encrypting the credentials (one time, and after any changes), getting the credentials into your session, and a copy-password function.

Prerequisite:  Download and get the dependency functions into your session before using them.

# Load dependencies.            
    . "\\Path\To\Import-PSCredential.ps1"            
    . "\\Path\To\Export-PSCredential.ps1"            
    . "\\Path\To\New-DynamicParam.ps1"

Encrypt credentials using Export-PSCredential as desired.  You only need to do this one time, and any time the credentials change.

# I name mine COMPUTER.CURRENTUSER.[domain.]USER[Qualification as needed] to help identify where I can use them and what accounts they cover.            
# Access to decrypt these is limited to the user that exported them, on the computer they were encrypted on            
# Consider storing these in a secured location.  These are on my D:\ for illustrative purposes only            
            
Export-PSCredential -Path "D:\$ENV:COMPUTERNAME.$ENV:USERNAME.contoso.cmonster.crd"            
Export-PSCredential -Path "D:\$ENV:COMPUTERNAME.$ENV:USERNAME.cmonster.crd"            
Export-PSCredential -Path "D:\$ENV:COMPUTERNAME.$ENV:USERNAME.contoso.TestUser.crd"

Now, any time you want to access these, pull them into your session.  You could put these in your profile so they are always available, or use them in a script that needs credentials.  Don’t forget to dot source Import-PSCredential function beforehand.

# Import credentials we previously exported.  I'm using names starting with 'Cred'            
    $CredCMonsterDomain = Import-PSCredential -Path "D:\$ENV:COMPUTERNAME.$ENV:USERNAME.domain.cmonster.crd"            
    $CredCMonster = Import-PSCredential -Path "D:\$ENV:COMPUTERNAME.$ENV:USERNAME.cmonster.crd"            
    $CredTestUserDomain = Import-PSCredential -Path "D:\$ENV:COMPUTERNAME.$ENV:USERNAME.domain.TestUser.crd"

Now I can use these credentials as desired:

Cred1 Cred2

This is great for scripts, but if I want quick access to a password in an interactive session, typing this out is tedious.  Let’s write a function to quickly extract passwords from these PSCredentials:

function Copy-Password             
{            
                
    [cmdletbinding()]            
    param()            
    DynamicParam            
    {            
        $Variables = Get-Variable -Name Cred* | Select -ExpandProperty Name            
        New-DynamicParam -Name Credential -ValidateSet $Variables -Mandatory -Position 0            
    }            
    Begin            
    {            
        $Credential = Get-Variable -Name $PSBoundParameters.Credential -ValueOnly            
        $Credential.GetNetworkCredential().Password | Clip            
    }            
}

Now if I have test or other credentials that I need to use very regularly, I have a simple way to get them into my session and to extract the plaintext passwords.

Creds

You could take this a step further. In the DynamicParam block, perhaps you could get all variables that are PSCredentials, using the -is comparison operator.

Get-Variable | Where-Object {$_.Value -is [PSCredential]}            

Another method would be to create the credential objects using New-Variable, with a specific description we could filter on later.

That’s about it! Keep an eye out for other resources as well.  For example, BetterCredentials from Joel Bennett offers a more functional drop-in replacement for Get-Credential. Consider writing your own functions tailored to your needs and environment.

Cheers!

Advertisements

One thought on “Credentials and Dynamic Parameters

  1. Pingback: Dynamic parameters, ValidateSet and Enums | IT magician with a knack for automation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s