<#
.Synopsis
    Import/Export Skype "salt" used to decrypt Credentials3 in config.xml

.Description
    Import/Export Skype "salt" used to decrypt Credentials3 in config.xml
    This allows you to move config.xml files between different machines.

    Salt is stored in the "HKEY_CURRENT_USER\Software\Skype*\ProtectedStorage"
    registry keys and protected with DPAPI.

    Skype 7 uses "Skype" key, while newer versions use "skypeapp-xxxxxxxxxxxx" keys.

    Export will get data from all Skype instances, which then can be imported
    into the Skype 7 registry key

.Parameter Export
    Switch. Script will export registry data to XML file.

.Parameter Import
    Switch. Script will export registry from to XML file.

.Parameter Path
    Path to XML file. Can be omited for Export.

.Example
    & .\Use-SkypeProtectedData.ps1 -Export

    Export Skype salt.

.Example
    & .\Use-SkypeProtectedData.ps1 -Import -Path .\MYPC_Skype_2019-04-10T04.05.14.9391042+03.00.xml

    Import Skype salt.
#>
[CmdletBinding(DefaultParameterSetName = 'Export')]
Param(
    [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'Export')]
    [switch]$Export,

    [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'Import')]
    [switch]$Import,

    [Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'Import')]
    [ValidateScript({
        Test-Path -LiteralPath $_ -PathType Leaf
    })]
    [ValidateNotNullOrEmpty()]
    [string]$Path
)

Add-Type -AssemblyName System.Security -ErrorAction Stop

if (-not $PSScriptRoot) {
    $PSScriptRoot = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
}

$SkypeSearchPath = 'HKEY_CURRENT_USER\Software\Skype*\ProtectedStorage'
$SkypeRegPath = 'HKEY_CURRENT_USER\Software\Skype\ProtectedStorage'

if ($PSCmdlet.ParameterSetName -eq 'Export') {

    Get-Item -Path "Registry::$SkypeSearchPath" | ForEach-Object {

        # Generate filename
        $SkypeKey = Split-Path -Path $_.PSParentPath -Leaf

        $FileName = Join-Path $PSScriptRoot (
            '{0}_{1}_{2}.xml' -f [System.Environment]::MachineName, $SkypeKey, (Get-Date -Format 'o' ).Replace(':', '.')
        )

        # Get Skype registry values
        $Protected = Get-ItemProperty -LiteralPath $_.PSPath

        # Strip PowerShell properties
        $SkypeItems = @(
            $Protected.PSObject.Properties |
            Select-Object -ExpandProperty Name
        ) -notlike 'PS*'

        # Decrypt values using DPAPI
        $SkypeItems | ForEach-Object {
            $Protected.$_ = [System.Security.Cryptography.ProtectedData]::Unprotect(
                $Protected.$_,
                $null,
                [System.Security.Cryptography.DataProtectionScope]::CurrentUser
            )
        }

        # Export unprotected object
        $Protected |
        Select-Object -Property $SkypeItems |
        Export-Clixml -Path $FileName
    }

} else {

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
        throw "File not found: $Path"
    }

    if (-not (Test-Path -Path "Registry::$SkypeRegPath")) {
        try {
            New-Item -Path "Registry::$SkypeRegPath" -Force -ErrorAction Stop > $null
        }
        catch {
            throw "Can't create registry key: $SkypeRegPath"        
        }
    }

    # Import object
    if ($Unprotected = Import-Clixml -Path $Path) {

        $Unprotected.PSObject.Properties | 
        Select-Object -ExpandProperty Name |
        ForEach-Object {

            # Encrypt values using DPAPI
            $Protected = [System.Security.Cryptography.ProtectedData]::Protect(
                $Unprotected.$_,
                $null,
                [System.Security.Cryptography.DataProtectionScope]::CurrentUser
            )

            # Set Skype registry values
            if ($Protected) {
                Set-ItemProperty -Path "Registry::$SkypeRegPath" -Name $_ -Value $Protected -Type Binary -Force
            }
        }
    }
}