Behandeln von Problemen mit dem Log Analytics-Agent für Windows

Dieser Artikel bietet Unterstützung bei der Problembehandlung von Fehlern, die beim Log Analytics-Agent für Windows in Azure Monitor auftreten können, und enthält mögliche Lösungen zum Beheben dieser Fehler.

Log Analytics-Problembehandlungstool

Das Problembehandlungstool für den Log Analytics-Agent für Windows ist eine Sammlung von PowerShell-Skripts für die Ermittlung und Diagnose von Problemen mit dem Log Analytics-Agent. Es ist bei der Installation des Agents automatisch enthalten. Das Ausführen des Tools sollte der erste Schritt bei der Diagnose eines Problems sein.

Verwenden des Tools zur Problembehandlung

  1. Öffnen Sie die PowerShell-Eingabeaufforderung als Administrator auf dem Computer, auf dem der Log Analytics-Agent installiert ist.

  2. Gehen Sie zu dem Verzeichnis, in dem sich das Tool befindet:

    cd "C:\Program Files\Microsoft Monitoring Agent\Agent\Troubleshooter"

  3. Führen Sie das Hauptskript mit diesem Befehl aus:

    .\GetAgentInfo.ps1

  4. Wählen Sie ein Problembehandlungsszenario aus.

  5. Befolgen Sie die Anweisungen an der Konsole. Beachten Sie, dass Ablaufverfolgungsprotokolle einen manuellen Eingriff erfordern, um die Protokollsammlung zu unterbrechen. Warten Sie je nach Reproduzierbarkeit des Problems die entsprechende Zeit ab, und wählen Sie „s“, um die Protokollerfassung anzuhalten und mit dem nächsten Schritt fortzufahren.

    Der Speicherort der Ergebnisdatei wird beim Abschluss protokolliert und in einem daraufhin geöffneten neuen Explorer-Fenster hervorgehoben.

Installation

Das Problembehandlungstool ist bei der Installation des Log Analytics-Agents ab Build 10.20.18053.0 automatisch enthalten.

Behandelte Szenarien

Das Problembehandlungstool überprüft die folgenden Szenarien:

  • Der Agent meldet keine Daten, oder es fehlen Heartbeat-Daten.
  • Die Bereitstellung der Agent-Erweiterung ist fehlgeschlagen.
  • Der Agent ist abgestürzt.
  • Der Agent verbraucht viel CPU oder Arbeitsspeicher.
  • Fehler bei der Installation und Deinstallation.
  • Bei benutzerdefinierten Protokollen sind Probleme aufgetreten.
  • Bei OMS-Gateway sind Probleme aufgetreten.
  • Bei Leistungsindikatoren sind Probleme aufgetreten.
  • Die Agent-Protokolle können nicht erfasst werden.

Hinweis

Führen Sie das Problembehandlungstool aus, wenn ein Problem auftritt. Wenn unserem Supportteam von Anfang an die Protokolle zur Verfügung stehen, lässt sich das Problem schneller beheben.

Wichtige Quellen für die Problembehandlung

Als Unterstützung bei der Behandlung von Problemen im Zusammenhang mit dem Log Analytics-Agent für Windows protokolliert der Agent Ereignisse im Windows-Ereignisprotokoll, insbesondere unter Anwendung und Dienste\Operations Manager.

Konnektivitätsprobleme

Wenn der Agent über einen Proxyserver oder eine Firewall kommuniziert, bestehen möglicherweise Einschränkungen, die die Kommunikation vom Quellcomputer und dem Azure Monitor-Dienst verhindern. Sollte die Kommunikation aufgrund einer Fehlkonfiguration blockiert sein, ist die Registrierung bei einem Arbeitsbereich möglicherweise nicht erfolgreich, wenn versucht wird, den Agent zu installieren oder ihn nach der Einrichtung so zu konfigurieren, dass Meldungen an einen anderen Arbeitsbereich übermittelt werden. Bei der Agent-Kommunikation könnten nach erfolgreicher Registrierung Fehler auftreten. In diesem Abschnitt werden die Methoden zur Behandlung dieser Art von Problemen beim Windows-Agent beschrieben.

