Azure Update Management (Log Analytics Agents & Automation Accounts)
Published Dec 19 2021 11:00 PM 9,141 Views
Microsoft

 

Many of our customers would like to start patching servers as soon as possible using a single Update Management Solution deployed on a single Log Analytics Workspace. To achieve this goal you need to deploy the Azure Monitor Agent (newer version) or the Microsoft Monitoring Agent (current version) on machines that could be domain joined or even on a workgroup. To add even more complexity, the use of PowerShell could be restricted.  

The above requirements can be broken up into 2 scenarios:

 

Scenarios

[Scenario 1] – Virtual Machine on Azure that is already connected to the domain. It might or might not have the agent. It might or might not have the proxy settings filled in.

[Scenario 2] – Virtual Machine on Azure that is not connected to the domain. It might or might not have the agent or proxy settings filled in.

We will now explore 3 Options for deploying the agents and 3 Query Methods to confirm if the installation was actually successful.

 

The 3 Options for deploying the Agent

 

Option 1 – Azure Policy

 

For both Scenario 1 and Scenario 2 this can be used. We would choose the Enable Azure Monitor for VMs Policy Initiative.

wernerrall_0-1639815644997.png

 

It can be assigned to any Management Group or Subscription

wernerrall_1-1639815645013.png

 

Simply choose your Log Analytics Workspace that is connected to the Automation Account Containing Update Management

wernerrall_2-1639815645019.png

 

I normally also create a Remediation Managed Identity

wernerrall_3-1639815645027.png

 

Set a default Non-Compliance message

wernerrall_4-1639815645034.png

 

And create

wernerrall_5-1639815645041.png

 

If we immediately go to the Deploy-VM-Monitoring we can view the compliance

wernerrall_6-1639815645052.png

 

By clicking on Non-Compliant Resources I can see the machines

wernerrall_7-1639815645058.png

 

But this policy might not have the Failed/Succeeded metric for the actual extension. For that we can use 3 query methods: Azure Resource Graph Explorer, Azure CLI Bash, Azure Cloud Shell PowerShell.

 

Option 2 – PowerShell

 

For Scenario 1 and Scenario 2 Our official method to deploy the Log Analytics Extension with PowerShell in Azure can be seen below.

 

 

$PublicSettings = @{"workspaceId" = "myWorkspaceId"}
$ProtectedSettings = @{"workspaceKey" = "myWorkspaceKey"}
Set-AzVMExtension -ExtensionName "MicrosoftMonitoringAgent" `
   -ResourceGroupName "myResourceGroup" `
    -VMName "myVM" `
    -Publisher "Microsoft.EnterpriseCloud.Monitoring" `
    -ExtensionType "MicrosoftMonitoringAgent" `
    -TypeHandlerVersion 1.0 `
    -Settings $PublicSettings `
    -ProtectedSettings $ProtectedSettings `
    -Location WestUS

 

 

Or if you are using the Azure Monitor Agent

 

 

Set-AzVMExtension -ExtensionName "AMAWindows" `
    -ExtensionType AzureMonitorWindowsAgent `
    -Publisher " Microsoft.Azure.Monitor" `
    -ResourceGroupName "myResourceGroup" `
    -VMName "myVM" `
    -TypeHandlerVersion 1.0 `
    -Location WestUS

 

 

If the Extension already Exists, you mentioned there needs to some proxy settings filled in.

One way to configure Proxy settings quickly on multiple machines would be to use the Custom Script Extension. PowerShell 7 brings the functionality “-Parallel” which will run multiple instances of the same script.

To manually run the Customer Script Extension Proxy Setting on a Server and set the correct Workspace we can use the below script

 

 

#This section adds a new Workspace
$workspaceId = "<WS ID>"
$workspaceKey = "<WS KEy>"

$mma = New-Object -ComObject 'AgentConfigManager.MgmtSvcCfg'
$mma.AddCloudWorkspace($workspaceId, $workspaceKey)

#This section is where the Proxy can be configured
param($ProxyDomainName="https://proxy.contoso.com:30443")
$proxyMethod = $mma | Get-Member -Name 'SetProxyUrl'
if (!$proxyMethod)
{
    Write-Output 'Health Service proxy API not present, will not update settings.'
    return
}
#Clears Proxy settings in MMA
Write-Output "Clearing proxy settings."
$mma.SetProxyUrl('')

#Adds new proxy settings
Write-Output "Setting proxy to $ProxyDomainName"
$mma.SetProxyUrl($ProxyDomainName)
$mma.ReloadConfiguration()

 

 

