wks_automationHelper.psm1

<#
 
Versions:
    1.1.0 Adding support for System Managed Identities
 
#>


function get-ahCurrentAutomationInfo {
    [cmdletbinding()]
    param(
        [Parameter(Mandatory=$true)]
        [Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core.IAzureContextContainer]$azContext
    )

    
    $automationAccounts = @(Get-AzAutomationAccount -DefaultProfile $azContext)
    write-verbose "$($automationAccounts.count) AutomationAccounts found"
    write-verbose "$($automationAccounts |ConvertTo-Json -Depth 5)"
    $found = $false
    foreach ($Automation in $automationAccounts)
    {
        $AutomationInformation = @{}
        $AutomationInformation.Add("Location",$Automation.Location)
        $AutomationInformation.Add("ResourceGroupName",$Automation.ResourceGroupName)
        $AutomationInformation.Add("AutomationAccountName",$Automation.AutomationAccountName)
        $AutomationInformation.Add("SubscriptionId",$Automation.SubscriptionID)
        if($PSPrivateMetadata.JobId) {
            $Job = Get-AzAutomationJob -ResourceGroupName $Automation.ResourceGroupName `
                -AutomationAccountName $Automation.AutomationAccountName -Id $PSPrivateMetadata.JobId.Guid `
                -ErrorAction SilentlyContinue -DefaultProfile $azContext
            if (!([string]::IsNullOrEmpty($Job)))
            {
                if ($PSPrivateMetadata.JobId -eq $Job.JobId.Guid) {
                    $AutomationInformation = @{}
                    $AutomationInformation.Add("Location",$Automation.Location)
                    $AutomationInformation.Add("ResourceGroupName",$Automation.ResourceGroupName)
                    $AutomationInformation.Add("AutomationAccountName",$Automation.AutomationAccountName)
                    $AutomationInformation.Add("RunbookName",$Job.RunbookName)
                    $AutomationInformation.Add("JobId",$Job.JobId.Guid)
                    $AutomationInformation.Add("SubscriptionId",$Automation.SubscriptionID)
                    $AutomationInformation
                    $found = $true
                    break;
                }
            }
        } else {
            $AutomationInformation
            $found = $true
            break;
        }

    }
    if ($found -ne $true) { throw [Exception] "Automation Account information not found" }
}

function import-ahVariables {
    [cmdletbinding(DefaultParameterSetName = 'withAzureAutomationVariables')]
    param(
        [Parameter(Mandatory=$true, ParameterSetName='withProvidedVariables')]
        [Parameter(Mandatory=$true, ParameterSetName='withAzureAutomationVariables')]
        [object[]]$variableSets,
        [Parameter(Mandatory=$true, ParameterSetName='withProvidedVariables')]
        [PSCustomObject]$variables,
        [Parameter(Mandatory=$false, ParameterSetName='withProvidedVariables')]
        [Parameter(Mandatory=$false, ParameterSetName='withAzureAutomationVariables')]
        [ValidateSet('global','local','script')]
        [string]$scope='script',
        [Parameter(Mandatory=$true, ParameterSetName='withAzureAutomationVariables')]
        [Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core.IAzureContextContainer]$azContext
    )

    Write-Verbose "Calling cmd-let 'load-ahVariables' with parameterSet '$($PSCmdlet.ParameterSetName)'"

    if ($PSCmdlet.ParameterSetName -eq 'withAzureAutomationVariables') {
            write-verbose 'Running in Azure Automation'
            # Finding VariableSet matching with provided config file content
            $vset = $null

            $aaInfo = get-ahCurrentAutomationInfo -azContext $azContext -verbose:$VerbosePreference
            
            foreach ($vs in $variableSets) {
                Write-verbose "Testing variableSet $($vs.name)"
                $matchingVSet = $true
                foreach ($var in $vs.variableSet) {
                    try {
                        (Get-AzAutomationVariable -Name $($var.name) -ResourceGroupName $aaInfo.ResourceGroupName -AutomationAccountName $aaInfo.AutomationAccountName -DefaultProfile $azContext) |out-null
                        Write-verbose "- Validated attribute $($var.id) = $($var.name)"
                        
                    } catch {
                        $matchingVSet = $false
                        Write-Verbose "- Missing variable in Automation Accunt : $($var.name)"
                        Write-verbose $_.exception.message
                    }
                }
                if ($matchingVSet) { $vset = $vs; break }
                
            }
            if ($null -eq $vset) { 
                throw [System.ArgumentException]::new("No variableSet matching the attributes provided")
            }
            Write-Verbose "Using variableSet '$($vset.name)'"
            # Load Variables according to detected variableSet
            foreach ($var in $vset.variableSet) {
                try {
                    new-variable -name $var.id -value ((Get-AzAutomationVariable -Name $($var.name) -ResourceGroupName $aaInfo.ResourceGroupName -AutomationAccountName $aaInfo.AutomationAccountName -DefaultProfile $azContext)).value -scope $scope -Force
                    Write-verbose "Loaded $($var.name) : $($var.id) = $(get-variable -name $var.id -ValueOnly)"
                    
                } catch {
                    throw "Failed creating variable '$($var.name)'"
                }
            }
            return $vset.name
        
    } else {
        # Finding VariableSet matching with provided config file content
        $vset = $null
        
        foreach ($vs in $variableSets) {
            Write-verbose "Testing variableSet $($vs.name)"
            $matchingVSet = $true
            foreach ($var in $vs.variableSet) {
                if (Invoke-Expression "`$variables.name -notcontains '$($var.name)'") {
                    Write-Verbose "- Missing attribute $($var.name)"    
                    $matchingVSet = $false
                } else {
                    Write-verbose "- Validated attribute $($var.id) = $($var.name)"
                }
            }
            if ($matchingVSet) { $vset = $vs; break }
            
        }
        if ($null -eq $vset) { 
            throw [System.ArgumentException]::new("No variableSet matching the attributes provided")
        }
        Write-Verbose "Using variableSet '$($vset.name)'"
        
        # Load Variables according to detected variableSet
        foreach ($var in $variables) {
            if ($null -ne $var.value) {
                $v = $vset.variableSet |? {$_.name -eq $var.name}
                if ($null -eq $v) { write-warning "Variable $($var.name) is not recognized as member of this variableSet. Thus the variable was not created"}
                else {
                    
                    new-variable -name $v.id -value "$($var.value)" -scope $scope -Force
                    Write-verbose "Loaded $($var.name) : $($v.id) = $(get-variable -name $v.id -ValueOnly)"
                }
            } else {
                write-error "Failed loading variable '$($var.name)'"
            }
        }
        return $vset.name
    }   
}

function get-ahSecretFromAzVault {
    [cmdletbinding()]
    param (
        [Parameter(Mandatory=$true,ParameterSetName="currentContext")]
        [Parameter(Mandatory=$true,ParameterSetName="setContext")]
        [string]$vaultName,
        [Parameter(Mandatory=$true,ParameterSetName="setContext")]
        [Parameter(Mandatory=$true,ParameterSetName="currentContext")]
        [string]$vaultKeyName,
        [Parameter(Mandatory=$true,ParameterSetName="setContext")]
        [Microsoft.Azure.Commands.Profile.Models.Core.PSAzureProfile]$azContext
    )
    Write-verbose "Retrieving Secret from vault '$vaultName' with key '$vaultKeyName'"
    
    
    ########################################################
    try {
        if ($azContext) {
            Get-AzKeyVaultSecret -VaultName $vaultName -Name $vaultKeyName -ea stop -asplaintext -defaultProfile $azContext
        } else {
            Get-AzKeyVaultSecret -VaultName $vaultName -Name $vaultKeyName -ea stop -asplaintext
        }
    } catch {
        Throw "Failed Querying KeyVault Secret: $($_.exception.message)"
    }
}

function get-AhAutomationCredential {
    [cmdletbinding()]
    param (
        [Parameter(Mandatory=$true)]
        [string]$credName,
        [Parameter(Mandatory=$true)]
        [Microsoft.Azure.Commands.Profile.Models.Core.PSAzureProfile]$azContext
    )

    $aaInfo = get-ahCurrentAutomationInfo -azContext $azContext -verbose:$VerbosePreference
    Get-AzAutomationCredential -Name $credName -ResourceGroupName $aaInfo.ResourceGroupName `
        -AutomationAccountName $aainfo.AutomationAccountName -DefaultProfile $azContext

}

function connect-ahAzureContext {
    

    # Name of the Azure Run As connection
    $ConnectionName = 'AzureRunAsConnection'
    try
    {
        if($PSPrivateMetadata.JobId) {
            write-verbose 'Running in Azure Automation'
            
            # Try using managed identities by defaut
            # Currently supports only System Identity
            try 
            { 
                Write-Verbose ("Logging in to Azure using System Managed Identity") 
                return (Connect-AzAccount -Identity)
                
            } 
            catch { 
                Write-Warning -Message "Failed connecting with System managed identity : $($_.Exception). Trying RunAs Account"
            } 

            # Get the connection properties
            $ServicePrincipalConnection = Get-AutomationConnection -Name $ConnectionName      
        
            Connect-AzAccount `
                -ServicePrincipal `
                -TenantId $ServicePrincipalConnection.TenantId `
                -ApplicationId $ServicePrincipalConnection.ApplicationId `
                -CertificateThumbprint $ServicePrincipalConnection.CertificateThumbprint 
        } else {
            write-verbose 'Require interactive sign-in to connect'
            Connect-AzAccount -ea stop
        }
    }
    catch 
    {
        if (!$ServicePrincipalConnection)
        {
            # You forgot to turn on 'Create Azure Run As account'
            $ErrorMessage = "Connection $ConnectionName not found: $($_.exception.message)"
            throw $ErrorMessage
        }
        else
        {
            # Something else went wrong
            #Write-Error -Message $_.Exception.Message
            throw $_.Exception
        }
    }
}