Vergewissern Sie sich, dass die Firewall oder der Proxy so konfiguriert ist, dass die in der folgenden Tabelle beschriebenen Ports und URLs zulässig sind. Vergewissern Sie sich auch, dass die HTTP-Inspektion für den Webdatenverkehr nicht aktiviert ist. Dadurch kann ein sicherer TLS-Kanal zwischen dem Agent und Azure Monitor verhindert werden.

Agent-Ressource Ports Direction Umgehung der HTTPS-Inspektion
*.ods.opinsights.azure.com Port 443 Ausgehend Ja
*.oms.opinsights.azure.com Port 443 Ausgehend Ja
*.blob.core.windows.net Port 443 Ausgehend Ja
*.agentsvc.azure-automation.net Port 443 Ausgehend Ja

Informationen zur Firewall, die für Azure Government erforderlich sind, finden Sie unter Azure Government-Verwaltung. Wenn Sie den Azure Automation Hybrid Runbook Worker zum Herstellen einer Verbindung mit dem Automatisierungsdienst bzw. die Registrierung bei diesem nutzen möchten, um Runbooks oder Verwaltungslösungen in Ihrer Umgebung zu verwenden, muss dieser Zugriff auf die Portnummer und die unter Konfigurieren Ihres Netzwerks für den Hybrid Runbook Worker beschriebenen URLs besitzen.

