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.
It can be assigned to any Management Group or Subscription
Simply choose your Log Analytics Workspace that is connected to the Automation Account Containing Update Management
I normally also create a Remediation Managed Identity
Set a default Non-Compliance message
And create
If we immediately go to the Deploy-VM-Monitoring we can view the compliance
By clicking on Non-Compliant Resources I can see the machines
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()
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
- Download the MMA Agent
- Extract the contents because we want the MSI
- 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
}
- 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
- 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)
- Import the Module into the Automation Account
- 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"
}
}
}
- Import the MMAgent.ps1 script into the Automation Account State Configuration under Configurations. After the import click on MMAgent and click Compile.
- Assign a computer or node and within a few minutes the Agent will get pushed to the machine.
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.
Another subscription to showcase the Provisioning Status
*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
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
And the ExtensionHandlers will give me some more information
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/virtual-machines/extensions/oms-windows
https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/oms-linux
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.
Updated Dec 21, 2021
Version 2.0wernerrall
Microsoft
Joined January 31, 2020
Core Infrastructure and Security Blog
Follow this blog board to get notified when there's new activity