Rozwiązywanie problemów z agentem usługi Log Analytics dla systemu Windows

Ten artykuł zawiera pomoc w rozwiązywaniu problemów z błędami, które mogą wystąpić w przypadku agenta usługi Log Analytics dla systemu Windows w usłudze Azure Monitor i sugeruje możliwe rozwiązania ich rozwiązywania.

Narzędzie do rozwiązywania problemów z usługą Log Analytics

Agent usługi Log Analytics dla narzędzia do rozwiązywania problemów z systemem Windows to kolekcja skryptów programu PowerShell, które ułatwiają znajdowanie i diagnozowanie problemów z agentem usługi Log Analytics. Jest on automatycznie dołączany do agenta podczas instalacji. Uruchomienie narzędzia powinno być pierwszym krokiem w diagnozowaniu problemu.

Korzystanie z narzędzia do rozwiązywania problemów

  1. Otwórz wiersz polecenia programu PowerShell jako administrator na maszynie, na której zainstalowano agenta usługi Log Analytics.

  2. Przejdź do katalogu, w którym znajduje się narzędzie:

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

  3. Wykonaj skrypt główny przy użyciu tego polecenia:

    .\GetAgentInfo.ps1

  4. Wybierz scenariusz rozwiązywania problemów.

  5. Postępuj zgodnie z instrukcjami w konsoli programu . Należy pamiętać, że kroki śledzenia dzienników wymagają ręcznej interwencji w celu zatrzymania zbierania dzienników. Na podstawie powtarzalności problemu poczekaj na czas trwania i wybierz pozycję "s", aby zatrzymać zbieranie dzienników i przejść do następnego kroku.

    Lokalizacja pliku wyników jest rejestrowana po zakończeniu i jest otwierane nowe okno eksploratora.

Instalacja

Narzędzie do rozwiązywania problemów jest automatycznie uwzględniane podczas instalacji agenta usługi Log Analytics w wersji 10.20.18053.0 i nowszej.

Objęte scenariusze

Narzędzie do rozwiązywania problemów sprawdza następujące scenariusze:

  • Agent nie zgłasza danych ani brakuje danych pulsu.
  • Wdrożenie rozszerzenia agenta kończy się niepowodzeniem.
  • Agent ulega awarii.
  • Agent zużywa wysokie użycie procesora CPU lub pamięci.
  • Błędy instalacji i dezinstalacji.
  • Dzienniki niestandardowe mają problemy.
  • Brama pakietu OMS ma problemy.
  • Liczniki wydajności mają problemy.
  • Nie można zbierać dzienników agentów.

Uwaga

Uruchom narzędzie do rozwiązywania problemów, gdy wystąpi problem. Pierwsze dzienniki pomogą naszemu zespołowi pomocy technicznej w szybszym rozwiązywaniu problemu.

Ważne źródła rozwiązywania problemów

Aby ułatwić rozwiązywanie problemów związanych z agentem usługi Log Analytics dla systemu Windows, agent rejestruje zdarzenia w dzienniku zdarzeń systemu Windows, w szczególności w obszarze Aplikacja i usługi\Operations Manager.

Problemy z połączeniem

Jeśli agent komunikuje się za pośrednictwem serwera proxy lub zapory, ograniczenia mogą uniemożliwiać komunikację z komputera źródłowego i usługi Azure Monitor. Jeśli komunikacja jest zablokowana z powodu nieprawidłowej konfiguracji, rejestracja w obszarze roboczym może zakończyć się niepowodzeniem podczas próby zainstalowania agenta lub skonfigurowania agenta po konfiguracji w celu raportowania do innego obszaru roboczego. Komunikacja agenta może zakończyć się niepowodzeniem po pomyślnej rejestracji. W tej sekcji opisano metody rozwiązywania tego typu problemów z agentem systemu Windows.

Sprawdź dokładnie, czy zapora lub serwer proxy jest skonfigurowana tak, aby zezwalała na następujące porty i adresy URL opisane w poniższej tabeli. Upewnij się również, że inspekcja HTTP nie jest włączona dla ruchu internetowego. Może to uniemożliwić bezpieczny kanał TLS między agentem a usługą Azure Monitor.

Zasób agenta Porty Kierunek Pomijanie inspekcji HTTPS
*.ods.opinsights.azure.com Port 443 Wychodzące Tak
*.oms.opinsights.azure.com Port 443 Wychodzące Tak
*.blob.core.windows.net Port 443 Wychodzące Tak
*.agentsvc.azure-automation.net Port 443 Wychodzące Tak

Aby uzyskać informacje o zaporze wymagane dla platformy Azure Government, zobacz Zarządzanie platformą Azure Government. Jeśli planujesz używać hybrydowego procesu roboczego elementu Runbook usługi Azure Automation do nawiązywania połączenia z usługą Automation w celu korzystania z elementów Runbook lub rozwiązań do zarządzania w danym środowisku, musi mieć dostęp do numeru portu i adresów URL opisanych w temacie Konfigurowanie sieci dla hybrydowego procesu roboczego elementu Runbook.