Es gibt mehrere Möglichkeiten zur Überprüfung, ob der Agent erfolgreich mit Azure Monitor kommuniziert:

  • Aktivieren Sie die Integritätsbewertung des Azure Log Analytics-Agents im Arbeitsbereich. Sehen Sie sich im Dashboard für die Agent-Integritätsdiagnose die Spalte Anzahl der nicht reagierenden Agents an, um schnell festzustellen, ob der Agent aufgeführt ist.

  • Führen Sie die folgende Abfrage aus, um sicherzustellen, dass der Agent einen Heartbeat an den Arbeitsbereich sendet, an den er gemäß der Konfiguration berichten soll. Ersetzen Sie <ComputerName> durch den tatsächlichen Namen des Computers.

    Heartbeat 
    | where Computer like "<ComputerName>"
    | summarize arg_max(TimeGenerated, * ) by Computer 
    

    Wenn der Computer erfolgreich mit dem Dienst kommuniziert, sollte die Abfrage ein Ergebnis zurückgeben. Hat die Abfrage kein Ergebnis zurückgegeben, stellen Sie zunächst sicher, dass der Agent für das Berichten an den richtigen Arbeitsbereich konfiguriert ist. Ist er richtig konfiguriert, fahren Sie mit Schritt 3 fort und durchsuchen Sie das Windows-Ereignisprotokoll, um festzustellen, ob der Agent das Problem protokolliert, das ihn möglicherweise daran hindert, mit Azure Monitor zu kommunizieren.

  • Eine weitere Methode zur Erkennung eines Konnektivitätsproblems ist das Ausführen des TestCloudConnectivity-Tools. Das Tool wird standardmäßig mit dem Agent im Ordner %SystemRoot%\Program Files\Microsoft Monitoring Agent\Agent installiert. Wechseln Sie an einer Eingabeaufforderung mit erhöhten Rechten zum Ordner und führen Sie das Tool aus. Das Tool gibt die Ergebnisse zurück und hebt hervor, wo Fehler im Test aufgetreten sind. Vielleicht war es beispielsweise mit einem bestimmten Port oder einer bestimmten URL verknüpft, die blockiert wurde.

    Screenshot, der Ausführungsergebnisse des TestCloudConnection-Tools anzeigt.

  • Filtern Sie das Operations Manager-Ereignisprotokoll nach Ereignisquellen Integritätsdienstmodule, Integritätsdienst und Dienstconnector, und filtern Sie nach der Ereignisebene Warnung und Fehler, um zu überprüfen, ob Ereignisse geschrieben wurden, die in der folgenden Tabelle aufgeführt sind. Wenn dies der Fall ist, sehen Sie sich die Lösungsschritte für jedes mögliche Ereignis an.

    Ereignis-ID `Source` BESCHREIBUNG Lösung
    2133 und 2129 Integritätsdienst Fehler bei der Verbindung des Agents mit dem Dienst. Dieser Fehler kann auftreten, wenn der Agent nicht direkt oder über eine Firewall oder einen Proxyserver mit dem Azure Monitor-Dienst kommunizieren kann. Überprüfen Sie die Proxyeinstellungen des Agents, und stellen Sie sicher, dass die Netzwerkfirewall oder der Netzwerkproxy den TCP-Datenverkehr vom Computer zum Dienst zulässt.
    2138 Integritätsdienstmodule Proxy erfordert Authentifizierung. Konfigurieren Sie die Proxyeinstellungen des Agents, und geben Sie den erforderlichen Benutzernamen und das Kennwort für die Authentifizierung beim Proxyserver an.
    2129 Integritätsdienstmodule Fehler bei der Verbindung. Fehler bei der TLS-Aushandlung. Überprüfen Sie die TCP/IP-Einstellungen des Netzwerkadapters und die Proxyeinstellungen des Agents.
    2127 Integritätsdienstmodule Fehler beim Senden des Daten empfangen-Fehlercodes. Wenn dies im Laufe des Tages nur zeitweilig auftritt, kann es sich um eine zufällige Anomalie handeln, die ignoriert werden kann. Überwachen Sie dieses Verhalten, um festzustellen, wie häufig dieser Fehler auftritt. Tritt er im Laufe des Tages häufig auf, überprüfen Sie zunächst Ihre Netzwerkkonfiguration und die Proxyeinstellungen. Wenn die Beschreibung HTTP-Fehlercode 404 enthält und der Agent zum ersten Mal versucht, Daten an den Dienst zu senden, ist ein Fehlercode 500 mit einem internen Fehlercode 404 enthalten. Der Fehlercode 404 bedeutet „nicht gefunden“ und gibt an, dass der Speicherbereich für den neuen Arbeitsbereich weiterhin bereitgestellt wird. Bei der nächsten Wiederholung werden Daten wie erwartet erfolgreich in den Arbeitsbereich geschrieben. Ein HTTP-Fehler 403 weist möglicherweise auf ein Problem mit Berechtigungen oder Anmeldeinformationen hin. Der Fehler 403 enthält weitere Informationen, die bei der Problembehandlung helfen.
    4000 Dienstconnector Fehler bei der DNS-Namensauflösung. Der Computer konnte die Internetadresse, die beim Senden von Daten an den Dienst verwendet wurde, nicht auflösen. Dieses Problem kann an den Einstellungen der DNS-Auflösung auf Ihrem Computer, falschen Proxyeinstellungen oder an einem vorübergehenden DNS-Problem bei Ihrem Anbieter liegen. Wenn dieses Problem zeitweilig auftritt, kann es durch ein vorübergehendes Netzwerkproblem verursacht werden.
    4001 Dienstconnector Fehler bei der Verbindung mit dem Dienst Dieser Fehler kann auftreten, wenn der Agent nicht direkt oder über eine Firewall oder einen Proxyserver mit dem Azure Monitor-Dienst kommunizieren kann. Überprüfen Sie die Proxyeinstellungen des Agents, und stellen Sie sicher, dass die Netzwerkfirewall oder der Netzwerkproxy den TCP-Datenverkehr vom Computer zum Dienst zulässt.
    4002 Dienstconnector Der Dienst hat HTTP-Statuscode 403 als Antwort auf eine Abfrage zurückgegeben. Wenden Sie sich an den Dienstadministrator, um die Integrität des Diensts zu prüfen. Die Abfrage wird später wiederholt. Dieser Fehler wird während der anfänglichen Registrierungsphase des Agents geschrieben. Es wird eine URL angezeigt, die https://<workspaceID>.oms.opinsights.azure.com/AgentService.svc/AgentTopologyRequest ähnelt. Ein Fehlercode 403 bedeutet „verboten“ und kann durch eine falsch eingegebene Arbeitsbereichs-ID oder einen falschen Schlüssel verursacht werden. Das Datum und die Uhrzeit auf dem Computer könnten ebenfalls falsch sein. Wenn die Zeit ca. 15 Minuten von der aktuellen Uhrzeit abweicht, tritt beim Onboarding ein Fehler auf. Aktualisieren Sie zur Behebung dieses Problems das Datum und/oder die Zeitzone Ihres Windows-Computers.

