credlib.ps1 Powershell library for credentials
My powershell library for some heavily-used credential tasks.
# Filename: \\rdputil1\scripts\Functions\credlib.ps1
# License: CC-BY-SA 4.0
# Author: bgstack15
# Startdate: 2019-12-31 15:53
# Title: Shared Credentials library
# Purpose: Provide some reusable credential functions
# History:
# Usage:
# Reference:
# https://foxdeploy.com/2017/01/13/adding-tab-completion-to-your-powershell-functions/
# original implementation of storing crypted passwords \\rdputil1\e$\modules\EncryptModule\PassEncryptModule.psm1
# Improve:
# Dependencies:
# \\rdputil1\e$\scripts\Functions\loglib.ps1
#. \\rdputil1\scripts\Functions\loglib.ps1
${global:SecurePath} = "\\rdputil1\e$\test"
Function Set-Master-Encryption-Key {
Param(
[Parameter(Mandatory=$true)][string]$String
)
$bytes = [System.Text.Encoding]::UTF8.GetBytes($String)
If ($bytes.Length -ne 24) {
Throw "String must be 24 characters long."
}
$bytes | Out-File "${global:SecurePath}\keys\EncryptionMaster.key"
}
Function Set-Shared-Password {
Param(
[Parameter(Mandatory=$true)][string]$Password,
[Parameter(Mandatory=$true)][string]$PasswordCategory
)
$encryptedFile = "${global:SecurePath}\EncryptedData\$($PasswordCategory)"
$key = Get-Content "${global:SecurePath}\keys\EncryptionMaster.key"
$Password | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString -key $key | Out-File $encryptedFile
}
Function Get-Shared-Password {
[CmdletBinding()]
Param () # necessary to prevent error
DynamicParam {
$ParameterName = 'PasswordCategory'
$RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
$ParameterAttribute.Mandatory = $true
#$ParameterAttribute.Position = 1 # unneccessary, but a good example
$AttributeCollection.Add($ParameterAttribute)
$arrSet = ( Get-ChildItem "$(${global:SecurePath})\EncryptedData" ).name
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
$AttributeCollection.Add($ValidateSetAttribute)
$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
$RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
return $RuntimeParameterDictionary
}
Begin { $PasswordCategory = $PsBoundParameters[$ParameterName] } # actual variable population based on input
Process {
$key = Get-Content "$(${global:SecurePath})\keys\EncryptionMaster.key"
$passFile = Get-content (Get-ChildItem -Path "$(${global:SecurePath})\EncryptedData\$($PasswordCategory)") | ConvertTo-SecureString -Key $key
if ($passFile) {
return [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($passFile))
} else {
return "ERROR: Unable to decrypt data"
}
}
}
# Get-Shared-Credential -User "serviceaccount@${global:domain}" -PasswordCategory "O365"
# this one wraps around the Get-Shared-Password
Function Get-Shared-Credential {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)][string] $User
)
DynamicParam {
$ParameterName = 'PasswordCategory'
$RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
$ParameterAttribute.Mandatory = $true
#$ParameterAttribute.Position = 1 # unneccessary, but a good example
$AttributeCollection.Add($ParameterAttribute)
$arrSet = ( Get-ChildItem "$(${global:SecurePath})\EncryptedData" ).name
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
$AttributeCollection.Add($ValidateSetAttribute)
$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
$RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
return $RuntimeParameterDictionary
}
Begin { $PasswordCategory = $PsBoundParameters[$ParameterName] } # actual variable population based on input
Process {
$password = Get-Shared-Password -PasswordCategory $PasswordCategory | ConvertTo-SecureString -AsPlainText -Force
if ($pass -contains "ERROR") {
If ("${global:today}" -ne "") {
# if loglib has been loaded
Log "ERROR: Unable to decrypt password";
Log "ERROR: Exiting Script";
EXIT
} Else {
Throw "Unable to decrypt password. Exiting script."
}
}
$credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $user, $password
Return $credential
}
}
Function Set-Shared-Credential {
Param (
[Parameter(Mandatory=$true)][string] $Password,
[Parameter(Mandatory=$true)][string] $PasswordCategory
)
Set-Shared-Password -Password $Password -PasswordCategory $PasswordCategory
}
# Get-Basic-Base64-Auth-String returns "Basic 28931725917259725" which is the
Function Get-Basic-Base64-Auth-String {
Param (
[Parameter(Mandatory=$true)] [System.Management.Automation.PSCredential] $Credential,
[bool] $NoBasic = $false
)
$userauth = [System.Text.Encoding]::UTF8.GetBytes("$($Credential.Username):$( Get-Password-Insecurely -Credential $Credential )")
$return = [System.Convert]::ToBase64String($userauth)
if (!$NoBasic) { $return = "Basic $return" }
Return "$return"
}
# Get-Password-Insecurely -Credential $Credential
# returns the password from it. Obviously this is insecure as yogurt.
Function Get-Password-Insecurely {
Param (
[Parameter(Mandatory=$true)] [System.Management.Automation.PSCredential] $Credential
)
Return [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password))
}
# Get-Basic-Base64-Auth-Headers -Credential $Credential
# returns a hashtable with {"Authorization" = "Basic q192419284391724"}
Function Get-Basic-Base64-Auth-Headers {
Param (
[Parameter(Mandatory=$true)] [System.Management.Automation.PSCredential] $Credential
)
Return @{Authorization = $(Get-Basic-Base64-Auth-String -Credential $Credential) }
}
function Test-Cred {
# Ripped straight from https://www.powershellbros.com/test-credentials-using-powershell-function/
[CmdletBinding()]
[OutputType([String])]
Param (
[Parameter(
Mandatory = $false,
ValueFromPipeLine = $true,
ValueFromPipelineByPropertyName = $true
)][Alias('PSCredential')][ValidateNotNull()][System.Management.Automation.PSCredential][System.Management.Automation.Credential()]$Credentials
)
$Domain = $null
$Root = $null
$Username = $null
$Password = $null
If($Credentials -eq $null) {
Try { $Credentials = Get-Credential "domain\$env:username" -ErrorAction Stop ; }
Catch {
$ErrorMsg = $_.Exception.Message
Write-Warning "Failed to validate credentials: $ErrorMsg "
Pause
Break
}
}
# Checking module
Try {
# Split username and password
$Username = $credentials.username
$Password = $credentials.GetNetworkCredential().password
# Get Domain
$Root = "LDAP://" + ([ADSI]'').distinguishedName
$Domain = New-Object System.DirectoryServices.DirectoryEntry($Root,$UserName,$Password)
}
Catch { $_.Exception.Message ; Continue ; }
If(!$domain) { Write-Warning "Something went wrong" }
Else {
If ($domain.name -ne $null)
{ return "Authenticated" }
Else { return "Not authenticated" }
}
}
The "Shared" functions depend on a master encryption key. You really only need the Set-Master-Encryption key once. From then on, you use Get/Set-Shared- Password, and Get/Set-Shared-Credential. The Set-Shared-Password stores an encrypted string that is retrievable with the master encryption key. The Get- Shared-Credential builds a PSCredential object. Some of these functions contain the DynamicParam components necessary for autocompletion. This is a nice feature for when you have a large amount of credentials stored and you want to see what's available. Lots of functions depend on Get-Basic- Base64-Auth-Headers, which returns a hashtable of "Authorization: Basic 129834712743192742" needed for many http calls. The Test-Cred function is ripped off straight from Test credentials using PowerShell function - Powershellbros.com and coincidentally shows a much more convenient way to take a password out of a PSCredential object! Many of my other Powershell libraries depend on credlib, including: Powershell library for Bitbucket Cloud and Server
Comments