HybridWorkerToolkit.psm1

# .EXTERNALHELP en-US\HybridWorkerToolkit.psm1-Help.xml
Function Get-HybridWorkerConfiguration
{
    #Read Hybrid Worker reg key
    $HybridWorkerRegKeyValues = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\HybridRunbookWorker"

    #Get Hybrid worker version
    $SandboxAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-object {$_.ManifestModule.Name -eq 'Orchestrator.Sandbox.exe'}
    If ($SandboxAssembly)
    {
        $HybridWorkerVersion = split-path (split-path (split-path $SandboxAssembly.location)) -leaf
    }

    #Get System Proxy
    $SystemProxyBytes = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Connections" -Name WinHttpSettings).WinHttPSettings
    $SystemProxyLength = $SystemProxyBytes[12]
    if ($SystemProxyLength -gt 0)
    {
        $SystemProxy = -join ($SystemProxyBytes[(12+3+1)..(12+3+1+$SystemProxyLength-1)] | ForEach-Object {([char]$_)})
    } else {
        $SystemProxy = $null
    }

    #Get MMA configuration
    $MMAConfig = New-Object -ComObject 'AgentConfigManager.MgmtSvcCfg'
    $MMAVersion = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup").AgentVersion
    $HybridWorkerConfig = @{
        HybridWorkerGroupName = $HybridWorkerRegKeyValues.RunbookWorkerGroup
        AutomationAccountId = $HybridWorkerRegKeyValues.AccountId
        MachineId = $HybridWorkerRegKeyValues.MachineId
        ComputerName = $env:COMPUTERNAME
        MMAInstallRoot = $env:MOMROOT
        PSVersion = $host.Version.ToString()
        HybridWorkerVersion = $HybridWorkerVersion
        SystemProxy = $SystemProxy
        MMAVersion = $MMAVersion
        MMAProxyUrl = $MMAConfig.ProxyUrl
        MMAProxyUserName = $MMAConfig.ProxyUsername
        MMAOMSWorkspaceId = $MMAConfig.AzureOperationalInsightsWorkspaceId
    }
    $HybridWorkerConfig
}

# .EXTERNALHELP en-US\HybridWorkerToolkit.psm1-Help.xml
Function Get-HybridWorkerJobRuntimeInfo
{
    #Make sure this function is executed within a runbook
    If ($PSPrivateMetadata -eq $null -and $env:AUTOMATION_ASSET_SANDBOX_ID -eq $null)
    {
        Throw "Get-HybridWorkerJobRuntimeInfo function must be executed within an Azure Automation runbook executed on a Hybrid Worker."
        Exit -1
    }

    #Get job details from Windows event log
    $SandboxId = $env:AUTOMATION_ASSET_SANDBOX_ID
    $5532EventFilter = @"
<QueryList>
    <Query Id='0' Path='Microsoft-SMA/Operational'>
        <Select Path='Microsoft-SMA/Operational'>*[System[(EventID=5532)]] and *[System[(Level=4)]] and *[EventData[Data[@Name='sandboxId']='{$SandboxId}']]</Select>
    </Query>
</QueryList>
"@

    $3732EventFilter = @"
<QueryList>
    <Query Id='0' Path='Microsoft-SMA/Operational'>
        <Select Path='Microsoft-SMA/Operational'>*[System[(EventID=3732)]] and *[System[(Level=4)]] and *[EventData[Data[@Name='sandboxId']='{$SandboxId}']]</Select>
    </Query>
</QueryList>
"@

    #$LogEntry = Get-WinEvent -FilterHashtable $FilterHastable
    $3732LogEntry = Get-WinEvent -FilterXml $3732EventFilter
    $5532LogEntry = Get-WinEvent -FilterXml $5532EventFilter
    $3732LogEntryXML = [XML]$3732LogEntry.ToXml()
    $5532LogEntryXML = [XML]$5532LogEntry.ToXml()
    
    #Convert to hashtable
    $JobEventDetails = @{}
    Foreach ($item in $5532LogEntryXML.Event.EventData.Data)
    {
        $JobEventDetails.Add($Item.Name, $Item.'#text'.Trim("{ }"))
    }

    #Get account name, resource group name and subscription Id
    $RunbookType = ($3732LogEntryXML.Event.EventData.Data | Where-Object {$_.name -ieq 'runbookType'}).'#text'.Trim("{ }")
    $JobEventDetails.Add('RunbookType', $RunbookType)

    $JobInfo = @{
        JobId = $JobEventDetails.JobId;
        SandboxId = $SandboxId
        ProcessId = $PID
        AutomationAssetEndPoint = $env:AUTOMATION_ASSET_ENDPOINT
        PSModulePath = $Env:PSModulePath
        CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
        LogActivityTrace = $PSPrivateMetadata.LogActivityTrace
        CurrentWorkingDirectory = $PWD.ToString()
        RunbookType = $JobEventDetails.runbookType
        RunbookName = $JobEventDetails.runbookName
        AccountName = $JobEventDetails.accountName
        ResourceGroupName = $JobEventDetails.resourceGroupName
        SubscriptionId = $JobEventDetails.subscriptionId
        TimeTakenToStartRunninginSeconds = $JobEventDetails.timeTakenToStartRunningInSeconds
    }
    $JobInfo
}

