Microsoft Monitoring Agent /OMS 检测和移除工具

将计算机迁移到 Azure Monitor 代理 (AMA) 后,请根据操作系统移除旧的 Log Analytics 代理,以避免日志重复。 旧版发现和移除实用工具可以从 Azure 虚拟机 (VM)、Azure 虚拟机规模集 (VMSS) 和 Azure Arc 服务器中移除单个订阅中的扩展。

该实用工具按两个步骤工作:

  1. 发现:该实用工具会创建在简单 CSV 文件中安装旧代理的所有计算机的清单。 建议在实用工具运行时不要创建任何新的 VM。
  2. 移除:该实用工具会从 CSV 文件中列出的计算机中移除旧代理。 你应编辑 CSV 文件中的计算机列表,以确保只有你要从中移除代理的计算机存在。

注意

删除不适用于使用 Microsoft 软件安装程序 (MSI) 安装程序安装的Microsoft监视代理。 它仅适用于 VM 扩展。

先决条件

在连接 Internet 的计算机上执行所有设置步骤。 您需要:

  1. 以管理员身份打开 PowerShell:
  2. 运行 Invoke-WebRequest -Uri https://aka.ms/installazurecliwindows -OutFile AzureCLI.msi 命令。
  3. 运行 Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet' 命令。
  4. 最新版本的 Azure CLI 下载并安装。

步骤 1 登录并设置订阅

该工具一次处理一个订阅。 必须登录并进行订阅,以执行删除操作。 以管理员身份打开 PowerShell 命令提示符并登录。

az cloud set -n AzureChinaCloud
az login

接下来必须设置订阅。

Az account set --subscription {subscription_id or subscription_name}

步骤 2 复制脚本

你会使用以下脚本进行代理移除。 打开名为 LogAnalyticsAgentUninstallUtilityScript.ps1 的本地目录中的文件,并将脚本复制到该文件中。

# This is per subscription, the customer has to set the az subscription before running this.
# az login
# az account set --subscription <subscription_id/subscription_name>
# This script uses parallel processing, modify the $parallelThrottleLimit parameter to either increase or decrease the number of parallel processes
# PS> .\LogAnalyticsAgentUninstallUtilityScript.ps1 GetInventory
# The above command will generate a csv file with the details of Vm's and Vmss and Arc servers that has log analyice Agent extension installed. 
# The customer can modify the the csv by adding/removing rows if needed
# Remove the log analytics agent by running the script again as shown below:
# PS> .\LogAnalyticsAgentUninstallUtilityScript.ps1 UninstallExtension

# This version of the script requires Powershell version >= 7 in order to improve performance via ForEach-Object -Parallel
# https://learn.microsoft.com/en-us/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://learn.microsoft.com/en-us/powershell/scripting/whats-new/migrating-from-windows-powershell-51-to-powershell-7?view=powershell-7.1."
    exit 1
}

$parallelThrottleLimit = 16

function GetArcServersWithLogAnalyticsAgentExtensionInstalled {
    param (
        $fileName
    )
    
    $serverList = az connectedmachine list --query "[].{ResourceId:id, ResourceGroup:resourceGroup, ServerName:name}" | ConvertFrom-Json
    if(!$serverList)
    {
        Write-Host "Cannot get the Arc server list"
        return
    }

    $serversCount = $serverList.Length
    $vmParallelThrottleLimit = $parallelThrottleLimit
    if ($serversCount -lt $vmParallelThrottleLimit) 
    {
        $serverParallelThrottleLimit = $serversCount
    }

    $serverGroups = @()

    if($serversCount -eq 1)
    {
        $serverGroups += ,($serverList[0])
    }
    else
    {
        # split the list into batches to do parallel processing
        for ($i = 0; $i -lt $serversCount; $i += $vmParallelThrottleLimit) 
        { 
            $serverGroups += , ($serverList[$i..($i + $serverParallelThrottleLimit - 1)]) 
        }
    }

    Write-Host "Detected $serversCount Arc servers in this subscription."
    $hash = [hashtable]::Synchronized(@{})
    $hash.One = 1

    $serverGroups | Foreach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        $len = $using:serversCount
        $hash = $using:hash
        $_ | ForEach-Object {
            $percent = 100 * $hash.One++ / $len
            Write-Progress -Activity "Getting Arc server extensions Inventory" -PercentComplete $percent
            $serverName = $_.ServerName
            $resourceGroup = $_.ResourceGroup
            $resourceId = $_.ResourceId
            Write-Debug "Getting extensions for Arc server: $serverName"
            $extensions = az connectedmachine extension list -g $resourceGroup --machine-name $serverName --query "[?contains(['MicrosoftMonitoringAgent', 'OmsAgentForLinux', 'AzureMonitorLinuxAgent', 'AzureMonitorWindowsAgent'], properties.type)].{type: properties.type, name: name}" | ConvertFrom-Json

            if (!$extensions) {
                return
            }
            $extensionMap = @{}
            foreach ($ext in $extensions) {
                $extensionMap[$ext.type] = $ext.name
            }
            $extensionName = ""
            if ($extensionMap.ContainsKey("MicrosoftMonitoringAgent")) {
                $extensionName = $extensionMap["MicrosoftMonitoringAgent"]
            }
            elseif ($extensionMap.ContainsKey("OmsAgentForLinux")) {
                $extensionName = $extensionMap["OmsAgentForLinux"]
            }
            if ($extensionName) {
                $amaExtensionInstalled = "False"
                if ($extensionMap.ContainsKey("AzureMonitorWindowsAgent") -or $extensionMap.ContainsKey("AzureMonitorLinuxAgent")) {
                    $amaExtensionInstalled = "True"
                }
                $csvObj = New-Object -TypeName PSObject -Property @{
                    'ResourceId'              = $resourceId
                    'Name'                    = $serverName
                    'Resource_Group'          = $resourceGroup
                    'Resource_Type'           = "ArcServer"
                    'Install_Type'            = "Extension"
                    'Extension_Name'          = $extensionName
                    'AMA_Extension_Installed' = $amaExtensionInstalled
                }
                $csvObj | Export-Csv $using:fileName -Append -Force | Out-Null
            }
            # az cli sometime cannot handle many requests at same time, so delaying next request by 2 milliseconds
            Start-Sleep -Milliseconds 2
        }
    }
}

