You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell脚本遍历Azure资源后无限循环问题求助

问题修复:Azure多订阅VM状态采集脚本无限循环问题

问题根源

你的脚本出现重复执行(看似无限循环)的核心原因有两点:

  1. 订阅ID列表存在重复项:示例中两个订阅ID完全一致,会导致同一订阅被重复遍历
  2. VM范围错误:在资源组循环内使用Get-AzVM获取当前订阅下所有VM,而非当前资源组的VM,导致每个资源组都会遍历所有VM,重复处理同一台机器

此外,手动拼接CSV字符串容易出错,也会增加调试难度。

修复后的脚本

# 去重后的Azure订阅ID列表
$subscriptionIds = @(
    "c0978b9d-b809-xxxxxx-xxxx-391ceb2cfdba"
) | Select-Object -Unique

$scriptPath = "C:\Users\xxxxx\Desktop\Windows\CHECK_WINDOWS.ps1"
$outputFile = "C:\Users\xxxxx\Desktop\Windows\Outputfiles\StateWindows.csv"

# 初始化结果数组,用于存储采集到的状态对象
$results = @()

foreach ($subscriptionId in $subscriptionIds) {
    # 设置订阅上下文
    Set-AzContext -SubscriptionId $subscriptionId | Out-Null
    Write-Host "开始处理订阅:$subscriptionId"

    # 获取带有指定标签的资源组
    $resourceGroups = Get-AzResourceGroup | Where-Object { 
        $_.Tags -ne $null -and $_.Tags['ApplicationName'] -like "*US*" 
    }

    foreach ($group in $resourceGroups) {
        Write-Host "开始处理资源组:$($group.ResourceGroupName)"

        # 移除资源组锁(如果存在)
        $rgLock = Get-AzResourceLock -ResourceGroupName $group.ResourceGroupName -ErrorAction SilentlyContinue
        if ($rgLock) {
            Remove-AzResourceLock -LockId $rgLock.LockId -Force
            Write-Host "已移除资源组 $($group.ResourceGroupName) 的锁定"
        }

        # 获取当前资源组下的Windows VM,减少不必要的遍历
        $vms = Get-AzVM -ResourceGroupName $group.ResourceGroupName | Where-Object {
            $_.StorageProfile.OSDisk.OSType -eq "Windows" -and 
            $_.Tags['ApplicationName'] -like "*OSS.NORAM.US*"
        }

        foreach ($vm in $vms) {
            Write-Host "开始处理VM:$($vm.Name)"

            # 移除VM锁(如果存在)
            $lock = Get-AzResourceLock -ResourceName $vm.Name -ResourceType "Microsoft.Compute/virtualMachines" -ResourceGroupName $group.ResourceGroupName -ErrorAction SilentlyContinue
            if ($lock) {
                Remove-AzResourceLock -LockId $lock.LockId -Force
                Write-Host "已移除VM $($vm.Name) 的锁定"
            }

            # 获取VM状态
            $statuscheck = Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status
            $vmState = $statuscheck.Statuses.DisplayStatus[1]

            # 初始化状态对象
            $vmStatus = [PSCustomObject]@{
                "Server Name"        = $vm.Name
                "GPO_HARMOR"         = "-"
                "BIOMEDIC_AGENT"     = "-"
                "EDWARD_STATUS"      = "-"
                "SENSOR_STATUS"      = "-"
                "SENTINEL_STATUS"    = "-"
                "VM_STATE"           = $vmState
            }

            # 如果VM处于运行状态,执行脚本采集详细状态
            if ($vmState -eq "VM running") {
                Write-Host "正在采集 $($vm.Name) 的代理状态..."
                $scriptResult = Invoke-AzVMRunCommand -ResourceGroupName $vm.ResourceGroupName -VMName $vm.Name -CommandId 'RunPowerShellScript' -ScriptPath $scriptPath

                # 解析脚本输出(假设CHECK_WINDOWS.ps1返回的是CSV格式的一行)
                $stateLine = @($scriptResult | Out-String -Stream) -match '^".*AZ-.*"$'
                if ($stateLine) {
                    $stateValues = $stateLine -split ',' | ForEach-Object { $_.Trim('"') }
                    # 将解析后的值赋值给对象
                    $vmStatus."GPO_HARMOR" = $stateValues[1]
                    $vmStatus."BIOMEDIC_AGENT" = $stateValues[2]
                    $vmStatus."EDWARD_STATUS" = $stateValues[3]
                    $vmStatus."SENSOR_STATUS" = $stateValues[4]
                    $vmStatus."SENTINEL_STATUS" = $stateValues[5]
                }
                Write-Host "$($vm.Name) 状态采集完成"
            } else {
                Write-Host "$($vm.Name) 未运行,跳过代理状态采集"
            }

            # 将状态对象加入结果数组
            $results += $vmStatus

            # 恢复VM锁(可选,根据你的需求启用)
            # New-AzResourceLock -LockLevel CanNotDelete -LockName "PreventDel" -LockNotes "PreventDel" -ResourceName $vm.Name -ResourceType "Microsoft.Compute/virtualMachines" -ResourceGroupName $group.ResourceGroupName -Force
            # Write-Host "已恢复VM $($vm.Name) 的锁定"
        }

        # 恢复资源组锁
        New-AzResourceLock -LockLevel CanNotDelete -LockName "PreventDel" -LockNotes "PreventDel" -ResourceGroupName $group.ResourceGroupName -Force
        Write-Host "已恢复资源组 $($group.ResourceGroupName) 的锁定"
    }
    Write-Host "订阅 $subscriptionId 处理完成"
}

# 将结果导出为CSV文件,覆盖原有内容
$results | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8
Write-Host "所有资源处理完成,结果已导出至 $outputFile"

关键优化点

  • 订阅ID去重:使用Select-Object -Unique确保每个订阅只处理一次
  • 缩小VM范围:仅获取当前资源组下符合条件的Windows VM,避免重复遍历
  • 对象化处理CSV:使用PSCustomObject存储状态,通过Export-Csv导出,避免手动拼接字符串的错误
  • 明确的终止逻辑:脚本完成所有循环后自动导出结果并退出,不会重复执行

内容的提问来源于stack exchange,提问作者woodyboow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:50:55