Datensammlungsprobleme

Nachdem der Agent installiert wurde und Berichte an den konfigurierten Arbeitsbereich bzw. die Arbeitsbereiche sendet, könnte das Empfangen der Konfiguration sowie das Sammeln oder Weiterleiten von Leistung, Protokollen oder anderen Daten an den Dienst (je nachdem, was aktiviert ist und den Computer als Ziel hat) beendet werden. Sie müssen Folgendes festlegen:

  • Handelt es sich um einen bestimmten Datentyp oder sind keinerlei Daten im Arbeitsbereich verfügbar?
  • Wird der Datentyp von einer Lösung oder als Teil der Datensammlungskonfiguration des Arbeitsbereichs angegeben?
  • Wie viele Computer sind betroffen? Sendet ein einzelner Computer oder senden mehrere Computer Berichte an den Arbeitsbereich?
  • War er aktiv und hat er zu einem bestimmten Zeitpunkt des Tages aufgehört, oder wurden noch nie Daten gesammelt?
  • Weist die verwendete Protokollsuchabfrage die korrekte Syntax auf?
  • Hat der Agent jemals seine Konfiguration von Azure Monitor empfangen?

Als erster Schritt bei der Problembehandlung muss festgestellt werden, ob der Computer ein Heartbeat-Ereignis sendet.

Heartbeat 
    | where Computer like "<ComputerName>"
    | summarize arg_max(TimeGenerated, * ) by Computer