wernerrall_8-1639815645066.png

 

If we wanted to Automate this for multiple machines, we could do something like mentioned in below article.

How to run scripts against multiple Azure VMs by using Run Command - Thomas Maurer

 

Option 3 – Desired State Configuration

 

Desired State Configuration is another great way of ensuring the MMA is present on machines and configured correctly. This also makes execution easier because you can use a specified approved account or Hybrid runbook worker to execute the DSC in case of strict security rules where only certain accounts can run PowerShell scripts.

Steps

  1. Download the MMA Agent

wernerrall_9-1639815645068.png

 

  1. Extract the contents because we want the MSI

wernerrall_10-1639815645068.png

 

  1. Open Notepad and save the below as “Get-MSIFileInformation.ps1” in your Downloads folder.

 

param(
[parameter(Mandatory=$true)]
[IO.FileInfo]$Path,
[parameter(Mandatory=$true)]
[ValidateSet("ProductCode","ProductVersion","ProductName")]
[string]$Property
)
try {
    $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer
    $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$WindowsInstaller,@($Path.FullName,0))
    $Query = "SELECT Value FROM Property WHERE Property = '$($Property)'"
    $View = $MSIDatabase.GetType().InvokeMember("OpenView","InvokeMethod",$null,$MSIDatabase,($Query))
    $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null)
    $Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)
    $Value = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)
    return $Value
}
catch {
    Write-Output $_.Exception.Message
}

 

 

  1. Open PowerShell and cd to Downloads, and run the Newly saved MSI Script

.\Get-MSIFileInformation.ps1 -Path C:\Users\<youruser>\Downloads\MMASetup-A
MD64\MOMAgent.msi -Property ProductCode

 

wernerrall_11-1639815645071.png

 

  1. Create Automation Variables for

OPSINSIGHTS_WS_ID  (This is your Workspace you need the server to connect to),

OPSINSIGHTS_WS_KEY (This is the key for the workspace),