# .EXTERNALHELP en-US\HybridWorkerToolkit.psm1-Help.xml
Function New-HybridWorkerRunbookLogEntry
{
    Param(
        [Parameter(Mandatory=$false,HelpMessage='Please specify the event log name')][Alias('Log')][String]$LogName= 'Application',
        [Parameter(Mandatory=$true,HelpMessage='Please specify the event log ID')][int]$Id,
        [Parameter(Mandatory=$false,HelpMessage='Please specify the event level')][String][ValidateSet('Information', 'Warning', 'Error')]$Level= 'Information',
        [Parameter(Mandatory=$false,HelpMessage='Please specify the event log source')][String][ValidateSet('AzureAutomation Job Verbose', 'AzureAutomation Job Status', 'AzureAutomation Job Result','AzureAutomation Job Process')]$Source = 'AzureAutomation Job Status',
        [Parameter(Mandatory=$false,HelpMessage='Please specify if the Hybrid Worker configuration should be logged in the event log too')][ValidateScript({if ($_ -eq $true) {$LogMinimum -ne $true}})][Boolean]$LogHybridWorkerConfig=$false,
        [Parameter(Mandatory=$false,HelpMessage='Please specify if only the minimum information (JobId) should be logged')][ValidateScript({if ($_ -eq $true) {$LogHybridWorkerConfig -ne $true}})][Boolean][Alias('Minimum')]$LogMinimum=$false,
        [Parameter(Mandatory=$true,HelpMessage='Please specify the event log message')][String]$Message,
        [Parameter(Mandatory=$false,HelpMessage='Please specify additional event parameters')][String[]]$AdditionalParameters
    )
    #make sure the event log specified exists
    If (!([System.Diagnostics.EventLog]::Exists($LogName)))
    {
        Throw "the event log specified '$LogName' does not exist. Only administrative event logs are supported."
        Exit -1
    }

    #make sure the event source exists
    if ([System.Diagnostics.EventLog]::SourceExists($source) -eq $false)
    {
        [System.Diagnostics.EventLog]::CreateEventSource($source, $LogName)
    }

    #Determine event level
    Switch ($Level.ToLower())
    {
        'information' {$EventLevel = [System.Diagnostics.EventLogEntryType]::Information}
        'warning' {$EventLevel = [System.Diagnostics.EventLogEntryType]::Warning}
        'error' {$EventLevel = [System.Diagnostics.EventLogEntryType]::Error}
    }

    #Get the runbook runtime info (only if it's not previously retrieved)
    If ($Script:RunbookRuntimeInfo -eq $null)
    {
        $Script:RunbookRuntimeInfo = Get-HybridWorkerJobRuntimeInfo
    }

    #Get the Hybrid Worker configuration (only if it's not previously retrieved)
    If ($Script:HybridWorkerConfig -eq $null)
    {
        $Script:HybridWorkerConfig = Get-HybridWorkerConfiguration
    }

    #Create event log entry
    $evtId = New-Object System.Diagnostics.EventInstance($Id,0,$EventLevel);
    $evtObject = New-Object System.Diagnostics.EventLog;
    $evtObject.Log = $LogName;
    $evtObject.Source = $Source;
    $MessageArray = @()
    $MessageArray += $Message
    
    #Add user-specified additional parameterss
    If ($AdditionalParameters.count -gt 0)
    {
        Foreach ($item in $AdditionalParameters)
        {
            $MessageArray += $item
        }
    }
    If ($LogMinimum -eq $false)
    {
        #Add environment related info
        $MessageArray += "AutomationAccountName: $($Script:RunbookRuntimeInfo.AccountName)"
        $MessageArray += "HybridWorkerGroupName: $($Script:HybridWorkerConfig.HybridWorkerGroupName)"
        $MessageArray += "ResourceGroupName: $($Script:RunbookRuntimeInfo.ResourceGroupName)"
        $MessageArray += "AzureSubscriptionId: $($Script:RunbookRuntimeInfo.SubscriptionId)"
        If ($LogHybridWorkerConfig -eq $true)
        {
            $MessageArray += "OMSWorkspaceId: $($Script:HybridWorkerConfig.MMAOMSWorkspaceId)"
        }

        #Add agent related info
        If ($LogHybridWorkerConfig -eq $true)
        {
            $MessageArray += "HybridWorkerVersion: $($Script:HybridWorkerConfig.HybridWorkerVersion)"
            $MessageArray += "MMAVersion: $($Script:HybridWorkerConfig.MMAVersion)"
            $MessageArray += "MMAInstallRoot: $($Script:HybridWorkerConfig.MMAInstallRoot)"
            $MessageArray += "MMAProxyUrl: $($Script:HybridWorkerConfig.MMAProxyUrl)"
            $MessageArray += "SystemProxy: $($Script:HybridWorkerConfig.SystemProxy)"
        }

        #Add runbook and job related info
        $MessageArray += "JobId: $($Script:RunbookRuntimeInfo.JobId)"
        $MessageArray += "SandboxId: $($Script:RunbookRuntimeInfo.SandboxId)"
        $MessageArray += "ProcessId: $($Script:RunbookRuntimeInfo.ProcessId)"
        $MessageArray += "CurrentWorkingDirectory: $($Script:RunbookRuntimeInfo.CurrentWorkingDirectory)"
        $MessageArray += "RunbookType: $($Script:RunbookRuntimeInfo.RunbookType)"
        $MessageArray += "RunbookName: $($Script:RunbookRuntimeInfo.RunbookName)"
        $MessageArray += "TimeTakenToStartRunninginSeconds: $($Script:RunbookRuntimeInfo.TimeTakenToStartRunninginSeconds)"
    } else {
        $MessageArray += "JobId: $($Script:RunbookRuntimeInfo.JobId)"
    }
    $evtObject.WriteEvent($evtId, $MessageArray)
}