从已启用 Arc 的服务器卸载 Azure Connected Machine 代理

如果不再需要通过启用Azure Arc的服务器管理计算机,则必须从服务器中删除任何 VM 扩展、断开代理连接,并从服务器卸载软件。 必须依次完成所有这些步骤,才能完全移除系统中所有相关的软件组件。

删除 VM 扩展

如果将 Azure VM 扩展部署到已启用 Azure Arc 的服务器,则必须在断开代理或卸载软件之前卸载所有扩展。 卸载 Azure Connected Machine 代理不会自动删除扩展,如果重新连接服务器以Azure Arc,则无法识别这些扩展。

有关如何列出和删除已启用 Azure Arc 的服务器上的任何扩展的指导,请参阅以下资源:

断开服务器与 Azure Arc 的连接

从已启用 Arc 的服务器中删除所有扩展后,下一步是断开代理的连接。 此操作将删除服务器的相应Azure资源,并清除代理的本地状态。

若要断开代理连接,请在服务器上以管理员身份运行 azcmagent disconnect 命令。 系统会提示使用有权删除订阅中的资源的 Azure 帐户登录。 如果资源已在Azure中删除,请传递其他标志以清理本地状态:azcmagent disconnect --force-local-only

如果您的管理员帐户和Azure帐户不同,可能会遇到登录提示默认使用管理员帐户的问题。 若要解决这些问题,请运行 azcmagent disconnect --use-device-code 命令。 系统会提示使用有权删除资源的 Azure 帐户登录。

Caution

将代理与在 Azure Local 上运行的已启用 Arc 的 VM 断开连接时,请仅使用 azcmagent disconnect --force-local-only 命令。 使用不带 --force-local-only 标志的命令可能会导致 Azure Local 上的 Arc VM 从 Azure 和本地删除。

卸载代理

断开代理与Azure Arc的连接后,请从服务器中删除 Connected Machine 代理。

以下两种方法都将移除代理,但不会移除计算机上的“C:\Program Files\AzureConnectedMachineAgent”文件夹

从控制面板中卸载

按照以下步骤从计算机中卸载Windows代理:

  1. 使用拥有管理员权限的帐户登录到计算机。

  2. 在“控制面板”中,选择“程序和功能”。

  3. 在“程序和功能”中,选择“Azure Connected Machine Agent”,点击“卸载”,然后点击“是”。

还可以直接从代理安装向导中删除Windows代理。 运行 AzureConnectedMachineAgent.msi 安装程序包以执行此操作。

从命令行卸载

可以使用以下示例,从命令提示符手动卸载代理或使用自动化方法(如脚本)。 首先,需要从操作系统中检索产品代码,即应用程序包的主体标识符 GUID。 使用 Msiexec.exe 命令行 (msiexec /x {Product Code}) 执行卸载。

  1. 打开注册表编辑器。

  2. 在注册表项 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall 下,查找并复制产品代码 GUID。

  3. 使用 Msiexec 卸载代理,如以下示例所示:

    • 在命令行中,输入以下命令:

      msiexec.exe /x {product code GUID} /qn
      
    • 可使用 PowerShell 执行相同的步骤:

      Get-ChildItem -Path HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall | `
      Get-ItemProperty | `
      Where-Object {$_.DisplayName -eq "Azure Connected Machine Agent"} | `
      ForEach-Object {MsiExec.exe /x "$($_.PsChildName)" /qn}
      

删除过时的服务器资源

如果退役或断开服务器而未彻底删除代理,则资源通常仍保留在Azure门户网站中,状态为 Disconnected。 随着时间的推移,这些过时的资源可能会混乱你的环境。

以下 PowerShell 脚本可帮助你识别和删除已启用Azure Arc的服务器,这些服务器在指定的天数内已断开连接。

Prerequisites

  • Azure PowerShell:已安装 Az 模块。
  • Permissions:需要通过 Azure Resource Graph 读取权限来查询,且需有参与者或所有者权限(或Microsoft.HybridCompute/machines/delete)来删除资源。

清理脚本

此脚本使用 Azure Resource Graph 查询状态为 Microsoft.HybridCompute/machinesDisconnected 时间戳早于配置的阈值的 lastStatusChange 资源。

将以下代码保存为 Cleanup-StaleArcServers.ps1.

<#
.SYNOPSIS
    Identifies and removes stale Azure Arc-enabled servers that have been disconnected for a specified number of days.

.DESCRIPTION
    This script queries Azure Resource Graph to find Azure Arc-enabled servers (Microsoft.HybridCompute/machines)
    that have a status of 'Disconnected' and have not updated their status for more than the specified number of days.
    Supports -WhatIf and -Confirm via SupportsShouldProcess.

.PARAMETER DaysDisconnected
    The number of days a server must be disconnected to be considered stale. Default is 60.

.PARAMETER Subscription
    Optional. One or more Subscription IDs to scope the query to.
    If not specified, queries all subscriptions the current context has access to.

.PARAMETER ManagementGroup
    Optional. A Management Group name to scope the query to.
    Cannot be used together with -Subscription.

.EXAMPLE
    .\Cleanup-StaleArcServers.ps1 -DaysDisconnected 60 -WhatIf
    Lists Arc servers disconnected for more than 60 days across all subscriptions.

.EXAMPLE
    .\Cleanup-StaleArcServers.ps1 -DaysDisconnected 90 -Subscription 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
    Permanently deletes Arc servers disconnected for more than 90 days in the specified subscription.

.NOTES
    Author: Microsoft
    Date: 2026-01-12
    Requires: Az.ResourceGraph, Az.Resources
#>

[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
param (
    [int]$DaysDisconnected = 60,

    [ValidateNotNullOrEmpty()]
    [string[]]$Subscription,

    [ValidateNotNullOrEmpty()]
    [string]$ManagementGroup
)

# Check required modules
foreach ($mod in @('Az.ResourceGraph', 'Az.Resources')) {
    if (-not (Get-Module -Name $mod -ListAvailable -ErrorAction SilentlyContinue)) {
        Write-Error "Required module '$mod' is not installed. Run: Install-Module $mod -Scope CurrentUser"
        return
    }
}

# Check for Azure connection
try {
    $context = Get-AzContext -ErrorAction Stop
    Write-Host "Connected to Azure context: $($context.Name)" -ForegroundColor Cyan
}
catch {
    Write-Error "Not connected to Azure. Please run 'Connect-AzAccount -Environment AzureChinaCloud' first."
    return
}

# Construct the KQL query
# We look for resources of type hybridcompute/machines
# Status must be Disconnected
# lastStatusChange must be older than $DaysDisconnected
$kqlQuery = @"
Resources
| where type == 'microsoft.hybridcompute/machines'
| where properties.status == 'Disconnected'
| where properties.lastStatusChange < ago($($DaysDisconnected)d)
| project id, name, resourceGroup, subscriptionId, location, status = properties.status, lastStatusChange = properties.lastStatusChange
"@

Write-Host "Searching for Arc servers disconnected for more than $DaysDisconnected days..." -ForegroundColor Yellow

# Execute Search with pagination (Search-AzGraph returns max 1000 results per call)
$staleServers = [System.Collections.Generic.List[object]]::new()
$skipToken = $null

try {
    do {
        $params = @{
            Query = $kqlQuery
            First = 1000
        }
        if ($skipToken) {
            $params['SkipToken'] = $skipToken
        }
        if ($Subscription) {
            $params['Subscription'] = $Subscription
        }
        if ($ManagementGroup) {
            $params['ManagementGroup'] = $ManagementGroup
        }

        $result = Search-AzGraph @params -ErrorAction Stop
        if ($result) {
            $staleServers.AddRange([object[]]$result)
            $skipToken = $result.SkipToken
        }
    } while ($skipToken)
}
catch {
    Write-Error "Failed to query Azure Resource Graph. Ensure resource graph module is installed and you have read permissions.`nError: $_"
    return
}

