DSCResources/xDSCVault_Unwrap/xDSCVault_Unwrap.psm1

$errorActionPreference = 'Stop'
Set-StrictMode -Version 'Latest'

Import-Module -Name (Join-Path -Path (Split-Path -Path $PSScriptRoot -Parent) `
        -ChildPath 'CommonResourceHelper.psm1')

# Localized messages for verbose and error statements in this resource
$script:localizedData = Get-LocalizedData -ResourceName 'xDSCVault_Unwrap'

function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [parameter(Mandatory = $true)]        
        [System.String]
        $WrappedToken,

        [parameter(Mandatory = $true)]        
        [System.String]
        $RoleId,

        [parameter(Mandatory = $true)]        
        [System.String]
        $VaultAddress,
   
        [System.String]
        $ApiPrefix = 'v1'
    )

    $returnValue = @{
        WrappedToken = $WrappedToken
        RoleId       = $RoleId
        VaultAddress = $VaultAddress
        ApiPrefix    = $ApiPrefix
        ApiPath      = ($VaultAddress + '/' + $ApiPrefix + '/')
    }

    $returnValue
}


function Set-TargetResource
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]        
        [System.String]
        $WrappedToken,

        [parameter(Mandatory = $true)]        
        [System.String]
        $RoleId,

        [parameter(Mandatory = $true)]        
        [System.String]
        $VaultAddress,
   
        [System.String]
        $ApiPrefix = 'v1'
    )

    $resourceData = Get-TargetResource @PSBoundParameters
    $apiUri = ($resourceData.ApiPath + 'sys/wrapping/unwrap')
    $headers = New-Object -TypeName 'System.Collections.Generic.Dictionary[[String],[String]]'
    $headers.Add('X-Vault-Token', $resourceData.WrappedToken)
    try
    {
        Write-Verbose -Message ($script:localizedData.AttemptUnwrap)
        $result = Invoke-RestMethod -Method Post -Uri $apiUri -Headers $headers -ErrorAction Stop
        Remove-StoredCredential -Target $VaultAddress -ErrorAction SilentlyContinue
        New-StoredCredential -Target $resourceData.VaultAddress -Type Generic -UserName $resourceData.RoleId -Password $($result.data.secret_id) -Persist LocalMachine -ErrorAction Stop
    }
    catch
    {
        if ($_.Exception.Response.GetResponseStream() -ne $null) 
        {
            $responseBody = Read-RESTException -Exception $_.Exception.Response.GetResponseStream()
            if ($responseBody -match 'wrapping token is not valid or does not exist' ) 
            {
                Write-Error -Message ($script:localizedData.VaultTokenLookupInvalid)
            } 
        }
        else
        {
            Write-Error -Message $_.Exception
        }
    }
}


function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [parameter(Mandatory = $true)]        
        [System.String]
        $WrappedToken,

        [parameter(Mandatory = $true)]        
        [System.String]
        $RoleId,

        [parameter(Mandatory = $true)]        
        [System.String]
        $VaultAddress,
   
        [System.String]
        $ApiPrefix = 'v1'
    )

    $resourceData = Get-TargetResource @PSBoundParameters

    try
    {
        Write-Verbose -Message ($script:localizedData.CheckingDNS -f $VaultAddress)
        $regex = $VaultAddress -match '(?<=://).+'
        $dns = Resolve-DnsName -Name $matches[0] -ErrorAction Stop
        $health = Invoke-RestMethod -Uri ($resourceData.VaultAddress + '/' + $ApiPrefix + '/sys/health') -ErrorAction Stop
    }
    catch 
    {
        if ($_.Exception -match 'DNS name does not exist' )
        {
            Write-Error -Message ($script:localizedData.VaultDnsException)
        }
        elseif ($_.Exception -match 'The operation has timed out') 
        {
            Write-Error -Message ($script:localizedData.VaultDnsTimeout)
        }
        else
        {
            Write-Error -Message $_.Exception
        }
    }

    $apiUri = ($resourceData.ApiPath + 'sys/wrapping/lookup')
    $headers = New-Object -TypeName 'System.Collections.Generic.Dictionary[[String],[String]]'
    $headers.Add('X-Vault-Token', $resourceData.WrappedToken)

    try
    {
        Write-Verbose -Message ($script:localizedData.IsVaulttokenwrapped)
        $result = Invoke-RestMethod -Method Post -Uri $apiUri -Headers $headers -ErrorAction Stop
        Write-Verbose -Message ($script:localizedData.Vaulttokenisstillwrapped)
        $apiResult = ($script:localizedData.Resultwrapped)
    }
    catch
    {
        if ($_.Exception.Response.GetResponseStream() -ne $null) 
        {
            $responseBody = Read-RESTException -Exception $_.Exception.Response.GetResponseStream()
            if ($responseBody -match 'wrapping token is not valid or does not exist' ) 
            {
                Write-Verbose -Message ($script:localizedData.VaultTokenLookupInvalid)
                $apiResult = ($script:localizedData.Resulttokenerror)
            } 
        }
        else
        {
            Write-Error -Message $_.Exception
        }     
    }
    
    if ($apiResult -ne 'tokenError' -and (Get-StoredCredential -Target $VaultAddress) -eq $null) 
    {
        Write-Verbose -Message ($script:localizedData.Notokenerrorandnocredspresent)
        return $false
    }
    elseif ($apiResult -ne 'tokenError' -and (Get-StoredCredential -Target $VaultAddress) -ne $null)
    {
        Write-Verbose -Message ($script:localizedData.Notokenerrorandcredspresent)
        return $false
    }
    elseif ($apiResult -eq 'tokenError' -and (Get-StoredCredential -Target $VaultAddress) -eq $null)
    {
        Write-Verbose -Message ($script:localizedData.Tokenerrorwithnostoredcredspresent -f $VaultAddress)  
        return $true
    }
    elseif ($apiResult -eq 'tokenError' -and (Get-StoredCredential -Target $VaultAddress) -ne $null)
    {
        Write-Verbose -Message ($script:localizedData.Tokenerrorwithstoredcredspresent -f $VaultAddress)        
        return $true
    }S
}

Export-ModuleMember -Function *-TargetResource