Istnieje kilka sposobów sprawdzania, czy agent pomyślnie komunikuje się z usługą Azure Monitor:

  • Włącz ocenę kondycji agenta usługi Azure Log Analytics w obszarze roboczym. Na pulpicie nawigacyjnym Kondycja agenta wyświetl kolumnę Liczba nieodpowiadających agentów , aby szybko sprawdzić, czy agent jest wymieniony.

  • Uruchom następujące zapytanie, aby potwierdzić, że agent wysyła puls do obszaru roboczego skonfigurowanego do raportowania. Zastąp <ComputerName> wartość rzeczywistą nazwą maszyny.

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

    Jeśli komputer pomyślnie komunikuje się z usługą, zapytanie powinno zwrócić wynik. Jeśli zapytanie nie zwróciło wyniku, najpierw sprawdź, czy agent jest skonfigurowany do raportowania do poprawnego obszaru roboczego. Jeśli jest poprawnie skonfigurowany, przejdź do kroku 3 i wyszukaj dziennik zdarzeń systemu Windows, aby sprawdzić, czy agent rejestruje problem, który może uniemożliwić komunikację z usługą Azure Monitor.

  • Inną metodą identyfikowania problemu z łącznością jest uruchomienie narzędzia TestCloud Połączenie ivity. Narzędzie jest instalowane domyślnie z agentem w folderze %SystemRoot%\Program Files\Microsoft Monitoring Agent\Agent. W wierszu polecenia z podwyższonym poziomem uprawnień przejdź do folderu i uruchom narzędzie. Narzędzie zwróci wyniki i wskaże, gdzie test nie powiódł się. Na przykład być może był on związany z określonym portem lub adresem URL, który został zablokowany.

    Screenshot that shows TestCloudConnection tool execution results.

  • Filtruj dziennik zdarzeń programu Operations Manager według źródeł zdarzeń Usługa kondycji Moduły, HealthService i Service Połączenie or oraz filtruj według ostrzeżenia i błędu poziomuzdarzeń, aby potwierdzić, czy zostały zapisane zdarzenia z poniższej tabeli. Jeśli tak jest, zapoznaj się z krokami rozwiązywania uwzględnionych dla każdego możliwego zdarzenia.

    Identyfikator zdarzenia Lokalizacja źródłowa opis Rozwiązanie
    2133 & 2129 Health Service (Usługa kondycji) Połączenie do usługi z agenta nie powiodło się. Ten błąd może wystąpić, gdy agent nie może komunikować się bezpośrednio lub przez zaporę lub serwer proxy do usługi Azure Monitor. Sprawdź ustawienia serwera proxy agenta lub czy zapora sieciowa lub serwer proxy zezwala na ruch TCP z komputera do usługi.
    2138 moduły Usługa kondycji Serwer proxy wymaga uwierzytelniania. Skonfiguruj ustawienia serwera proxy agenta i określ nazwę użytkownika/hasło wymagane do uwierzytelnienia na serwerze proxy.
    2129 moduły Usługa kondycji Połączenie nie powiodło się. Nie można negocjować protokołu TLS. Sprawdź ustawienia protokołu TCP/IP karty sieciowej i ustawienia serwera proxy agenta.
    2127 moduły Usługa kondycji Błąd podczas wysyłania danych odebrano kod błędu. Jeśli dzieje się to okresowo w ciągu dnia, może to być przypadkowa anomalia, którą można zignorować. Monitoruj, aby zrozumieć, jak często się dzieje. Jeśli dzieje się to często przez cały dzień, najpierw sprawdź konfigurację sieci i ustawienia serwera proxy. Jeśli opis zawiera kod błędu HTTP 404 i po raz pierwszy agent próbuje wysłać dane do usługi, będzie zawierać błąd 500 z wewnętrznym kodem błędu 404. Kod błędu 404 oznacza "nie znaleziono", co oznacza, że obszar magazynowania dla nowego obszaru roboczego jest nadal aprowizowany. Po następnej próbie dane zostaną pomyślnie zapisane w obszarze roboczym zgodnie z oczekiwaniami. Błąd HTTP 403 może wskazywać na problem z uprawnieniami lub poświadczeniami. Więcej informacji zawiera błąd 403, aby pomóc w rozwiązaniu problemu.
    4000 Łącznik usługi Rozpoznawanie nazw DNS nie powiodło się. Maszyna nie może rozpoznać adresu internetowego używanego podczas wysyłania danych do usługi. Ten problem może dotyczyć ustawień programu rozpoznawania nazw DNS na maszynie, nieprawidłowych ustawień serwera proxy lub tymczasowego problemu z systemem DNS u dostawcy. Jeśli występuje okresowo, może to być spowodowane przejściowym problemem związanym z siecią.
    4001 Łącznik usługi Połączenie do usługi nie powiodło się. Ten błąd może wystąpić, gdy agent nie może komunikować się bezpośrednio lub przez zaporę lub serwer proxy do usługi Azure Monitor. Sprawdź ustawienia serwera proxy agenta lub czy zapora sieciowa lub serwer proxy zezwala na ruch TCP z komputera do usługi.
    4002 Łącznik usługi Usługa zwróciła kod stanu HTTP 403 w odpowiedzi na zapytanie. Zapoznaj się z administratorem usługi pod kątem kondycji usługi. Zapytanie zostanie ponowione później. Ten błąd jest zapisywany podczas początkowej fazy rejestracji agenta. Zobaczysz adres URL podobny do https:// workspaceID.oms.opinsights.azure.com/AgentService.svc/AgentTopologyRequest>.< Kod błędu 403 oznacza "zabronione" i może być spowodowany błędnie wtypowanym identyfikatorem lub kluczem obszaru roboczego. Data i godzina mogą być również niepoprawne na komputerze. Jeśli czas wynosi +/- 15 minut od bieżącego czasu, dołączanie kończy się niepowodzeniem. Aby rozwiązać ten problem, zaktualizuj datę i/lub godzinę komputera z systemem Windows.

