IntelliTect.CredentialManager.psm1
Set-StrictMode -Version "Latest" function Set-CredentialManagerCredential { <# .SYNOPSIS Sets a PowerShell Credential (PSCredential) from the Windows Credential Manager .DESCRIPTION Adapted from: http://social.technet.microsoft.com/Forums/scriptcenter/en-US/e91769eb-dbce-4e77-8b61-d3e55690b511/addedit-saved-password-in-credential-manager-windows-7?forum=ITCG .PARAMETER TargetName The name of the target login informations in the Windows Credential Manager .PARAMETER $Credential The credentials to be stored in Windows Credential Manager .EXAMPLE .\Set-Credential TargetName (Get-Credential) .LINK Get-Credential #> [CmdletBinding(SupportsShouldProcess,DefaultParametersetName="SplitCredentialValues")] param( [Parameter(Mandatory=$true, Position=0)] [string]$TargetName ,[Parameter(ParameterSetName="PSCredentialObject", Position=1)] [PSCredential]$credential = $null # Removed Get-Credential default value because otherwise you get prompted even when using the SplitCredentialValues parameter set. ,[Parameter(ParameterSetName="SplitCredentialValues", Mandatory=$true, Position=1)] [string]$userName ) if (-not (Get-IsWindowsPlatform)){ throw "This cmdlet is not supported on non-Windows operating systems." } switch ($PsCmdlet.ParameterSetName) { "PSCredentialObject" { if($credential -eq $null) { $credential = Get-Credential; } break; } "SplitCredentialValues" { $password = (Read-Host -AsSecureString -Prompt "Enter the password") $credential=new-object -typename System.Management.Automation.PSCredential $userName,$password; break; } } $output = $null; if($PSCmdlet.ShouldProcess("Storing credential within ManagerCredential name '$TargetName.'")) { $output = cmdkey /generic:$TargetName /user:$($credential.UserName) /pass:$($credential.GetNetworkCredential().password) } $output = $output | Where-Object{ -not [string]::IsNullOrWhiteSpace($_) } if("$output".Trim() -notlike "*successfully*") { throw $output; } Return; #TODO: Switch to native PowerShell $sig = @" [DllImport("Advapi32.dll", SetLastError=true, EntryPoint="CredWriteW", CharSet=CharSet.Unicode)] public static extern bool CredWrite([In] ref Credential userCredential, [In] UInt32 flags); [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] public struct Credential { public UInt32 flags; public UInt32 type; public IntPtr targetName; public IntPtr comment; public System.Runtime.InteropServices.ComTypes.FILETIME lastWritten; public UInt32 credentialBlobSize; public IntPtr credentialBlob; public UInt32 persist; public UInt32 attributeCount; public IntPtr Attributes; public IntPtr targetAlias; public IntPtr userName; } "@ Add-Type -MemberDefinition $sig -Namespace "ADVAPI32" -Name 'Util' $cred = New-Object ADVAPI32.Util+Credential $cred.flags = 0 $cred.type = 2 $cred.targetName = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni('server2') $cred.userName = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni('home\tome') $cred.attributeCount = 0 $cred.persist = 2 $password = "password" $cred.credentialBlobSize = [System.Text.Encoding]::Unicode.GetBytes($password).length $cred.credentialBlob = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni($password) [ADVAPI32.Util]::CredWrite([ref]$cred,0) } function Get-CredentialManagerCredential { <# .SYNOPSIS Gets a PowerShell Credential (PSCredential) from the Windows Credential Manager .DESCRIPTION Adapted from: http://stackoverflow.com/questions/7162604/get-cached-credentials-in-powershell-from-windows-7-credential-manager .PARAMETER TargetName The name of the target login informations in the Windows Credential Manager .EXAMPLE .\Get-CredentialFromWindowsCredentialManager.ps1 tfs.codeplex.com UserName Password -------- -------- codeplexuser System.Security.SecureString .LINK Get-Credential #> # We have to supress this warning because we are taking the # credential directly from native code - we have no choice but to use ConvertTo-SecureString [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [CmdletBinding()] param([Parameter(Mandatory=$true)][string]$TargetName) if (-not (Get-IsWindowsPlatform)) { throw "This cmdlet is not supported on non-Windows operating systems." } $sig = @" [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct NativeCredential { public UInt32 Flags; public CRED_TYPE Type; public IntPtr TargetName; public IntPtr Comment; public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten; public UInt32 CredentialBlobSize; public IntPtr CredentialBlob; public UInt32 Persist; public UInt32 AttributeCount; public IntPtr Attributes; public IntPtr TargetAlias; public IntPtr UserName; internal static NativeCredential GetNativeCredential(Credential cred) { NativeCredential ncred = new NativeCredential(); ncred.AttributeCount = 0; ncred.Attributes = IntPtr.Zero; ncred.Comment = IntPtr.Zero; ncred.TargetAlias = IntPtr.Zero; ncred.Type = CRED_TYPE.GENERIC; ncred.Persist = (UInt32)1; ncred.CredentialBlobSize = (UInt32)cred.CredentialBlobSize; ncred.TargetName = Marshal.StringToCoTaskMemUni(cred.TargetName); ncred.CredentialBlob = Marshal.StringToCoTaskMemUni(cred.CredentialBlob); ncred.UserName = Marshal.StringToCoTaskMemUni(System.Environment.UserName); return ncred; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct Credential { public UInt32 Flags; public CRED_TYPE Type; public string TargetName; public string Comment; public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten; public UInt32 CredentialBlobSize; public string CredentialBlob; public UInt32 Persist; public UInt32 AttributeCount; public IntPtr Attributes; public string TargetAlias; public string UserName; } public enum CRED_TYPE : uint { GENERIC = 1, DOMAIN_PASSWORD = 2, DOMAIN_CERTIFICATE = 3, DOMAIN_VISIBLE_PASSWORD = 4, GENERIC_CERTIFICATE = 5, DOMAIN_EXTENDED = 6, MAXIMUM = 7, // Maximum supported cred type MAXIMUM_EX = (MAXIMUM + 1000), // Allow new applications to run on old OSes } public class CriticalCredentialHandle : Microsoft.Win32.SafeHandles.CriticalHandleZeroOrMinusOneIsInvalid { public CriticalCredentialHandle(IntPtr preexistingHandle) { SetHandle(preexistingHandle); } public Credential GetCredential() { if (!IsInvalid) { NativeCredential ncred = (NativeCredential)Marshal.PtrToStructure(handle, typeof(NativeCredential)); Credential cred = new Credential(); cred.CredentialBlobSize = ncred.CredentialBlobSize; cred.CredentialBlob = Marshal.PtrToStringUni(ncred.CredentialBlob, (int)ncred.CredentialBlobSize / 2); cred.UserName = Marshal.PtrToStringUni(ncred.UserName); cred.TargetName = Marshal.PtrToStringUni(ncred.TargetName); cred.TargetAlias = Marshal.PtrToStringUni(ncred.TargetAlias); cred.Type = ncred.Type; cred.Flags = ncred.Flags; cred.Persist = ncred.Persist; return cred; } else { throw new InvalidOperationException("Invalid CriticalHandle!"); } } override protected bool ReleaseHandle() { if (!IsInvalid) { CredFree(handle); SetHandleAsInvalid(); return true; } return false; } } [DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool CredRead(string target, CRED_TYPE type, int reservedFlag, out IntPtr CredentialPtr); [DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)] public static extern bool CredFree([In] IntPtr cred); "@ Add-Type -MemberDefinition $sig -Namespace "ADVAPI32" -Name 'Util' $nCredPtr= New-Object IntPtr $success = [ADVAPI32.Util]::CredRead($TargetName,1,0,[ref] $nCredPtr) if ($success) { $critCred = New-Object ADVAPI32.Util+CriticalCredentialHandle $nCredPtr $cred = $critCred.GetCredential() $username = $cred.UserName $securePassword = $cred.CredentialBlob | ConvertTo-SecureString -AsPlainText -Force $cred.CredentialBlob = "" $cred = $null return new-object System.Management.Automation.PSCredential $username, $securePassword } else { #TODO: Determine if it is better to Error or return $null? Write-Error "No credentials were found in Windows Credential Manager for TargetName: $TargetName" } } function Remove-CredentialManagerCredential { <# .SYNOPSIS Removes a PowerShell Credential (PSCredential) from the Windows Credential Manager .DESCRIPTION Adapted from: http://stackoverflow.com/questions/7162604/get-cached-credentials-in-powershell-from-windows-7-credential-manager .PARAMETER TargetName The name of the target login informations in the Windows Credential Manager .EXAMPLE Remove-CredentialFromWindowsCredentialManager gmail.com UserName Password -------- -------- Inigo.Montoya@gmail.com System.Security.SecureString .LINK Set-Credential Get-Credential #> [CmdletBinding(SupportsShouldProcess)] param([Parameter(Mandatory)][string]$TargetName) Invoke-ShouldProcess -ContinueMessage "Removing credential from Credential Manager named ''$TargetName'" ` -InquireMessage "Remove credential from Credential Manager named '$TargetName'?" ` -Caption 'Remove credential from Credential Manager' { cmdkey /delete:$TargetName } } Function Get-CredentialPassword { [CmdletBinding()] param( [Parameter(Mandatory)][PSCredential]$credential ) return $credential.GetNetworkCredential().password } |