Wenn die Abfrage Ergebnisse zurückgibt, müssen Sie ermitteln, ob ein bestimmter Datentyp nicht erfasst und an den Dienst weitergeleitet wird. Dieses Problem kann dadurch verursacht werden, dass der Agent keine aktualisierte Konfiguration vom Dienst erhält, oder durch ein anderes Symptom, das den normalen Betrieb des Agents verhindert. Führen Sie zur weiteren Problembehandlung die folgenden Schritte aus.

  1. Öffnen Sie auf dem Computer eine Eingabeaufforderung mit erhöhten Rechten und starten Sie den Agent-Dienst durch Eingabe von net stop healthservice && net start healthservice neu.

  2. Öffnen Sie das Operations Manager-Ereignisprotokoll, und suchen Sie nach den Ereignis-IDs 7023, 7024, 7025, 7028 und 1210 aus der Ereignisquelle Integritätsdienst. Diese Ereignisse geben an, dass der Agent die Konfiguration von Azure Monitor erfolgreich empfängt und der Computer aktiv überwacht wird. In der Beschreibung für Ereignis-ID 1210 werden außerdem in der letzten Zeile alle Lösungen und Insights angegeben, die im Umfang der Überwachung auf dem Agent enthalten sind.

    Screenshot mit einer Beschreibung der Ereignis-ID 1210.

  3. Warten Sie einige Minuten. Wenn die erwarteten Daten in den Abfrageergebnissen oder der Visualisierung nicht angezeigt werden (je nachdem, ob Sie die Daten aus einer Lösung oder Insight anzeigen), suchen Sie im Ereignisprotokoll Operations Manager nach den Ereignisquellen Integritätsdienst und Integritätsdienstmodulen. Filtern Sie nach der Ereignisebene Warnung und Fehler, um zu überprüfen, ob Ereignisse geschrieben wurden, die in der folgenden Tabelle aufgeführt sind.

    Ereignis-ID `Source` BESCHREIBUNG Lösung
    8.000 Integritätsdienst Dieses Ereignis gibt an, ob ein Workflow im Zusammenhang mit der Leistung, ein Ereignis oder ein anderer gesammelter Datentyp nicht zur Erfassung im Arbeitsbereich an den Dienst weitergeleitet werden kann. Die Ereignis-ID 2136 aus der Quelle HealthService wird zusammen mit diesem Ereignis geschrieben und kann angeben, dass der Agent nicht mit dem Dienst kommunizieren kann. Mögliche Gründe dafür könnte eine falsche Konfiguration der Proxy- und Authentifizierungseinstellungen, ein Netzwerkausfall oder dass die Netzwerkfirewall oder der Netzwerkproxy keinen TCP-Datenverkehr vom Computer zum Dienst zulässt.
    10102 und 10103 Integritätsdienstmodule Der Workflow konnte die Datenquelle nicht auflösen. Dieses Problem kann auftreten, wenn der angegebene Leistungsindikator oder die Instanz auf dem Computer nicht vorhanden oder in den Einstellungen des Arbeitsbereichs falsch definiert ist. Wenn es sich um einen vom Benutzer angegebenen Leistungsindikator handelt, überprüfen Sie, ob die angegebenen Informationen dem richtigen Format entsprechen und auf den Zielcomputern vorhanden sind.
    26002 Integritätsdienstmodule Der Workflow konnte die Datenquelle nicht auflösen. Dieses Problem kann auftreten, wenn das angegebene Windows-Ereignisprotokoll auf dem Computer nicht vorhanden ist. Dieser Fehler kann problemlos ignoriert werden, wenn der Computer dieses Ereignisprotokoll nicht registrieren soll. Wenn dies ein vom Benutzer angegebenes Ereignisprotokoll ist, überprüfen Sie andernfalls, ob die angegebenen Informationen korrekt sind.

Probleme mit angehefteten Zertifikaten mit älteren Microsoft Monitoring Agents – Breaking Change

Übersicht über Änderungen im Zusammenhang mit der Stammzertifizierungsstelle

Ab dem 30. Juni 2023 akzeptiert das Log Analytics-Backend keine Verbindungen mehr von Microsoft Monitoring Agent (MMA), die auf ein veraltetes Stammzertifikat verweisen. Bei diesen MMAs handelt es sich um ältere Versionen vor dem Release im Winter 2020 (Log Analytics Agent) und vor SCOM 2019 UR3 (SCOM). Jede Version, Bundle: 10.20.18053/Erweiterung: 1.0.18053.0 oder höher, hat keine Probleme sowie jede Version oberhalb von SCOM 2019 UR3. Jeder Agent, der älter ist, wird unterbrochen und funktioniert nicht mehr und lädt nicht mehr in Log Analytics hoch.

Was genau ändert sich?

Im Rahmen einer laufenden Sicherheitsanstrengung für verschiedene Azure-Dienste wechselt Azure Log Analytics offiziell vom Baltimore CyberTrust-Stammzertifizierungsstellen-Stammzertifikat zum DigiCert Global G2-Stammzertifizierungsstellen-Stammzertifikat. Diese Änderung wirkt sich auf die TLS-Kommunikation mit Log Analytics aus, wenn das neue DigiCert Global G2-Zertifizierungsstellen-Stammzertifikat im Betriebssystem fehlt oder die Anwendung auf die alte Baltimore-Stammzertifizierungsstelle verweist. Dies bedeutet, dass Log Analytics keine Verbindungen von MMA mehr akzeptiert, die diese alte Stammzertifizierungsstelle verwenden, nachdem sie eingestellt wurde.

