Public/New-CachedCredential.ps1

function New-CachedCredential {
    <#
        .SYNOPSIS
            Store a credential in the registry-backed cache.
        .DESCRIPTION
            Stores a PSCredential in the DPAPI-encrypted registry cache. The credential can be
            retrieved later with Get-CachedCredential. The cache key is derived from the username hash.
        .PARAMETER UserName
            The username to prompt credentials for.
        .PARAMETER Credential
            A pre-built PSCredential object to cache.
        .PARAMETER RegistryRoot
            Override the registry root for this operation. Defaults to module configuration.
        .PARAMETER Message
            Message to display in the credential prompt dialog.
    #>

    [CmdletBinding(DefaultParameterSetName = 'prompt')]
    [OutputType([pscredential])]
    param(
        [Parameter(ValueFromPipeline = $true, Mandatory = $true, Position = 0, ParameterSetName = 'prompt_credential')]
        [string]$UserName,

        [Parameter(ValueFromPipeline = $true, Mandatory = $true, Position = 0, ParameterSetName = 'credential_provided')]
        [pscredential]$Credential,

        [Parameter(Mandatory = $false, Position = 1, ParameterSetName = 'prompt_credential')]
        [Parameter(Mandatory = $false, Position = 1, ParameterSetName = 'credential_provided')]
        [Parameter(Mandatory = $false, Position = 0, ParameterSetName = 'prompt')]
        [string]$RegistryRoot,

        [Parameter(Mandatory = $true, Position = 2, ParameterSetName = 'prompt_credential')]
        [string]$Message
    )
    Begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        [pscredential]$OutputCredential = [System.Management.Automation.PSCredential]::Empty
    }
    Process {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] ParameterSetName: $($PsCmdlet.ParameterSetName)"
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] PSBoundParameters: $($PSBoundParameters | Out-String)"

        switch ($PsCmdlet.ParameterSetName) {
            "prompt" {
                $InputCredential = Get-Credential
            }
            "prompt_credential" {
                $params = @{}
                if ($PSBoundParameters.ContainsKey('UserName')) { $params['UserName'] = $UserName }
                if ($PSBoundParameters.ContainsKey('Message')) { $params['Message'] = $Message }
                $InputCredential = Get-Credential @params
                if ($InputCredential.UserName -eq $PSBoundParameters.UserName -and $InputCredential.UserName -cne $PSBoundParameters.UserName) {
                    Write-Warning "Get-Credential replaced the value of `$UserName = '$($PSBoundParameters.UserName)' with '$($InputCredential.UserName)'."
                }
            }
            "credential_provided" {
                $InputCredential = $Credential
            }
        }
        if ($null -eq $InputCredential -or $InputCredential -eq [System.Management.Automation.PSCredential]::Empty) {
            throw "Invalid/Empty credentials received."
        }
        $OutputCredential = $InputCredential

        if ([string]::IsNullOrEmpty($RegistryRoot)) {
            $RegistryRoot = $script:CredentialCacheConfig.RegistryRoot
        }
        $RegistryKey = "{0}\Credential\{1}" -f $RegistryRoot, (ConvertTo-Hash $InputCredential.UserName)

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Creating Registry Key: $($RegistryKey)"
        New-Item -Path $RegistryKey -ErrorAction Stop -Force | Out-Null
        New-ItemProperty -Path $RegistryKey -PropertyType String -Name UserName -Value $InputCredential.UserName | Out-Null
        New-ItemProperty -Path $RegistryKey -PropertyType String -Name Password -Value ($InputCredential.Password | ConvertFrom-SecureString) | Out-Null
        New-ItemProperty -Path $RegistryKey -PropertyType String -Name Domain -Value $InputCredential.GetNetworkCredential().Domain | Out-Null
        New-ItemProperty -Path $RegistryKey -PropertyType String -Name DomainUserName -Value $InputCredential.GetNetworkCredential().UserName | Out-Null
        New-ItemProperty -Path $RegistryKey -PropertyType String -Name LastUpdate -Value (Get-Date -Format 'yyyyMMddHHmmss') | Out-Null
    }
    End {
        $OutputCredential
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended"
    }
}