diff --git a/BetterCredentials.psd1 b/BetterCredentials.psd1 index 903b63b..1c29d94 100644 Binary files a/BetterCredentials.psd1 and b/BetterCredentials.psd1 differ diff --git a/BetterCredentials.psm1 b/BetterCredentials.psm1 index 5a3184f..e1f8931 100644 --- a/BetterCredentials.psm1 +++ b/BetterCredentials.psm1 @@ -1,3 +1,6 @@ +## Copyright (c) 2014, Joel Bennett +## Licensed under MIT license + $ScriptRoot = Get-Variable PSScriptRoot -ErrorAction SilentlyContinue | ForEach-Object { $_.Value } if(!$ScriptRoot) { $ScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent @@ -35,6 +38,9 @@ function Get-Credential { # Will prompt for credentials inline in the host instead of in a popup dialog # .Notes # History: + # v 4.3 Update module metadata and copyrights, etc. + # v 4.2 Provide -Force switch to force prompting instead of loading + # v 4.1 Modularize and Release # v 4.0 Change -Store to save credentials in the Windows Credential Manager (Vault) # v 3.0 Modularize so I can "Requires" it # v 2.9 Reformat to my new coding style... @@ -99,6 +105,11 @@ function Get-Credential { [Parameter(ParameterSetName="Delete",Mandatory=$true)] [switch]$Delete, + # Ignore stored credentials and re-prompt + # Note: when combined with -Store this overwrites stored credentials + [Alias("New")] + [switch]$Force, + # The password [Parameter(ParameterSetName="Promptless",Mandatory=$true)] $Password @@ -106,9 +117,9 @@ function Get-Credential { process { Write-Verbose ($PSBoundParameters | Out-String) [Management.Automation.PSCredential]$Credential = $null - if( $UserName -is [Management.Automation.PSCredential]) { + if( $UserName -is [System.Management.Automation.PSCredential]) { $Credential = $UserName - } elseif($UserName -ne $null) { + } elseif(!$Force -and $UserName -ne $null) { $UserName = $UserName.ToString() if($Domain) { if($Delete) { @@ -127,15 +138,15 @@ function Get-Credential { Write-Verbose "UserName: $(if($Credential){$Credential.UserName}else{$UserName})" if($Password) { - if($Password -isnot [Security.SecureString]) { + if($Password -isnot [System.Security.SecureString]) { $Password = Encode-SecureString $Password } Write-Verbose "Creating credential from inline Password" if($Domain) { - $Cred = New-Object Management.Automation.PSCredential ${Domain}\${UserName}, ${Password} + $Cred = New-Object System.Management.Automation.PSCredential ${Domain}\${UserName}, ${Password} } else { - $Cred = New-Object Management.Automation.PSCredential ${UserName}, ${Password} + $Cred = New-Object System.Management.Automation.PSCredential ${UserName}, ${Password} } if($Credential) { $Credential | Get-Member -type NoteProperty | % { @@ -163,7 +174,7 @@ function Get-Credential { } } Write-Verbose "Generating Credential with Read-Host -AsSecureString" - $Credential = New-Object Management.Automation.PSCredential $UserName,$(Read-Host "Password for user $UserName" -AsSecureString) + $Credential = New-Object System.Management.Automation.PSCredential $UserName,$(Read-Host "Password for user $UserName" -AsSecureString) } else { if($GenericCredentials) { $Type = "Generic" } else { $Type = "Domain" } @@ -175,8 +186,6 @@ function Get-Credential { } } - - if($Store) { if($Description) { Add-Member -InputObject $Credential -MemberType NoteProperty -Name Description -Value $Description @@ -186,6 +195,19 @@ function Get-Credential { Write-Error $result } } + + # Make sure it's Generic + if($GenericCredentials -and $Credential.UserName.Contains("\")) { + ${UserName} = @($Credential.UserName -Split "\\")[-1] + $Cred = New-Object System.Management.Automation.PSCredential ${UserName}, $Credential.Password + if($Credential) { + $Credential | Get-Member -type NoteProperty | % { + Add-Member -InputObject $Cred -MemberType NoteProperty -Name $_.Name -Value $Credential.($_.Name) + } + } + $Credential = $Cred + } + return $Credential } } @@ -203,9 +225,9 @@ function Decode-SecureString { ) end { if($secure -eq $null) { return "" } - $BSTR = [Runtime.InteropServices.marshal]::SecureStringToBSTR($secure) - Write-Output [Runtime.InteropServices.marshal]::PtrToStringAuto($BSTR) - [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) + $BSTR = [System.Runtime.InteropServices.marshal]::SecureStringToBSTR($secure) + Write-Output [System.Runtime.InteropServices.marshal]::PtrToStringAuto($BSTR) + [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) } } @@ -221,11 +243,12 @@ function Encode-SecureString { ) end { [char[]]$Chars = $String.ToString().ToCharArray() - $SecureString = New-Object Security.SecureString + $SecureString = New-Object System.Security.SecureString foreach($c in $chars) { $SecureString.AppendChar($c) } $SecureString.MakeReadOnly(); Write-Output $SecureString } } New-Alias gcred Get-Credential -Export-ModuleMember -Function Get-Credential -Alias gcred \ No newline at end of file +Export-ModuleMember -Function Get-Credential -Alias gcred + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a889b35 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2014, Joel Bennett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/NativeMethods.cs b/NativeMethods.cs index 12330fb..6003566 100644 --- a/NativeMethods.cs +++ b/NativeMethods.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) 2014, Joel Bennett +// Licensed under MIT license +using System; using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32.SafeHandles; diff --git a/ReadMe.md b/ReadMe.md index 82ac036..440e8de 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -20,9 +20,14 @@ Despite the fact that this feature arrived late in the life of BetterCredentials On out BetterCredentials\Get-Credential command, the `-Store` switch causes the returned credentials to be stored in the vault, and the `-Delete` switch makes sure they are not. -Once you've stored credentials in the vault, future requests for the same credential (based on the domain and username) will simply return the credentials without prompting! +Once you've stored credentials in the vault, future requests for the same credential -- where you pass in a username (and optionally, a domain) will simply return the credentials without prompting. Because of this, there is also a `-Force` switch (alias: `-New`) which prevents loading and forces the prompt to be displayed. When you need to change a stored password, use both together: + BetterCredentials\Get-Credential -Force -Store ##### NOTES -I feel like I should apoligize for the clumsyness of `Get-Credential YourName -Delete`, and maybe some day I'll write a full set of `Get`, `Set`, `Remove` commands, but for now, there's only one command in this module, so that's how it is. \ No newline at end of file +In my scripts and sample code, I nearly always use `BetterCredentials\Get-Credential` as a way to make sure that I'm invoking this overload of Get-Credential, but the idea is that you can simply import the BetterCredentials module in your profile and automatically get this overload whenever you're calling Get-Credential. Of course, I haven't (yet) overloaded the [Credential] transform attribute, so the automatic prompting when you pass a user name to a `-Credential` attribute doesn't use my module -- you have to explicitly call `Get-Credential`. + +I feel like I should apoligize for the clumsyness of `Get-Credential YourName -Delete`, and maybe some day I'll write a full set of `Get`, `Set`, `Remove` commands, but for now, there's only one command in this module, so that's how it is. + +Licensed under MIT license, see [License](LICENSE). \ No newline at end of file