Lösungsprodukte

Möglicherweise haben Sie die Breaking Change-Benachrichtigung erhalten, auch wenn Sie den Microsoft Monitoring Agent nicht persönlich installiert haben. Das liegt daran, dass verschiedene Azure-Produkte den Microsoft Monitoring Agent nutzen. Wenn Sie eines dieser Produkte verwenden, sind Sie möglicherweise betroffen, da sie den Log Analytics-Agent unter Windows nutzen. Für diese Produkte mit den folgenden Links gibt es möglicherweise spezifische Anweisungen, die erfordern, dass Sie ein Upgrade auf den neuesten Agent durchführen müssen.

Identifizieren und Beheben von Breaking Agents

Für Bereitstellungen mit einer begrenzten Anzahl von Agents wird dringend empfohlen, ein Upgrade Ihres Agent pro Knoten über diese Verwaltungsanweisungen durchzuführen.

Für Bereitstellungen mit mehreren Knoten haben wir ein Skript geschrieben, das alle betroffenen Breaking MMAs pro Abonnement erkennt und anschließend ein Upgrade auf die neueste Version durchführt. Diese Skripts müssen sequenziell ausgeführt werden, beginnend mit UpdateMMA.ps1 und dann UpgradeMMA.ps1. Je nach Computer kann das Skript eine Weile dauern. PowerShell 7 oder höher ist für die Ausführung erforderlich, um eine Zeitüberschreitung zu vermeiden.

UpdateMMA.ps1 Dieses Skript durchläuft virtuelle Computer in Ihren Abonnements, überprüft, ob vorhandene MMAs installiert sind, und generiert dann eine CSV-Datei mit Agents, für die ein Upgrade durchgeführt werden muss.

UpgradeMMA.ps1 Dieses Skript verwendet die in UpdateMMA.ps1 generierte CSV-Datei, um ein Upgrade aller Breaking MMAs durchzuführen.

Beide Skripts können eine Weile dauern.

# UpdateMMA.ps1
# This script is to be run per subscription, the customer has to set the az subscription before running this within the terminal scope.
# This script uses parallel processing, modify the $parallelThrottleLimit parameter to either increase or decrease the number of parallel processes
# PS> .\UpdateMMA.ps1 GetInventory
# The above command will generate a csv file with the details of VM's and VMSS that require MMA upgrade. 
# The customer can modify the csv by adding/removing rows if needed
# Update the MMA by running the script again and passing the csv file as parameter as shown below:
# PS> .\UpdateMMA.ps1 Upgrade
# If you don't want to check the inventory, then run the script wiht an additional -no-inventory-check
# PS> .\UpdateMMA.ps1 GetInventory & .\UpdateMMA.ps1 Upgrade


# This version of the script requires Powershell version >= 7 in order to improve performance via ForEach-Object -Parallel
# https://docs.microsoft.com/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.1
if ($PSVersionTable.PSVersion.Major -lt 7) 
{
    Write-Host "This script requires Powershell version 7 or newer to run. Please see https://docs.microsoft.com/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.1."
    exit 1
}

$parallelThrottleLimit = 16
$mmaFixVersion = [version]"10.20.18053.0"