Problemy z zbieraniem danych

Po zainstalowaniu agenta i przekazaniu raportów do skonfigurowanego obszaru roboczego lub obszarów roboczych może zatrzymać odbieranie konfiguracji i zbieranie lub przekazywanie wydajności, dzienników lub innych danych do usługi w zależności od tego, co jest włączone i przeznaczone dla komputera. Musisz określić:

  • Czy jest to określony typ danych, czy wszystkie dane, które nie są dostępne w obszarze roboczym?
  • Czy typ danych jest określony przez rozwiązanie, czy określony jako część konfiguracji zbierania danych obszaru roboczego?
  • Ilu komputerów dotyczy problem? Czy jest to jeden komputer, czy wiele komputerów raportujących do obszaru roboczego?
  • Czy to działało i czy zatrzymało się o określonej porze dnia, czy nigdy nie zostało zebrane?
  • Czy zapytanie przeszukiwania dzienników, którego używasz, jest poprawne syntaktycznie?
  • Czy agent kiedykolwiek otrzymał konfigurację z usługi Azure Monitor?

Pierwszym krokiem rozwiązywania problemów jest ustalenie, czy komputer wysyła zdarzenie pulsu.

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

Jeśli zapytanie zwraca wyniki, należy określić, czy określony typ danych nie jest zbierany i przekazywany do usługi. Ten problem może być spowodowany tym, że agent nie otrzymuje zaktualizowanej konfiguracji z usługi lub inny objaw uniemożliwiający normalne działanie agenta. Wykonaj poniższe kroki, aby kontynuować rozwiązywanie problemów.

  1. Otwórz wiersz polecenia z podwyższonym poziomem uprawnień na komputerze i uruchom ponownie usługę agenta, wprowadzając polecenie net stop healthservice && net start healthservice.

  2. Otwórz dziennik zdarzeń programu Operations Manager i wyszukaj identyfikatoryzdarzeń 7023, 7024, 7025, 7028 i 1210 ze źródłazdarzeń HealthService. Te zdarzenia wskazują, że agent pomyślnie odbiera konfigurację z usługi Azure Monitor i aktywnie monitoruje komputer. Opis zdarzenia dla identyfikatora zdarzenia 1210 będzie również określać w ostatnim wierszu wszystkie rozwiązania i Szczegółowe informacje, które są uwzględnione w zakresie monitorowania agenta.

    Screenshot that shows an Event ID 1210 description.

  3. Poczekaj kilka minut. Jeśli oczekiwane dane nie są widoczne w wynikach lub wizualizacji zapytania, w zależności od tego, czy wyświetlasz dane z rozwiązania lub szczegółowych informacji, w dzienniku zdarzeń programu Operations Manager wyszukaj źródłazdarzeń HealthService i Usługa kondycji Modules. Filtruj według ostrzeżeń na poziomiezdarzenia i błędu, aby potwierdzić, czy zostały zapisane zdarzenia z poniższej tabeli.

    Identyfikator zdarzenia Lokalizacja źródłowa opis Rozwiązanie
    8000 HealthService To zdarzenie określi, czy przepływ pracy związany z wydajnością, zdarzeniem lub innym typem danych zebranym nie może przekazać dalej do usługi pozyskiwania danych do obszaru roboczego. Identyfikator zdarzenia 2136 ze źródłowej usługi HealthService jest zapisywany razem z tym zdarzeniem i może wskazywać, że agent nie może komunikować się z usługą. Możliwe przyczyny mogą być błędne skonfigurowanie ustawień serwera proxy i uwierzytelniania, awarii sieci lub zapory sieciowej lub serwera proxy nie zezwalają na ruch TCP z komputera do usługi.
    10102 i 10103 moduły Usługa kondycji Przepływ pracy nie może rozpoznać źródła danych. Ten problem może wystąpić, jeśli określony licznik wydajności lub wystąpienie nie istnieje na komputerze lub jest niepoprawnie zdefiniowane w ustawieniach danych obszaru roboczego. Jeśli jest to licznik wydajności określony przez użytkownika, sprawdź, czy określone informacje są zgodne z poprawnym formatem i istnieją na komputerach docelowych.
    26002 moduły Usługa kondycji Przepływ pracy nie może rozpoznać źródła danych. Ten problem może wystąpić, jeśli określony dziennik zdarzeń systemu Windows nie istnieje na komputerze. Ten błąd można bezpiecznie zignorować, jeśli komputer nie ma zarejestrowanego tego dziennika zdarzeń. W przeciwnym razie, jeśli jest to dziennik zdarzeń określony przez użytkownika, sprawdź, czy podane informacje są poprawne.