function GetVmsWithLogAnalyticsAgentExtensionInstalled
{
    param(
        $fileName
    )
    
    $vmList = az vm list --query "[].{ResourceId:id, ResourceGroup:resourceGroup, VmName:name}" | ConvertFrom-Json
     
    if(!$vmList)
    {
        Write-Host "Cannot get the VM list"
        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 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 extensions Inventory" -PercentComplete $percent
            $resourceId = $_.ResourceId
            $vmName = $_.VmName
            $resourceGroup = $_.ResourceGroup
            Write-Debug "Getting extensions for VM: $vmName"
            $extensions = az vm extension list -g $resourceGroup --vm-name $vmName --query "[?contains(['MicrosoftMonitoringAgent', 'OmsAgentForLinux', 'AzureMonitorLinuxAgent', 'AzureMonitorWindowsAgent'], typePropertiesType)].{type: typePropertiesType, name: name}" | ConvertFrom-Json
            
            if (!$extensions) {
                return
            }
            $extensionMap = @{}
            foreach ($ext in $extensions) {
                $extensionMap[$ext.type] = $ext.name
            }
            $extensionName = ""
            if ($extensionMap.ContainsKey("MicrosoftMonitoringAgent")) {
                $extensionName = $extensionMap["MicrosoftMonitoringAgent"]
            }
            elseif ($extensionMap.ContainsKey("OmsAgentForLinux")) {
                $extensionName = $extensionMap["OmsAgentForLinux"]
            }
            if ($extensionName) {
                $amaExtensionInstalled = "False"
                if ($extensionMap.ContainsKey("AzureMonitorWindowsAgent") -or $extensionMap.ContainsKey("AzureMonitorLinuxAgent")) {
                    $amaExtensionInstalled = "True"
                }
                $csvObj = New-Object -TypeName PSObject -Property @{
                    'ResourceId'              = $resourceId
                    'Name'                    = $vmName
                    'Resource_Group'          = $resourceGroup
                    'Resource_Type'           = "VM"
                    'Install_Type'            = "Extension"
                    'Extension_Name'          = $extensionName
                    'AMA_Extension_Installed' = $amaExtensionInstalled
                }
                $csvObj | Export-Csv $using:fileName -Append -Force | Out-Null
            }
            # az cli sometime cannot handle many requests at same time, so delaying next request by 2 milliseconds
            Start-Sleep -Milliseconds 2
        }
    }
}

function GetVmssWithLogAnalyticsAgentExtensionInstalled
{
    param(
        $fileName
    )

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

    $vmssCount = $vmssList.Length
    Write-Host "Detected $vmssCount Vmss 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 extensions Inventory" -PercentComplete $percent
        $resourceId = $_.ResourceId
        $vmssName = $_.VmssName
        $resourceGroup = $_.ResourceGroup
        Write-Debug "Getting extensions for VMSS: $vmssName"
        $extensions = az vmss extension list -g $resourceGroup --vmss-name $vmssName --query "[?contains(['MicrosoftMonitoringAgent', 'OmsAgentForLinux', 'AzureMonitorLinuxAgent', 'AzureMonitorWindowsAgent'], typePropertiesType)].{type: typePropertiesType, name: name}" | ConvertFrom-Json
        
        if (!$extensions) {
            return
        }
        $extensionMap = @{}
        foreach ($ext in $extensions) {
            $extensionMap[$ext.type] = $ext.name
        }
        $extensionName = ""
        if ($extensionMap.ContainsKey("MicrosoftMonitoringAgent")) {
            $extensionName = $extensionMap["MicrosoftMonitoringAgent"]
        }
        elseif ($extensionMap.ContainsKey("OmsAgentForLinux")) {
            $extensionName = $extensionMap["OmsAgentForLinux"]
        }
        if ($extensionName) {
            $amaExtensionInstalled = "False"
            if ($extensionMap.ContainsKey("AzureMonitorWindowsAgent") -or $extensionMap.ContainsKey("AzureMonitorLinuxAgent")) {
                $amaExtensionInstalled = "True"
            }
            $csvObj = New-Object -TypeName PSObject -Property @{
                'ResourceId'              = $resourceId
                'Name'                    = $vmssName
                'Resource_Group'          = $resourceGroup
                'Resource_Type'           = "VMSS"
                'Install_Type'            = "Extension"
                'Extension_Name'          = $extensionName
                'AMA_Extension_Installed' = $amaExtensionInstalled
            }
            $csvObj | Export-Csv $using:fileName -Append -Force | Out-Null
        }
        # az cli sometime cannot handle many requests at same time, so delaying next request by 2 milliseconds
        Start-Sleep -Milliseconds 2
    }
}

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

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

    Start-Transcript -Path $logFileName -Append
    GetVmsWithLogAnalyticsAgentExtensionInstalled $fileName
    GetVmssWithLogAnalyticsAgentExtensionInstalled $fileName
    GetArcServersWithLogAnalyticsAgentExtensionInstalled $fileName
    Stop-Transcript
}

