Get-AzureVmManagementSolutionOnboardingState.ps1

<#PSScriptInfo
 
.VERSION 1.0.8
 
.GUID 3268e204-99af-4846-8aa6-1a210e011bce
 
.AUTHOR Stas Kuvshinov
 
.COMPANYNAME Microsoft Corporation
 
.COPYRIGHT Microsoft Corporation
 
.TAGS Automation Management
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES LogAnalyticsQuery
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
The LogAnalyticsQuery module is available on https://dev.loganalytics.io/documentation/Tools/PowerShell-Cmdlets
 
.PRIVATEDATA
 
#>
 

#Requires -Module @{ ModuleName = 'AzureRM.Profile'; ModuleVersion = '3.1.0' }
#Requires -Module @{ ModuleName = 'AzureRM.Compute'; ModuleVersion = '3.1.0' }
#Requires -Module @{ ModuleName = 'AzureRM.Resources'; ModuleVersion = '3.1.0' }
#Requires -Module @{ ModuleName = 'AzureRM.OperationalInsights'; ModuleVersion = '3.4.1' }

<#
 
.Parameter vmResourceId
Required. Full resource identifier of an Azure VM
 
.Parameter solutionType
Required. Type of the management solution. Possible values: 'updates', 'changeTracking'
 
.Parameter queryIntervalHours
Optional. Query interval window in hours to use when looking for ingested data. (Default = 24)
 
.EXAMPLE
.\Get-AzureVmManagementSolutionOnboardingState.ps1 -vmResourceId /subscriptions/6c098ac2-6c43-4fd8-875c-6d089beb2ef5/resourceGroups/RG1/providers/Microsoft.Compute/virtualMachines/stas-ubuntu-1604-x -solutionType updates
 
.EXAMPLE
.\Get-AzureVmManagementSolutionOnboardingState.ps1 -vmResourceId /subscriptions/6c098ac2-6c43-4fd8-875c-6d089beb2ef5/resourceGroups/RG1/providers/Microsoft.Compute/virtualMachines/stas-ubuntu-1604-x -solutionType updates -queryIntervalHours 12
 
.Example
.\Get-AzureVmManagementSolutionOnboardingState.ps1 -vmResourceId /subscriptions/6c098ac2-6c43-4fd8-875c-6d089beb2ef5/resourceGroups/RG1/providers/Microsoft.Compute/virtualMachines/ws-2012r2-a4 -solutionType changeTracking
 
.DESCRIPTION
 The script gets management solution onboarding information for an Azure VM.
  
 Most of the script dependencies are available at the PowerShell Gallery with the only exception of the LogAnalyticsQuery.psm1 module that you need to manually download from https://dev.loganalytics.io/documentation/Tools/PowerShell-Cmdlets.
#>
 
Param(
    [string]
    [Parameter(Mandatory = $true)]
    $vmResourceId,

    [string]
    [Parameter(Mandatory = $true)]
    [ValidateSet("updates", "changeTracking")]
    $solutionType,

    [int]
    [Parameter(Mandatory = $false)]
    $queryIntervalHours = 24
)

$information = [pscustomobject] [ordered] @{
    'AzureVMFound'=$false
    'AzureVMHasManagementExtensionInstalled'='n/a'
    'AzureVMManagementExtensionHasManagementWorkspaceInformation'='n/a'
    'ManagementWorkspaceFoundInSubscription'='n/a'
    'VmHeartbeatDataIngestedIntoWorkspace'='n/a'
    'VmHeartbeatDataIndicatesThatVmHasSolutionEnabled'='n/a'
    'SolutionDataIngestedIntoWorkspace'='n/a'
}