OPINSIGHTS_PROXY_URL (This is the proxy URL in format  https://proxy.contoso.com:30443)

 

wernerrall_12-1639815645075.png

 

  1. Import the Module into the Automation Account

wernerrall_13-1639815645077.png

 

wernerrall_14-1639815645082.png

 

  1. Save the below script as MMAgent.ps1 and Modify the ProductID that was found in Step 4. Also update the ProductID as found in Step 4.

 

Configuration MMAgent
{
    $OIPackageLocalPath = "C:\Deploy\MMASetup-AMD64.exe"
    $OPSINSIGHTS_WS_ID = Get-AutomationVariable -Name "OPSINSIGHTS_WS_ID"
    $OPSINSIGHTS_WS_KEY = Get-AutomationVariable -Name "OPSINSIGHTS_WS_KEY"
    $OPINSIGHTS_PROXY_URL = Get-AutomationVariable -Name " OPINSIGHTS_PROXY_URL"

    Import-DscResource -ModuleName xPSDesiredStateConfiguration
    Import-DscResource -ModuleName PSDesiredStateConfiguration

    Node OMSnode {
        Service OIService
        {
            Name = "HealthService"
            State = "Running"
            DependsOn = "[Package]OI"
        }
        xRemoteFile OIPackage {
            Uri = "https://go.microsoft.com/fwlink/?LinkId=828603"
            DestinationPath = $OIPackageLocalPath
        }
        Package OI {
            Ensure = "Present"
            Path  = $OIPackageLocalPath
            Name = "Microsoft Monitoring Agent"
            ProductId = "88EE688B-31C6-4B90-90DF-FBB345223F94"
            Arguments = '/C:"setup.exe /qn NOAPM=1 ADD_OPINSIGHTS_WORKSPACE=1 OPINSIGHTS_WORKSPACE_ID=' + $OPSINSIGHTS_WS_ID + ' OPINSIGHTS_WORKSPACE_KEY=' + $OPSINSIGHTS_WS_KEY + ' OPINSIGHTS_PROXY_URL=' + $OPINSIGHTS_PROXY_URL + ' AcceptEndUserLicenseAgreement=1"'
            DependsOn = "[xRemoteFile]OIPackage"
        }
    }
}

 

 

  1. Import the MMAgent.ps1 script into the Automation Account State Configuration under Configurations. After the import click on MMAgent and click Compile.

 

wernerrall_15-1639815645086.png

 

wernerrall_16-1639815645088.png

 

  1. Assign a computer or node and within a few minutes the Agent will get pushed to the machine.

 

wernerrall_17-1639815645094.png

 

wernerrall_18-1639815645100.png

 

wernerrall_19-1639815645107.png

 

The 3 Methods to Query Agent Installation

 

1.      Azure Resource Graph Explorer [Query All Servers]*

 

 

// LogAnalyticsandHealthyAgentv5
// All Running, All Health and All Monitoring Extensions
// Click the "Run query" command above to execute the query and see results.
// Linux and Windows Agents
// Click the "Run query" command above to execute the query and see results.
// This query will show machines that are currently running.
// This query will show the extensions that relates to MicrosoftMonitoringAgent','AzureMonitorWindowsAgent'and 'OMSAgentForLinux'

resources
| where type == 'microsoft.compute/virtualmachines'
| where properties.extended.instanceView.powerState.displayStatus=="VM running" and properties.osProfile.windowsConfiguration.provisionVMAgent=="true" or properties.extended.instanceView.powerState.displayStatus=="VM running" and properties.osProfile.linuxConfiguration.provisionVMAgent=="true"
| extend
    JoinID = toupper(id),
    OSName = tostring(name),
    OSType = tostring(properties.storageProfile.osDisk.osType),
    RSG = tostring(resourceGroup),
    SUB = tostring(subscriptionId),
    LOC = tostring(location)
| join kind=leftouter(
resources
| where type == 'microsoft.compute/virtualmachines/extensions' and name == 'MicrosoftMonitoringAgent' or name == 'AzureMonitorWindowsAgent' or name == 'OMSAgentForLinux'
// | where properties.provisioningState == 'Succeeded'
|extend 
  VMId = toupper(substring(id, 0, indexof(id, '/extensions'))),
  props = tostring(properties.settings),
  prvstatus = tostring(properties)
)on $left.JoinID == $right.VMId
| summarize Extensions = make_list(props) by id, OSName, OSType, RSG, SUB, LOC, prvstatus

 

 

Example of execution. This will show me all machines that are running and their provisionState of the Extension that related to Log Analytics.

 

The subscription where the policies have not applied yet.

wernerrall_20-1639815645123.png

 

Another subscription to showcase the Provisioning Status

wernerrall_21-1639815645138.png

 

*Although Resource Graph is the easiest way to get information about all machines at once it takes longer to update than the Bash or PowerShell. This means if you are querying your machines and you see one has failed and you repair the failure Resource Graph will take time to update. Therefore if you want realtime information please refer to Azure CLI or Cloud Shell, the limitation being only looking at one server.

 

2.      Azure CLI Bash [Deep Dive 1 Server Real Time]

If I find that I need to deep dive into one specific server to see if the Extension Provisioning succeeded or failed I can use Cloud Shell Bash in the Azure Portal.

The command is:

 

 

az vm extension show -g <resource group> --vm-name <vmname> --name MicrosoftMonitoringAgent

 

 

wernerrall_22-1639815645151.png

 

3.      Azure Cloud Shell PowerShell [Deep Dive 1 Server]

The Bash is great at showing a one pager but if I wanted to dive into even more detail about why an extension failed I can use Cloud Shell PowerShell

The command is:

 

 

Get-AzVM -ResourceGroupName <resource group> -Name <server> -Status

 

 

I can look at the Extensions Portion and I will have the error code and message

wernerrall_23-1639815645163.png

 

And the ExtensionHandlers will give me some more information

wernerrall_24-1639815645176.png

 

These are only methods to assist you in querying your VM Extensions. We need them to be healthy to connect to the Automation Account.

 

Thank you for reading and I hope this has been beneficial to you in your patching journey.

 

Some more helpful Links

 

PowerShell/Get-MSIFileInformation.ps1 at master · NickolajA/PowerShell (github.com)

Install Log Analytics agent on Windows computers - Azure Monitor | Microsoft Docs

Install the Azure Monitor agent - Azure Monitor | Microsoft Docs

Log Analytics virtual machine extension for Windows - Azure Virtual Machines | Microsoft Docs

https://docs.microsoft.com/en-us/azure/security-center/faq-data-collection-agents#what-are-the-recom...

https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/oms-windows

https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/oms-linux

https://docs.microsoft.com/en-us/azure/azure-monitor/vm/quick-collect-linux-computer#obtain-workspac...

 

 

Disclaimer
The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.

 

Co-Authors
Version history
Last update:
‎Dec 21 2021 07:24 AM
Updated by: