Public/Add-StoredCredential.ps1

function Add-StoredCredential {
    <#
    .SYNOPSIS
    Stores the given credential on the local hard drive
 
    .DESCRIPTION
    Exports the given credential object to an XML file which is saved in the TMD_Files directory
 
    .PARAMETER Name
    The name to be used when referencing the stored credential
 
    .PARAMETER Credential
    The credential object to be stored
 
    .PARAMETER EncryptionKey
    An optional key to be used to encrypt the credential using AES. The specified key must
    be either a base64 encoded string or a byte array with a size of 128, 192, or 256 bits
 
    .PARAMETER Passthru
    Returns the PSCredential object created and stored with the Name provided
 
    .EXAMPLE
    Get-Credential | Add-StoredCredential -Name 'MyCreds'
 
    .EXAMPLE
    $Key = Get-AesKey -Size 128
    Add-StoredCredential -Name 'MyEncryptedCreds' -EncryptionKey $Key
 
    .OUTPUTS
    None
    #>


    [CmdletBinding(DefaultParameterSetName = 'EncryptedWithDPAPI')]
    [Alias('New-StoredCredential')]
    param(
        [CmdletBinding()]
        [Parameter(Mandatory = $true,
            Position = 0,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true)]
        [Alias('CredentialName')]
        [String]$Name,

        [Parameter(Mandatory = $false,
            Position = 1,
            ValueFromPipelineByPropertyName = $true)]
        [PSCredential]$Credential,

        [Parameter(Mandatory = $false,
            Position = 2,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'EncryptedWithKey')]
        [Alias('Key')]
        [Object]$EncryptionKey,

        ## Allow returning the PSCredential Object (useful when prompted for new)
        [switch]$Passthru
    )

    begin {

        # Validate the encryption key provided
        if ($PSCmdlet.ParameterSetName -eq 'EncryptedWithKey') {

            # Make sure the encryption key is a string or a byte array
            if ($EncryptionKey.GetType() -notin [String], [Byte[]]) {
                throw "EncryptionKey must be either a Base64 encoded string or byte array with a size of 128, 192, or 256 bits"
            }

            # Convert the base64 string into a byte array
            if ($EncryptionKey.GetType() -eq [String]) {
                $EncryptionKey = [Convert]::FromBase64String($EncryptionKey)
            }

            # Make sure the byte array is the correct size
            if ($EncryptionKey.Count -notin 16, 24, 32) {
                throw "The encryption key must have a size of 128, 192, or 256 bits"
            }
        }
    }

    process {
        if (!$Credential) {    
            $Credential = (Get-Credential)
        }

        ## Encrypt the credential using either AES or Windows DP API and save to disk
        $CredentialFileName = $Name
        if($PSCmdlet.ParameterSetName -eq 'EncryptedWithKey'){
            $CredentialFileName += '.ecredential'
        } else {
            $CredentialFileName += '.credential'
        }
        $CredentialFilePath = Join-Path $Global:UserPaths.Credentials $CredentialFileName
        if ($PSCmdlet.ParameterSetName -eq 'EncryptedWithKey') {
            $EncryptedPassword = ConvertFrom-SecureString -SecureString $Credential.Password -Key $EncryptionKey
            $EncryptedCredential = [PSCustomObject]@{
                UserName = $Credential.UserName
                Password = $EncryptedPassword
            }
            New-Item -Path $CredentialFilePath -ItemType File -Value ($EncryptedCredential | ConvertTo-Json) -Force | Out-Null
        } else {
            Export-Clixml -InputObject $Credential -Path $CredentialFilePath
        }

        ## Return the PSCredential Object
        if ($Passthru.isPresent) {
            $Credential
        }
    }
}