Store/Update-CredentialStore.ps1

function Update-CredentialStore {
    <#
    .SYNOPSIS
        A brief description of the function or script.
 
    .DESCRIPTION
        Describe the function of the script using a single sentence or more.
 
    .PARAMETER One
        Description of the Parameter (what it does)
 
    .INPUTS
        Describe the script input parameters (if any), otherwise it may also list the word "[None]".
 
    .OUTPUTS
        Describe the script output parameters (if any), otherwise it may also list the word "[None]".
 
    .EXAMPLE
        .\Remove-Some-Script.ps1 -One content
 
    .NOTES
        File Name : Update-CredentialStore.ps1
        Author : Marco Blessing - marco.blessing@googlemail.com
        Requires :
 
    .LINK
        https://github.com/OCram85/PSCredentialStore
    #>

    [CmdletBinding()]
    [OutputType()]
    param(
        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Version]$From = '1.2.0',

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [Version]$To = '2.0.0',

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$Path,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$PfxCertificate

    )
    begin {
    }
    process {
        if (Test-Path -Path $Path) {
            $CSOld = Get-CredentialStore -Shared -Path $Path -ErrorAction Stop
            if ($CSOld.Version -ne $From) {
                $ErrorParams = @{
                    Message     = 'Can not migrate CredentialStore from version {0} to {1}' -f $From, $To
                    ErrorAction = 'Stop'
                    Exception   = [System.Exception]::new()
                }
                Write-Error @ErrorParams
            }

            $CSNew = [PSCustomObject]@{
                PSTypeName     = 'PSCredentialStore.Store'
                Version        = $To
                Created        = $CurrentDate
                PfxCertificate = $null
                Thumbprint     = $null
                Type           = $null
            }

            if ($PWD -eq (Get-DefaultCredentialStorePath)) {
                $CSNew.Type = 'Private'
            }
            elseif ($PWD -eq (Get-DefaultCredentialStorePath -Shared)) {
                $CSNew.Type = 'Shared'
            }
            else {
                $ErrorParams = @{
                    Message     = 'Can not determine a valid CredentialStore Type!'
                    ErrorAction = 'Stop'
                    Exception   = [System.Exception]::new()
                }
                Write-Error @ErrorParams
            }
            $Cert = Get-PfxCertificate -FilePath $PfxCertificate -ErrorAction Stop

            $CSNew.PfxCertificate = Join-Path -Path $PfxCertificate
            $CSNew.Thumbprint = $Cert.Thumbprint


            $CredentialItems = $CSOld | Get-Member -MemberType NoteProperty | Where-Object {
                $_.Definition -like "*.PSCustomObject*"
            } | Select-Object -ExpandProperty Name

            # iterate through all existing items
            foreach ($Item in $CredentialItems) {

                $CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S"
                $RSAKey = Get-RandomAESKey

                $CredentialObj = [PSCustomObject]@{
                    User         = $Item.UserName
                    Password     = $null
                    Created      = $CurrentDate
                    LastChange   = $null
                    EncryptedKey = [Convert]::ToBase64String(
                        $Cert.PublicKey.Key.Encrypt(
                            $RSAKey,
                            [System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1
                        )
                    )
                }
                if ($CSOld.Type -eq 'Private') {
                    $CredentialObject.Password = ConvertTo-SecureString -SecureString $Item.Password | ConvertFrom-SecureString -Key $RSAKey
                }
                elseif ($CSNew.Type -eq 'Shared') {
                    $ChallengeKey = [io.file]::ReadAllBytes((Join-Path -Path $PWD -ChildPath '/Challenge.bin'))
                    $CredentialObject.Password = ConvertTo-SecureString -SecureString $Item.Password -Key $ChallengeKey | ConvertFrom-SecureString -Key $RSAKey
                }
                Add-Member -InputObject $CSNew -Name (
                    ($Item | Get-Variable).Name
                ) -MemberType NoteProperty -Value $CredentialObj
            }
            $CSNew | ConvertTo-Json -Depth 5 | Out-File -LiteralPath (
                Join-Path -Path $PWD -ChildPath './CredentialStore.json'
            ) -Encoding utf8 -Confirm:$true
        }
        else {
            $ErrorParams = @{
                Message     = 'Could not find the given CredentialStore path!'
                ErrorAction = 'Stop'
                Exception   = [System.IO.FileNotFoundException]::new()
            }
            Write-Error @ErrorParams
        }
    }
    end {
    }
}