function UninstallExtension
{
    param(
        $fileName = "LogAnalyticsAgentExtensionInventory.csv"
    )
    Start-Transcript -Path $logFileName -Append
    Import-Csv $fileName | ForEach-Object -ThrottleLimit $parallelThrottleLimit -Parallel {
        if ($_.Install_Type -eq "Extension") 
        {
            $extensionName = $_.Extension_Name
            $resourceName = $_.Name
            Write-Debug "Uninstalling extension: $extensionName from $resourceName"
            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 delete --name $extensionName --vmss-name $resourceName --resource-group $_.Resource_Group --output none --no-wait
            }
            elseif($_.Resource_Type -eq "VM")
            {
                # if the extension is installed with a custom name, provide the name using the flag: --extension-instance-name <extension name>
                az vm extension delete --name $extensionName --vm-name $resourceName --resource-group $_.Resource_Group --output none --no-wait
            }
            elseif($_.Resource_Type -eq "ArcServer")
            {
                az connectedmachine extension delete --name $extensionName --machine-name $resourceName --resource-group $_.Resource_Group --no-wait --output none --yes -y
            }
            # az cli sometime cannot handle many requests at same time, so delaying next delete request by 2 milliseconds
            Start-Sleep -Milliseconds 2
        }
    }
    Stop-Transcript
}

$logFileName = "LogAnalyticsAgentUninstallUtilityScriptLog.log"

switch ($args.Count)
{
    0 {
        Write-Host "The arguments provided are incorrect."
        Write-Host "To get the Inventory: Run the script as: PS> .\LogAnalyticsAgentUninstallUtilityScript.ps1 GetInventory"
        Write-Host "To uninstall Log Analytics Agent from Inventory: Run the script as: PS> .\LogAnalyticsAgentUninstallUtilityScript.ps1 UninstallExtension"
    }
    1 {
        if (-Not (Test-Path $logFileName)) {
            New-Item -Path $logFileName -ItemType File
        }
        $funcname = $args[0]
        Invoke-Expression "& $funcname"
    }
    2 {
        if (-Not (Test-Path $logFileName)) {
            New-Item -Path $logFileName -ItemType File
        }
        $funcname = $args[0]
        $funcargs = $args[1]
        Invoke-Expression "& $funcname $funcargs"
    }
}

步骤 3 获取清单

在订阅中收集所有 VM、VMSS 和已启用 Arc 的服务器上所有旧代理的列表。 你会运行下载的脚本,以获取订阅中旧代理的清单。

.\LogAnalyticsAgentUninstallUtilityScript.ps1 GetInventory

该脚本会报告在订阅中发现的 VM、VMSS 或已启用 Arc 的服务器的总数。 它需要几分钟的时间来运行。 你会在控制台窗口中看到进度栏。 完成后,可以使用以下格式在本地目录中看到名为 LogAnalyticsAgentExtensionInventory.csv 的 CSV 文件。

资源_ID 名称 资源组 资源类型 安装类型 扩展名 AMA_Extension_Installed
a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1 Linux-ama-e2e-debian9 Linux-AMA-E2E VM 扩展 OmsAgentForLinux 真 实
b1b1b1b1-cccc-dddd-eeee-f2f2f2f2f2f2 test2012-r2-da test2012-r2-daAMA-ADMIN VM 扩展 Microsoft 监视代理

步骤 4 卸载清单

此脚本会循环访问 VM、虚拟机规模集和已启用 Arc 的服务器的列表,并卸载旧代理。 如果代理未运行,则无法将其移除。

.\LogAnalyticsAgentUninstallUtilityScript.ps1 UninstallExtension

脚本完成后,可以在 LogAnalyticsAgentExtensionInventory.csv 文件中查看 VM、虚拟机规模集和已启用 Arc 的服务器删除状态。