DSCResources/xDSCVault_Write/xDSCVault_Write.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_Write'
function Get-TargetResource
{
  [CmdletBinding()]
  [OutputType([System.Collections.Hashtable])]
  param
  (
    [parameter(Mandatory = $true)]
    [System.String]
    $VaultAddress,

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

    [System.String]
    $VaultValue,

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

    [parameter(Mandatory = $true)]
    [System.Boolean]
    $ForceUpdate,

    [System.String]
    $AuthBackend = 'approle'
  )

  Write-Verbose -Message ($script:localizedData.ObtainClientToken)
  $clientToken = Start-VaultAuth -VaultAddress $VaultAddress -ApiPrefix $ApiPrefix -AuthBackend $AuthBackend

  $currentVaultValue = Read-VaultData -VaultAddress $VaultAddress -ClientToken $clientToken.auth.client_token -VaultPath $VaultPath -ApiPrefix $ApiPrefix
  
  if ($clientToken.auth.client_token -ne $null) 
  {
    $clientTokenResult = ConvertTo-SecureString -String $clientToken.auth.client_token -AsPlainText -Force
  }
  else 
  {
    $clientTokenResult = 'Error obtaining client token'
  }
  
  if ($currentVaultValue -ne 404) 
  {
    $currentVaultValueOutput = ConvertTo-SecureString -String $currentVaultValue -AsPlainText -Force
  }
  else 
  {
    $currentVaultValueOutput = 'No value retrieved'
  }
  
  if ($currentVaultValue -eq 404) 
  {
    $readResult = $currentVaultValue
  }
  else 
  {
    $readResult = 200
  }

  $returnValue = @{
    VaultAddress      = $VaultAddress
    VaultPath         = $VaultPath
    VaultValue        = $VaultValue
    ApiPath           = ($VaultAddress + '/' + $ApiPrefix + '/' + $VaultPath)
    ClientToken       = $clientTokenResult
    CurrentVaultValue = $currentVaultValueOutput
    ReadResultStatus  = $readResult
    RandomSecret      = $RandomSecret
    ForceUpdate       = $ForceUpdate
    AuthBackend       = $AuthBackend
  }

  $returnValue
}


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

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

    [System.String]
    $VaultValue,

    [System.String]
    $ApiPrefix = 'v1',

    [parameter(Mandatory = $true)]
    [System.Boolean]
    $RandomSecret,

    [parameter(Mandatory = $true)]
    [System.Boolean]
    $ForceUpdate,

    [System.String]
    $AuthBackend = 'approle'
  )

  $resourceData = Get-TargetResource @PSBoundParameters

  if ($resourceData.CurrentVaultValue.GetType().Name -eq 'SecureString')
  {
    Write-Verbose -Message ($script:localizedData.DecryptingCurrentValueSecureString)
    $resourceData.CurrentVaultValue = [System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($resourceData.CurrentVaultValue)) 
  }
  else
  {
    Write-Verbose -Message ($script:localizedData.NoCurrentValueRetrieved -f $VaultPath)
    $resourceData.CurrentVaultValue = $null
  }

  if ($resourceData.ClientToken.GetType().Name -eq 'SecureString')
  {
    Write-Verbose -Message ($script:localizedData.DecryptingClientTokenSecureString)
    $clientToken = [System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($resourceData.ClientToken)) 
  }
  else
  {
    Write-Error -Message ($script:localizedData.ClientTokenMissing)
  }

    
  if ([string]::IsNullOrEmpty($resourceData.VaultValue) -eq $true -and $resourceData.RandomSecret -eq $true) 
  {
    Write-Verbose -Message ($script:localizedData.ValueEmptywithRandomSecretTrue)
    if ([string]::IsNullOrEmpty($resourceData.CurrentVaultValue) -ne $true -and $resourceData.RandomSecret -eq $true -and $resourceData.ForceUpdate -eq $false) 
    {
      Write-Verbose -Message ($script:localizedData.ValueEmptywithRandomSecretTrueNoForce)
    }
    elseif ([string]::IsNullOrEmpty($resourceData.CurrentVaultValue) -ne $true -and $resourceData.RandomSecret -eq $true -and $resourceData.ForceUpdate -eq $true) 
    {
      Write-Verbose -Message ($script:localizedData.ValueEmptywithRandomSecretTrueWithForce)
      Write-VaultData -VaultAddress $resourceData.VaultAddress -VaultPath $resourceData.VaultPath -Value (Get-StrongPassword -Length 20 -NumberOfSpecialCharacters 2) -ClientToken $clientToken -Verbose
    }
    if ([string]::IsNullOrEmpty($resourceData.CurrentVaultValue) -eq $true -and $resourceData.RandomSecret -eq $true -and $resourceData.ForceUpdate -eq $false) 
    {
      Write-Verbose -Message ($script:localizedData.AllValuesEmptywithRandomSecretTrueNoForce)
      Write-VaultData -VaultAddress $resourceData.VaultAddress -VaultPath $resourceData.VaultPath -Value (Get-StrongPassword -Length 20 -NumberOfSpecialCharacters 2) -ClientToken $clientToken -Verbose
    }
  }
  elseif ([string]::IsNullOrEmpty($resourceData.VaultValue) -eq $false -and $resourceData.RandomSecret -eq $true) 
  {
    Write-Error -Message ($script:localizedData.VaultValueTruewithRandomSecretTrue)
  }
  elseif ([string]::IsNullOrEmpty($resourceData.VaultValue) -eq $true -and $resourceData.RandomSecret -eq $false) 
  {
    Write-Error -Message ($script:localizedData.VaultValueFalsewithRandomSecretFalse)
  }
  elseif ([string]::IsNullOrEmpty($resourceData.VaultValue) -eq $false -and $resourceData.RandomSecret -eq $false) 
  {
    Write-Verbose -Message ($script:localizedData.VaultValueTruewithRandomSecretFalse)
    if ($resourceData.VaultValue -eq $resourceData.CurrentVaultValue) 
    {
      Write-Verbose -Message ($script:localizedData.VaultValueMatchesSupplied -f $VaultPath)
    }
    elseif ($resourceData.VaultValue -ne $resourceData.CurrentVaultValue) 
    {
      Write-Verbose -Message ($script:localizedData.VaultValueDoesNotMatchSupplied -f $VaultPath)
      Write-VaultData -VaultAddress $resourceData.VaultAddress -VaultPath $resourceData.VaultPath -Value $resourceData.VaultValue -ClientToken $clientToken -Verbose
    }
  }
  else 
  {
    Write-Verbose -Message ($script:localizedData.UnknownError)
    return $false  
  }
}


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

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

    [System.String]
    $VaultValue = [string]::Empty,

    [System.String]
    $ApiPrefix = 'v1',

    [parameter(Mandatory = $true)]
    [System.Boolean]
    $RandomSecret,

    [parameter(Mandatory = $true)]
    [System.Boolean]
    $ForceUpdate,

    [System.String]
    $AuthBackend = 'approle'
  )

  $resourceData = Get-TargetResource @PSBoundParameters

  if ($resourceData.CurrentVaultValue.GetType().Name -eq 'SecureString')
  {
    Write-Verbose -Message ($script:localizedData.DecryptingCurrentValueSecureString)
    $resourceData.CurrentVaultValue = [System.Runtime.InteropServices.marshal]::PtrToStringAuto([System.Runtime.InteropServices.marshal]::SecureStringToBSTR($resourceData.CurrentVaultValue)) 
  }
  else
  {
    Write-Verbose -Message ($script:localizedData.NoCurrentValueRetrieved -f $VaultPath)
    $resourceData.CurrentVaultValue = $null
  }
   
  if ($resourceData.ReadResultStatus -eq 404) 
  {
    Write-Verbose -Message ($script:localizedData.Returned404 -f $VaultPath)
    return $false
  }
    
  if ([string]::IsNullOrEmpty($resourceData.VaultValue) -eq $true -and $resourceData.RandomSecret -eq $true) 
  {
    Write-Verbose -Message ($script:localizedData.ValueEmptywithRandomSecretTrue)
    if ([string]::IsNullOrEmpty($resourceData.CurrentVaultValue) -ne $true -and $resourceData.RandomSecret -eq $true -and $resourceData.ForceUpdate -eq $false) 
    {
      Write-Verbose -Message ($script:localizedData.ValueEmptywithRandomSecretTrueNoForce)
      return $true
    }
    elseif ([string]::IsNullOrEmpty($resourceData.CurrentVaultValue) -ne $true -and $resourceData.RandomSecret -eq $true -and $resourceData.ForceUpdate -eq $true) 
    {
      Write-Verbose -Message ($script:localizedData.ValueEmptywithRandomSecretTrueWithForce)
      return $false
    }
    if ([string]::IsNullOrEmpty($resourceData.CurrentVaultValue) -eq $true -and $resourceData.RandomSecret -eq $true -and $resourceData.ForceUpdate -eq $false) 
    {
      Write-Verbose -Message ($script:localizedData.AllValuesEmptywithRandomSecretTrueNoForce)
      return $true
    }
  }
  elseif ([string]::IsNullOrEmpty($resourceData.VaultValue) -eq $false -and $resourceData.RandomSecret -eq $true) 
  {
    Write-Error -Message ($script:localizedData.VaultValueTruewithRandomSecretTrue)
  }
  elseif ([string]::IsNullOrEmpty($resourceData.VaultValue) -eq $true -and $resourceData.RandomSecret -eq $false) 
  {
    Write-Error -Message ($script:localizedData.VaultValueFalsewithRandomSecretFalse)
  }
  elseif ([string]::IsNullOrEmpty($resourceData.VaultValue) -eq $false -and $resourceData.RandomSecret -eq $false) 
  {
    Write-Verbose -Message ($script:localizedData.VaultValueTruewithRandomSecretFalse)

    if ($resourceData.VaultValue -eq $resourceData.CurrentVaultValue) 
    {
      Write-Verbose -Message ($script:localizedData.VaultValueMatchesSupplied -f $VaultPath)
      return $true        
    }
    elseif ($resourceData.VaultValue -ne $resourceData.CurrentVaultValue) 
    {
      Write-Verbose -Message ($script:localizedData.VaultValueDoesNotMatchSupplied -f $VaultPath)
      return $false
    }
  }
  else 
  {
    Write-Verbose -Message ($script:localizedData.UnknownError)
    return $false  
  }
}


Export-ModuleMember -Function *-TargetResource