다음을 통해 공유


MMA/OMS 검색 및 제거 유틸리티

컴퓨터를 AMA(Azure Monitor 에이전트)로 마이그레이션한 후 운영 체제에 따라 레거시 Log Analytics 에이전트를 제거하여 로그가 중복되지 않도록 합니다. 레거시 검색 및 제거 유틸리티는 단일 구독에서 Azure VM(Virtual Machines), Azure VMSS(Virtual Machine Scale Sets) 및 Azure Arc 서버에서 확장을 제거할 수 있습니다.

이 유틸리티는 다음 두 단계로 작동합니다.

  1. 검색: 이 유틸리티는 레거시 에이전트가 간단한 CSV 파일에 설치된 모든 컴퓨터의 인벤토리를 만듭니다. 유틸리티가 실행되는 동안에는 새 VM을 만들지 않는 것이 좋습니다.

  2. 제거: 유틸리티는 CSV 파일에 나열된 컴퓨터에서 레거시 에이전트를 제거합니다. 에이전트를 제거하려는 컴퓨터만 존재하도록 CSV 파일의 컴퓨터 목록을 편집해야 합니다.

참고 항목

MSI 설치 관리자를 사용하여 설치된 MMA 에이전트에서는 제거가 작동하지 않습니다. VM 확장에서만 작동합니다.

필수 조건

인터넷에 연결된 컴퓨터에서 모든 설정 단계를 수행합니다. 필요 항목:

  • Windows 10 이상 또는 Windows Server 2019 이상
  • PowerShell 7.0 이상. 이 기능을 사용하면 프로세스 속도를 높일 수 있는 병렬 실행이 가능합니다.
  • Azure Graph API와 통신하려면 Azcli를 설치해야 합니다.
  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 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://docs.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://docs.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, Virtual Machine Scale Sets 및 Arc 지원 서버 목록을 반복하고 레거시 에이전트를 제거합니다. 에이전트가 실행 중이 아니면 제거할 수 없습니다.

.\LogAnalyticsAgentUninstallUtilityScript.ps1 UninstallExtension

스크립트가 완료되면 "LogAnalyticsAgentExtensionInventory.csv" 파일에서 VM, Virtual Machine Scale Sets 및 Arc 지원 서버의 제거 상태를 확인할 수 있습니다.