$vmDiscriminator = New-Object -Type PSObject -Proper @{'id'=$vmResourceId}
$vm = $vmDiscriminator | Get-AzureRmResource
if($vm -ne $null){
    $information.AzureVMFound = $true

    $vmManagementExtensionResourceId = "$($vmResourceId)/extensions/MMAExtension"
    if($vm.Properties.osProfile.linuxConfiguration -ne $null){
        $vmManagementExtensionResourceId = "$($vmResourceId)/extensions/OMSAgentLinuxExtension"
    }
    $vmManagementExtensionDiscriminator = New-Object -Type PSObject -Proper @{'id'=$vmManagementExtensionResourceId}
    $vmManagementExtensionResource = $vmManagementExtensionDiscriminator | Get-AzureRmResource

    $information.AzureVMHasManagementExtensionInstalled = $false
    if($vmManagementExtensionResource -ne $null){
        $information.AzureVMHasManagementExtensionInstalled = $true

        $vmManagementWorkspaceId = $vmManagementExtensionResource.Properties.settings.workspaceId

        $information.AzureVMManagementExtensionHasManagementWorkspaceInformation = $false
        if($vmManagementWorkspaceId -ne $null){
            $information.AzureVMManagementExtensionHasManagementWorkspaceInformation = $true

            $vmManagementWorkspace = Get-AzureRmOperationalInsightsWorkspace | where-object {$_.CustomerId -eq $vmManagementWorkspaceId}

            $information.ManagementWorkspaceFoundInSubscription = $false
            if($vmManagementWorkspace -ne $null){
                $information.ManagementWorkspaceFoundInSubscription = $true

                $vmManagementWorkspaceResourceDiscriminator = New-Object -Type PSObject -Proper @{'id'=$vmManagementWorkspace.ResourceId}
                $vmManagementWorkspaceResource = $vmManagementWorkspaceResourceDiscriminator | Get-AzureRmResource

                $vmManagementWorkspaceSearchVersion = @{'0'='OQL';'1'='KQL'}[$vmManagementWorkspaceResource.Properties.features.searchVersion.ToString()]

                $queryVmHeartbeatDataIngestedIntoWorkspace = [String]::Format(@{
                'OQL'='Type=Heartbeat and (ResourceId="{0}" or Computer="{1}") | top 1'
                'KQL'='Heartbeat | where (ResourceId=~"{0}" or Computer=~"{1}") | take 1'
                }[$vmManagementWorkspaceSearchVersion], $vmResourceId, $vm.Name, $solutionType)

                $solutionTableName = @{'updates'='Update';'changeTracking'='ConfigurationChange'}[$solutionType]

                if($vmManagementWorkspaceSearchVersion -eq 'OQL'){
                    $endDate = (get-date)
                    $startDate = $endDate.AddHours(-1 * $queryIntervalHours)
                    $queryVmHeartbeatDataIngestedIntoWorkspace = [String]::Format('Type=Heartbeat and (ResourceId="{0}" or Computer="{1}") | top 1', $vmResourceId, $vm.Name, $solutionType)
                    $information.VmHeartbeatDataIngestedIntoWorkspace = ($vmManagementWorkspace | Get-AzureRmOperationalInsightsSearchResults -Query $queryVmHeartbeatDataIngestedIntoWorkspace -End $endDate -Start $startDate).Value.Count -eq 1                    

                    $queryVmHeartbeatDataIndicatesThatVmHasSolutionEnabled = [String]::Format('Type=Heartbeat and (ResourceId="{0}" or Computer="{1}") and Solutions:contains("{2}") | top 1', $vmResourceId, $vm.Name, $solutionType)
                    $information.VmHeartbeatDataIndicatesThatVmHasSolutionEnabled = ($vmManagementWorkspace | Get-AzureRmOperationalInsightsSearchResults -Query $queryVmHeartbeatDataIndicatesThatVmHasSolutionEnabled -End $endDate -Start $startDate).Value.Count -eq 1

                    $querySolutionDataIngestedIntoWorkspace = [String]::Format('Type={0} and Computer="{1}" | top 1', $solutionTableName, $vm.Name)
                    $information.SolutionDataIngestedIntoWorkspace = ($vmManagementWorkspace | Get-AzureRmOperationalInsightsSearchResults -Query $querySolutionDataIngestedIntoWorkspace -End $endDate -Start $startDate).Value.Count -eq 1
                }
                elseif($vmManagementWorkspaceSearchVersion -eq 'KQL'){
                    if(-not (Get-Command Invoke-LogAnalyticsQuery -ErrorAction SilentlyContinue)) {
                        Write-Error 'The VM is managed by a workspace with enhanced log analytics capabilities. Please, import the LogAnalyticsQuery module from https://dev.loganalytics.io/documentation/Tools/PowerShell-Cmdlets to verify if the solution data is being ingested into search.'
                        return $information
                    }

                    $queryVmHeartbeatDataIngestedIntoWorkspace = [String]::Format('Heartbeat | where TimeGenerated > ago(24h) and (ResourceId=~"{0}" or Computer=~"{1}") | take 1', $vmResourceId, $vm.Name, $solutionType)
                    $information.VmHeartbeatDataIngestedIntoWorkspace = (Invoke-LogAnalyticsQuery -WorkspaceName $vmManagementWorkspace.Name -ResourceGroup $vmManagementWorkspaceResource.ResourceGroupName -SubscriptionId $vmManagementWorkspaceResource.SubscriptionId -Query $queryVmHeartbeatDataIngestedIntoWorkspace).Results -ne $null

                    $queryVmHeartbeatDataIndicatesThatVmHasSolutionEnabled = [String]::Format('Heartbeat | where TimeGenerated > ago(24h) and (ResourceId=~"{0}" or Computer=~"{1}") and Solutions has "{2}" | take 1', $vmResourceId, $vm.Name, $solutionType)
                    $information.VmHeartbeatDataIndicatesThatVmHasSolutionEnabled = (Invoke-LogAnalyticsQuery -WorkspaceName $vmManagementWorkspace.Name -ResourceGroup $vmManagementWorkspaceResource.ResourceGroupName -SubscriptionId $vmManagementWorkspaceResource.SubscriptionId -Query $queryVmHeartbeatDataIndicatesThatVmHasSolutionEnabled).Results -ne $null

                    $querySolutionDataIngestedIntoWorkspace = [String]::Format('{0} | where TimeGenerated > ago(24h) and Computer=~"{1}" | take 1', $solutionTableName, $vm.Name)
                    $information.SolutionDataIngestedIntoWorkspace = (Invoke-LogAnalyticsQuery -WorkspaceName $vmManagementWorkspace.Name -ResourceGroup $vmManagementWorkspaceResource.ResourceGroupName -SubscriptionId $vmManagementWorkspaceResource.SubscriptionId -Query $querySolutionDataIngestedIntoWorkspace).Results -ne $null
                }
            }
        }
    }
}

return $information