function GetVmsWithMMAInstalled
{
    param(
        $fileName
    )

    $vmList = az vm list --show-details --query "[?powerState=='VM running'].{ResourceGroup:resourceGroup, VmName:name}" | ConvertFrom-Json
    
    if(!$vmList)
    {
        Write-Host "Cannot get the VM list, this script can only detect the running VM's"
        return
    }

    $vmsCount = $vmList.Length
    
    $vmParallelThrottleLimit = $parallelThrottleLimit
    if ($vmsCount -lt $vmParallelThrottleLimit) 
    {
        $vmParallelThrottleLimit = $vmsCount
    }

    if($vmsCount -eq 1)
    {
        $vmGroups += ,($vmList[0])
    }
    else
    {
        # split the vm's into batches to do parallel processing
        for ($i = 0; $i -lt $vmsCount; $i += $vmParallelThrottleLimit) 
        { 
            $vmGroups += , ($vmList[$i..($i + $vmParallelThrottleLimit - 1)]) 
        }
    }

    Write-Host "Detected $vmsCount Vm's running in this subscription."
    $hash = [hashtable]::Synchronized(@{})
    $hash.One = 1

    $vmGroups | Foreach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $len = $using:vmsCount
        $hash = $using:hash
        $_ | ForEach-Object {
            $percent = 100 * $hash.One++ / $len
            Write-Progress -Activity "Getting VM Inventory" -PercentComplete $percent
            $vmName = $_.VmName
            $resourceGroup = $_.ResourceGroup
            $responseJson = az vm run-command invoke --command-id RunPowerShellScript --name $vmName -g $resourceGroup --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
            if($responseJson)
            {
                $mmaVersion = $responseJson.Value[0].message
                if ($mmaVersion) 
                {
                    $extensionName = az vm extension list -g $resourceGroup --vm-name $vmName --query "[?name == 'MicrosoftMonitoringAgent'].name" | ConvertFrom-Json
                    if ($extensionName) 
                    {
                        $installType = "Extension"
                    }
                    else 
                    {
                        $installType = "Installer"
                    }
                    $csvObj = New-Object -TypeName PSObject -Property @{
                        'Name'           = $vmName
                        'Resource_Group' = $resourceGroup
                        'Resource_Type'  = "VM"
                        'Install_Type'   = $installType
                        'Version'        = $mmaVersion
                        "Instance_Id"    = ""
                    }
                    $csvObj | Export-Csv $using:fileName -Append -Force
                } 
            } 
        }
    }
}

function GetVmssWithMMAInstalled
{
    param(
        $fileName
    )

    # get the vmss list which are successfully provisioned
    $vmssList = az vmss list --query "[?provisioningState=='Succeeded'].{ResourceGroup:resourceGroup, VmssName:name}" | ConvertFrom-Json   

    $vmssCount = $vmssList.Length
    Write-Host "Detected $vmssCount Vmss running in this subscription."
    $hash = [hashtable]::Synchronized(@{})
    $hash.One = 1

    $vmssList | Foreach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $len = $using:vmssCount
        $hash = $using:hash
        $percent = 100 * $hash.One++ / $len
        Write-Progress -Activity "Getting VMSS Inventory" -PercentComplete $percent
        $vmssName = $_.VmssName
        $resourceGroup = $_.ResourceGroup

        # get running vmss instance ids
        $vmssInstanceIds = az vmss list-instances --resource-group $resourceGroup --name $vmssName --expand instanceView --query "[?instanceView.statuses[1].displayStatus=='VM running'].instanceId" | ConvertFrom-Json
        if ($vmssInstanceIds.Length -gt 0) 
        {
            $isMMAExtensionInstalled = az vmss extension list -g $resourceGroup --vmss-name $vmssName --query "[?name == 'MicrosoftMonitoringAgent'].name" | ConvertFrom-Json
            if ($isMMAExtensionInstalled ) 
            {
                # check an instance in vmss, if it needs an MMA upgrade. Since the extension is installed at VMSS level, checking for bad version in 1 instance should be fine.
                $responseJson = az vmss run-command invoke --command-id RunPowerShellScript --name $vmssName -g $resourceGroup --instance-id $vmssInstanceIds[0] --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
                $mmaVersion = $responseJson.Value[0].message
                if ($mmaVersion) 
                {
                    $csvObj = New-Object -TypeName PSObject -Property @{
                        'Name'           = $vmssName
                        'Resource_Group' = $resourceGroup
                        'Resource_Type'  = "VMSS"
                        'Install_Type'   = "Extension"
                        'Version'        = $mmaVersion
                        "Instance_Id"    = ""
                    }
                    $csvObj | Export-Csv $using:fileName -Append -Force
                }
            }
            else 
            {
                foreach ($instanceId in $vmssInstanceIds) 
                {
                    $responseJson = az vmss run-command invoke --command-id RunPowerShellScript --name $vmssName -g $resourceGroup --instance-id $instanceId --scripts '@UpgradeMMA.ps1' --parameters "functionName=GetMMAVersion" --output json | ConvertFrom-Json
                    $mmaVersion = $responseJson.Value[0].message
                    if ($mmaVersion) 
                    {
                        $csvObj = New-Object -TypeName PSObject -Property @{
                            'Name'           = $vmssName
                            'Resource_Group' = $resourceGroup
                            'Resource_Type'  = "VMSS"
                            'Install_Type'   = "Installer"
                            'Version'        = $mmaVersion
                            "Instance_Id"    = $instanceId
                        }
                        $csvObj | Export-Csv $using:fileName -Append -Force
                    }
                }
            }
        }      
    }
}

