MMA/OMS 发现和移除实用工具

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

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

  1. 发现:该实用工具会创建在简单 CSV 文件中安装旧代理的所有计算机的清单。 建议在实用工具运行时不要创建任何新的 VM。

  2. 移除:该实用工具会从 CSV 文件中列出的计算机中移除旧代理。 你应编辑 CSV 文件中的计算机列表,以确保只有你要从中移除代理的计算机存在。

!请注意,删除不适用于使用 MSI 安装程序安装的 MMA 代理。 它仅适用于 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 文件,格式如下。

Resource_ID 名称 Resource_Group Resource_Type Install_Type Extension_Name AMA_Extension_Installed
012cb5cf-e1a8-49ee-a484-d40673167c9c Linux-ama-e2e-debian9 Linux-AMA-E2E VM 扩展 OmsAgentForLinux True
8acae35a-454f-4869-bf4f-658189d98516 test2012-r2-da test2012-r2-daAMA-ADMIN VM 扩展 MicrosoftMonitorAgent False

步骤 4 卸载清单

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

.\LogAnalyticsAgentUninstallUtilityScript.ps1 UninstallExtension

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