Enrolling Azure VMs in Operations Management Suite


In a previous post I talked about Operations Management Suite aka Log Analytics and how it can help you achieve a better understanding of what’s happening on your on-premise and cloud resources. In this blog post I will show you how to enroll your Azure VMs in OMS.

There are four ways you can enroll your Azure virtual machines in OMS:

PowerShell. (Saw that coming didn’t you?)
Installing OMS Agent at provisioning time using an ARM JSON Template.
Connecting the Azure VMs to OMS from the portal.
Manually installing the Windows / Linux agent.

Let’s tackle the first three scenarios, shall we?

1. To connect your Azure VMs to OMS, I created a very simple interactive script that can help you do this operation with ease. Make sure that you have the latest Azure PS cmdlets installed.

function script:Connect-AzureVMstoOMS 
{
  <# .synopsis this script will allow you to en-roll multiple or all vms from your azure subscription in operations management suite .description the purpose of is ease enrollment process a specific oms account. requires user already be logged on his subscription. works with windows linux if currently selected does not have an account then has option provide workspace id and key. .parameter selectionmethod mandatory parameter -selection method used select which want en-rolled them. values="Multiple" omsworkspaceid optional -if doesn't exist specified required. omsworkspacekey key .example connect-azurevmstoom -selectionmethod -omsworkspaceid value -omsworkspacekey executed prompts he should was provided that's present #>



  param(
    [Parameter(Mandatory = $true,HelpMessage = 'The input for this parameter is Multiple or All. 
    The value  allows you to select a number of VMs that you want to enroll in OMS. 
    The value  will enroll all VMs Windows / Linux VMs in OMS')]
    [ValidateSet('Multiple','All')]
    [string]
    $SelectionMethod,
    
    [String]
    $OMSWorkSpaceID,
    
    [String]
    $OMSWorkSpaceKey
    
  )
           
  try
  {
    $Subscription = Get-AzureRmContext
  }
  catch
  {
    Write-Error -Message "No Azure Context was found.
    Please run Login-AzureRmAccount and select an Azure subscription"
  }


  
  if(($OMSWorkSpaceID -eq '') -and ($OMSWorkSpaceKey -eq ''))
  {   
    if ((Get-AzureRmOperationalInsightsWorkspace).Count -gt 1)
    {
      $OMSWorkSpace = Get-AzureRmOperationalInsightsWorkspace | Out-GridView -OutputMode Single
    }
    else
    {
      $OMSWorkSpace = Get-AzureRmOperationalInsightsWorkspace
    }
      
    if ($OMSWorkSpace -eq $null)
    {
      Write-Error -Message ('Cannot find an OMS account in the current subscription.
                            Subscription Name = {0} 
                            Subscription ID = {1}' `
                            -f $Subscription.Subscription.SubscriptionName, `
                               $Subscription.Subscription.SubscriptionID) `
                            -Category ObjectNotFound
      break
    }
    $OMSWorkSpaceID = $OMSWorkSpace.CustomerId
    $OMSWorkSpaceKey = (Get-AzureRmOperationalInsightsWorkspaceSharedKeys `
                        -ResourceGroupName $OMSWorkSpace.ResourceGroupName `
                        -Name $OMSWorkSpace.Name).PrimarySharedKey
  }
    
  
  switch ($SelectionMethod){
  
    'Multiple'
    {
      $VMs = Get-AzureRmVM | Out-GridView -OutputMode Multiple
    }
    'All'
    {
      $VMs = Get-AzureRmVM
    }
  }
  foreach ($VM in $VMs)
  {
    if ($VM.StorageProfile.OsDisk.OsType -eq 'Windows')
    {
      Write-Verbose -Message ('Installing Windows OMS Agent on {0}' -f $VM.Name)
      Set-AzureRmVMExtension -ResourceGroupName $VM.ResourceGroupName `
                             -VMName $VM.Name `
                             -Name 'MicrosoftMonitoringAgent' `
                             -Publisher 'Microsoft.EnterpriseCloud.Monitoring' `
                             -ExtensionType 'MicrosoftMonitoringAgent' `
                             -TypeHandlerVersion '1.0' `
                             -Location $VM.Location `
                             -SettingString "{'workspaceId': '$OMSWorkSpaceID'}" `
                             -ProtectedSettingString "{'workspaceKey': '$OMSWorkSpaceKey'}"
    }
    elseif ($VM.StorageProfile.OsDisk.OsType -eq 'Linux')
    {
      Write-Verbose -Message ('Installing Linux OMS Agent on {0}.Name' -f $VM.Name)
      Set-AzureRmVMExtension -ResourceGroupName $VM.ResourceGroupName `
                             -VMName $VM.Name -Name 'OmsAgentForLinux' `
                             -Publisher 'Microsoft.EnterpriseCloud.Monitoring' `
                             -ExtensionType 'OmsAgentForLinux' `
                             -TypeHandlerVersion '1.0' `
                             -Location $VM.Location `
                             -SettingString "{'workspaceId': '$OMSWorkSpaceID'}" `
                             -ProtectedSettingString "{'workspaceKey': '$OMSWorkSpaceKey'}"
    }
  }
}

2. To enroll a VM at provisioning time you need to deploy it using an ARM Template. I suggest using Visual Studio with the latest Azure SDK in order to ease the template creation process. With Visual Studio you have a graphical interface that allows you to add and nest resources as you please. Try it, you will love it ?

Here’s an example ARM template that handles both Linux and Windows scenarios:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspaceId": {
      "type": "string",
      "metadata": {
        "description": "Workspace ID"
      }
    },
    "workspaceKey": {
      "type": "securestring",
      "metadata": {
        "description": "Workspace Key"
      }
    },
    "vmName": {
      "type": "string",
      "metadata": {
        "description": "Virtual Machine name."
      }
    },

    "osType": {
      "type": "string",
      "allowedValues": [
        "Windows",
        "Linux"
      ],
      "metadata": {
        "description": "This is the OS that your VM will be running"
      }
    },
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "User name for the Virtual Machine."
      }
    },
    "adminPassword": {
      "type": "securestring",
      "metadata": {
        "description": "Password for the Virtual Machine."
      }
    },
    "dnsLabelPrefix": {
      "type": "string",
      "metadata": {
        "description": "DNS Label for the Public IP. Must be lowercase. It should match with the following regular expression: ^[a-z][a-z0-9-]{1,61}[a-z0-9]$ or it will raise an error."
      }
    }
  },
  "variables": {

    "computeApiVersion": "2016-03-30",
    "networkApiVersion": "2016-06-01",
    "storageApiVersion": "2016-01-01",

    "location": "[resourceGroup().location]",
    "storageAccountType": "Standard_LRS",
    "saVhdName": "[concat(parameters('vmName'), uniqueString(resourceGroup().id))]",

    "nicName": "[concat(parameters('vmName'), '.vmNIC')]",
    "addressPrefix": "10.0.0.0/16",
    "subnetName": "Subnet",
    "subnetPrefix": "10.0.0.0/24",
    "publicIPAddressName": "[concat(parameters('vmName'), '.PublicIP')]",
    "publicIPAddressType": "Dynamic",
    "vmSize": "Standard_D1_v2",
    "virtualNetworkName": "[concat(parameters('vmName'), '.VNET')]",
    "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
    "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",

    "Windows": {
      "imagePublisher": "MicrosoftWindowsServer",
      "imageOffer": "WindowsServer",
      "imageVersion": "2016-Datacenter",
      "omsType": "MicrosoftMonitoringAgent"
    },
    "Linux": {
      "imagePublisher": "Canonical",
      "imageOffer": "UbuntuServer",
      "imageVersion": "16.04.0-LTS",
      "omsType": "OmsAgentForLinux"

    },
    "OMSSettings": "[variables(parameters('osType'))]"
  },
  "resources": [
    {
      "apiVersion": "[variables('storageApiVersion')]",
      "type": "Microsoft.Storage/storageAccounts",
      "name": "[variables('saVhdName')]",
      "location": "[variables('location')]",
      "sku": {
        "name": "[variables('storageAccountType')]"
      },
      "kind": "Storage",
      "properties": {}
    },
    {
      "apiVersion": "[variables('networkApiVersion')]",
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[variables('publicIPAddressName')]",
      "location": "[resourceGroup().location]",
      "properties": {
        "publicIPAllocationMethod": "Dynamic",
        "dnsSettings": {
          "domainNameLabel": "[parameters('dnsLabelPrefix')]"
        }
      }
    },
    {
      "apiVersion": "[variables('networkApiVersion')]",
      "type": "Microsoft.Network/virtualNetworks",
      "name": "[variables('virtualNetworkName')]",
      "location": "[resourceGroup().location]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('addressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[variables('subnetName')]",
            "properties": {
              "addressPrefix": "[variables('subnetPrefix')]"
            }
          }
        ]
      }
    },
    {
      "apiVersion": "[variables('networkApiVersion')]",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[variables('nicName')]",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
        "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
              },
              "subnet": {
                "id": "[variables('subnetRef')]"
              }
            }
          }
        ]
      }
    },
    {
      "apiVersion": "[variables('computeApiVersion')]",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[parameters('vmName')]",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[concat('Microsoft.Storage/storageAccounts/', variables('saVhdName'))]",
        "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[variables('vmSize')]"
        },
        "osProfile": {
          "computername": "[parameters('vmName')]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('OMSSettings').imagePublisher]",
            "offer": "[variables('OMSSettings').imageOffer]",
            "sku": "[variables('OMSSettings').imageVersion]",
            "version": "latest"
          },
          "osDisk": {
            "name": "osdisk",
            "vhd": {
              "uri": "[concat('http://', variables('saVhdName'), '.blob.core.windows.net/vhds/', concat(concat( parameters('vmName') ), '-osdisk.vhd'))]"
            },
            "caching": "ReadWrite",
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": "true",
            "storageUri": "[concat('http://', variables('saVhdName'), '.blob.core.windows.net')]"
          }
        }
      },
      "resources": [
        {
          "name": "Microsoft.EnterpriseCloud.Monitoring",
          "type": "extensions",
          "location": "[resourceGroup().location]",
          "apiVersion": "2015-06-15",
          "dependsOn": [
            "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]"
          ],
          "tags": {
            "displayName": "OMSEnroll"
          },
          "properties": {
            "publisher": "Microsoft.EnterpriseCloud.Monitoring",
            "type": "[variables('OMSSettings').omsType]",
            "typeHandlerVersion": "1.0",
            "autoUpgradeMinorVersion": true,
            "settings": {
              "workspaceId": "[parameters('workspaceId')]"
            },
            "protectedSettings": {
              "workspaceKey": "[parameters('workspaceKey')]"
            }
          }
        }
      ]
    }
  ]
  }

3. Enrolling VMs from the Azure Portal is very a very simple operation. You basically go to your Log Analytics resource located in your Azure subscription, select Virtual Machines and press connect on each virtual machine that shows the status “Not Connected”. The downside of doing it this way, is that if you have a lot of VMs that you want to enroll in your Log Analytics account, then it will take a lot of clicking.