if ($staleServers.Count -eq 0) {
    Write-Host "No stale Arc servers found matching the criteria." -ForegroundColor Green
    return
}

Write-Host "Found $($staleServers.Count) stale servers." -ForegroundColor Yellow

# Process results
$successCount = 0
$failCount = 0

foreach ($server in $staleServers) {
    if ($PSCmdlet.ShouldProcess($server.id, "Delete stale Arc server '$($server.name)' (Disconnected since: $($server.lastStatusChange))")) {
        try {
            Remove-AzResource -ResourceId $server.id -Force -ErrorAction Stop
            Write-Host "Successfully deleted '$($server.name)'." -ForegroundColor Green
            $successCount++
        }
        catch {
            Write-Error "Failed to delete '$($server.name)'. Error: $_"
            $failCount++
        }
    }
}

Write-Host "`nCleanup completed. Deleted: $successCount, Failed: $failCount, Total: $($staleServers.Count)" -ForegroundColor Green

如何使用脚本

Prerequisites

该脚本需要以下 PowerShell 模块:

  • Az.ResourceGraph
  • Az.Resources

如果未安装它们,请运行:

Install-Module Az.ResourceGraph, Az.Resources -Scope CurrentUser

步骤

  1. 登录到 Azure

    打开 PowerShell 终端并登录。

    Connect-AzAccount -Environment AzureChinaCloud
    
  2. 运行假设分析

    首先,使用 -WhatIf 开关运行脚本。 此步骤列出满足条件的服务器,而无需实际删除这些服务器。 此命令检查已断开连接 60 天或以上的服务器。

    .\Cleanup-StaleArcServers.ps1 -DaysDisconnected 60 -WhatIf
    

    若要将查询范围限定为特定订阅,请使用 -Subscription 参数:

    .\Cleanup-StaleArcServers.ps1 -DaysDisconnected 60 -Subscription 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' -WhatIf
    

    若要改为将查询范围限定为管理组,请使用 -ManagementGroup 参数:

    .\Cleanup-StaleArcServers.ps1 -DaysDisconnected 60 -ManagementGroup 'MyManagementGroup' -WhatIf
    

    查看输出,确保输出仅列出预期的服务器。

  3. 执行清理

    当您确信所要删除的服务器列表正确时,不带 -WhatIf 开关运行脚本。

    .\Cleanup-StaleArcServers.ps1 -DaysDisconnected 60
    

    若要清理长时间断开连接的服务器(例如六个月),请增加日计数:

    .\Cleanup-StaleArcServers.ps1 -DaysDisconnected 180
    

    每次删除之前,脚本都会提示确认。 若要跳过提示,请添加 -Confirm:$false