Przypięte problemy z certyfikatami ze starszymi agentami monitorowania firmy Microsoft — zmiana powodująca niezgodność

Omówienie zmiany głównego urzędu certyfikacji

Od 30 czerwca 2023 r. zaplecze usługi Log Analytics nie będzie już akceptować połączeń z mma odwołujących się do nieaktualnego certyfikatu głównego. Te wersje MMA są starsze niż wersja Winter 2020 (Agent usługi Log Analytics) i starsze niż SCOM 2019 UR3 (SCOM). Dowolna wersja, Pakiet: 10.20.18053 / Rozszerzenie: 1.0.18053.0 lub nowsza nie będzie mieć żadnych problemów, a także żadnej wersji powyżej SCOM 2019 UR3. Każdy agent starszy niż ten przestanie działać i nie będzie już działać i przekazywać do usługi Log Analytics.

Co dokładnie się zmienia?

W ramach ciągłych działań związanych z bezpieczeństwem w różnych usługach platformy Azure usługa Azure Log Analytics oficjalnie zmieni się z Katalogu głównego urzędu certyfikacji Baltimore CyberTrust na katalog główny urzędu certyfikacji DigiCert Global G2. Ta zmiana wpłynie na komunikację TLS z usługą Log Analytics, jeśli w systemie operacyjnym brakuje nowego certyfikatu głównego urzędu certyfikacji Global G2 firmy DigiCert lub aplikacja odwołuje się do starego głównego urzędu certyfikacji Baltimore. Oznacza to, że usługa Log Analytics nie będzie już akceptować połączeń z programu MMA, które używają tego starego głównego urzędu certyfikacji po wycofaniu.

Produkty rozwiązania

Być może otrzymano powiadomienie o zmianie powodującej niezgodność, nawet jeśli nie zainstalowano osobiście programu Microsoft Monitoring Agent. Dzieje się tak, ponieważ różne produkty platformy Azure korzystają z programu Microsoft Monitoring Agent. Jeśli używasz jednego z tych produktów, może to mieć wpływ, ponieważ korzystają z agenta usługi Log Analytics systemu Windows. W przypadku tych produktów z poniższymi linkami mogą istnieć konkretne instrukcje, które będą wymagały uaktualnienia do najnowszego agenta.

Identyfikowanie i ponowne korygowanie agentów powodujących niezgodność

W przypadku wdrożeń z ograniczoną liczbą agentów zdecydowanie zalecamy uaktualnienie agenta na węzeł za pomocą tych instrukcji zarządzania.

W przypadku wdrożeń z wieloma węzłami napisaliśmy skrypt, który wykryje wszelkie istotne awarie mmas na subskrypcję, a następnie uaktualnij je do najnowszej wersji. Te skrypty muszą być uruchamiane sekwencyjnie, począwszy od updateMMA.ps1, a następnie UpgradeMMA.ps1. W zależności od maszyny skrypt może chwilę potrwać. Aby uniknąć przekroczenia limitu czasu, wymagany jest program PowerShell 7 lub nowszy.

UpdateMMA.ps1 Ten skrypt będzie przechodzić przez maszyny wirtualne w subskrypcjach, sprawdzić istniejące mmas zainstalowane, a następnie wygenerować plik CSV agentów, którzy muszą zostać uaktualnioni.

UpgradeMMA.ps1 Ten skrypt będzie używać . Plik CSV wygenerowany w pliku UpdateMMA.ps1, aby uaktualnić wszystkie powodujące niezgodność mmas.

Ukończenie obu tych skryptów może trochę potrwać.

# 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"
    }
}