function Upgrade
{
    param(
        $fileName = "MMAInventory.csv"
    )
    Import-Csv $fileName | ForEach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $mmaVersion = [version]$_.Version
        if($mmaVersion -lt $using:mmaFixVersion)
        {
            if ($_.Install_Type -eq "Extension") 
            {
                if ($_.Resource_Type -eq "VMSS") 
                {
                    # if the extension is installed with a custom name, provide the name using the flag: --extension-instance-name <extension name>
                    az vmss extension set --name MicrosoftMonitoringAgent --publisher Microsoft.EnterpriseCloud.Monitoring --force-update --vmss-name $_.Name --resource-group $_.Resource_Group --no-wait --output none
                }
                else 
                {
                    # if the extension is installed with a custom name, provide the name using the flag: --extension-instance-name <extension name>
                    az vm extension set --name MicrosoftMonitoringAgent --publisher Microsoft.EnterpriseCloud.Monitoring --force-update --vm-name $_.Name --resource-group $_.Resource_Group --no-wait --output none
                }
            }
            else {
                if ($_.Resource_Type -eq "VMSS") 
                {
                    az vmss run-command invoke --command-id RunPowerShellScript --name $_.Name -g $_.Resource_Group --instance-id $_.Instance_Id --scripts '@UpgradeMMA.ps1' --parameters "functionName=UpgradeMMA" --output none
                }
                else 
                {
                    az vm run-command invoke --command-id RunPowerShellScript --name $_.Name -g $_.Resource_Group --scripts '@UpgradeMMA.ps1' --parameters "functionName=UpgradeMMA" --output none
                }
            }
        }
    }
}

function GetInventory
{
    param(
        $fileName = "MMAInventory.csv"
    )

    # create a new file 
    New-Item -Name $fileName -ItemType File -Force
    GetVmsWithMMAInstalled $fileName
    GetVmssWithMMAInstalled $fileName
}

switch ($args.Count)
{
    0 {
        Write-Host "The arguments provided are incorrect."
        Write-Host "To get the Inventory: Run the script as: PS> .\UpdateMMA.ps1 GetInventory"
        Write-Host "To update MMA from Inventory: Run the script as: PS> .\UpdateMMA.ps1 Upgrade"
        Write-Host "To do the both steps together: PS> .\UpdateMMA.ps1 GetInventory & .\UpdateMMA.ps1 Upgrade"
    }
    1 {
        $funcname = $args[0]
        Invoke-Expression "& $funcname"
    }
    2 {
        $funcname = $args[0]
        $funcargs = $args[1]
        Invoke-Expression "& $funcname $funcargs"
    }
}