Powershell

These functions will allow you to easily save a set of credentials to disk so that they can be reused during an unattended session later.  There are a few blog entries and newsgroup posts about this topic elsewhere, and Lee Holmes covers it in his “PowerShell Cookbook”, but nothing that I have seen actually helps you do the end-to-end of credential –> disk –> credential process.  Hope you find it useful!  I wrote this for my book, but as it’s of general use I thought I would share.

Update: 7/21/08 @ 11:16a

I’m changing the import conditions to work better on v1 of PowerShell.  Download link has updated code.

Update: 7/21/08 @ 7:10p

Reader Steve S. pointed out to me that if you give Export-PSCredential a username, it does not work, but he expected it to.  I agreed, so changed the logic a bit.  I like it this way, now it works just like Get-Credential does (try get-credential “username” to see what I mean).

One last thing—big props to Brandon Shell who has written on this topic as well.  In fact, I umm, er, was troubleshooting that script with him when he wrote it so I should know better.  To be fair, I—ok I have no excuse.  But I didn’t mean to steal any well-deserved thunder.  ;)  My script does store the username where his does not, although he says he’s got an updated one which does.  Even so—the more the merrier so that you can see multiple ways to solve a problem.

   1: # Author:     Hal Rottenberg <hal@halr9000.com>
   2: # Url:        http://halr9000.com/article/tag/lib-authentication.ps1
   3: # Purpose:    These functions allow one to easily save network credentials to disk in a relatively
   4: #            secure manner.  The resulting on-disk credential file can only [1] be decrypted
   5: #            by the same user account which performed the encryption.  For more details, see
   6: #            the help files for ConvertFrom-SecureString and ConvertTo-SecureString as well as
   7: #            MSDN pages about Windows Data Protection API.
   8: #            [1]: So far as I know today.  Next week I'm sure a script kiddie will break it.
   9: #
  10: # Usage:    Export-PSCredential [-Credential <PSCredential object>] [-Path <file to export>]
  11: #            Export-PSCredential [-Credential <username>] [-Path <file to export>]
  12: #            If Credential is not specififed, user is prompted by Get-Credential cmdlet.
  13: #            If a username is specified, then Get-Credential will prompt for password.
  14: #            If the Path is not specififed, it will default to "./credentials.enc.xml".
  15: #            Output: FileInfo object referring to saved credentials
  16: #
  17: #            Import-PSCredential [-Path <file to import>]
  18: #
  19: #            If not specififed, Path is "./credentials.enc.xml".
  20: #            Output: PSCredential object
  21:  
  22: function Export-PSCredential {
  23:     param ( $Credential = (Get-Credential), $Path = "credentials.enc.xml" )
  24:  
  25:     # Look at the object type of the $Credential parameter to determine how to handle it
  26:     switch ( $Credential.GetType().Name ) {
  27:         # It is a credential, so continue
  28:         PSCredential        { continue }
  29:         # It is a string, so use that as the username and prompt for the password
  30:         String                { $Credential = Get-Credential -credential $Credential }
  31:         # In all other caess, throw an error and exit
  32:         default                { Throw "You must specify a credential object to export to disk." }
  33:     }
  34:     
  35:     # Create temporary object to be serialized to disk
  36:     $export = "" | Select-Object Username, EncryptedPassword
  37:     
  38:     # Give object a type name which can be identified later
  39:     $export.PSObject.TypeNames.Insert(0,’ExportedPSCredential’)
  40:     
  41:     $export.Username = $Credential.Username
  42:  
  43:     # Encrypt SecureString password using Data Protection API
  44:     # Only the current user account can decrypt this cipher
  45:     $export.EncryptedPassword = $Credential.Password | ConvertFrom-SecureString
  46:  
  47:     # Export using the Export-Clixml cmdlet
  48:     $export | Export-Clixml $Path
  49:     Write-Host -foregroundcolor Green "Credentials saved to: " -noNewLine
  50:  
  51:     # Return FileInfo object referring to saved credentials
  52:     Get-Item $Path
  53: }
  54:  
  55: function Import-PSCredential {
  56:     param ( $Path = "credentials.enc.xml" )
  57:  
  58:     # Import credential file
  59:     $import = Import-Clixml $Path 
  60:     
  61:     # Test for valid import
  62:     if ( !$import.UserName -or !$import.EncryptedPassword ) {
  63:         Throw "Input is not a valid ExportedPSCredential object, exiting."
  64:     }
  65:     $Username = $import.Username
  66:     
  67:     # Decrypt the password and store as a SecureString object for safekeeping
  68:     $SecurePass = $import.EncryptedPassword | ConvertTo-SecureString
  69:     
  70:     # Build the new credential object
  71:     $Credential = New-Object System.Management.Automation.PSCredential $Username, $SecurePass
  72:     Write-Output $Credential
  73: }

[ download ] | [ view or revise my code on poshcode.org ]

: http://halr9000.com/article/531

2008-07-21 09:47:17

These versions work for you? The export is fine but the import doesn’t recognize the type. I don’t think the import function can validate the custom type you created.

PS C:\Scripts\PoSH> (import-clixml credentials.enc.xml).psobject.typenames
System.Management.Automation.PSCustomObject
System.Object

Or am I doing something wrong?

2008-07-21 10:13:06

You know, it works great for me in v2, but I get the same error in v1. If you look at the .xml file, does it have the typename? “ExportedPSCredential“. I bet it doesn’t.

Darn, that was pretty elegant. I guess I’ll take it out for now. Try this one: http://poshcode.org/472

(I’ll update the links above.)

2008-07-21 10:51:52

Thanks for the update. I suspected a version issue.

2008-07-21 12:22:53

[...] Rottenberg has put together a very nice set of functions for exporting and importing PSCredential to a file. The export function takes a PSCredential and serializes it to an XML file. The [...]

2008-07-25 22:47:16

[...] Hal brings us a couple of scripts for saving credentials [...]

Comments for this post will be closed on 18 October 2008.