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

PowerShell脚本foreach循环仅处理首行输入后终止的故障排查

故障原因

脚本仅处理输入文件第一行就终止,是PowerCLI模块默认错误行为和现有错误处理逻辑缺失共同导致的,这也是你之前用同类foreach结构处理普通文本、调用原生PowerShell cmdlet没出过问题,这次跑VMware相关脚本就异常的核心原因:

  • VMware PowerCLI模块的cmdlet默认遇到异常会抛出终止错误,一旦某轮循环内的命令执行失败,会直接跳出整个foreach循环,不会继续处理后续行;而原生PowerShell cmdlet默认抛出非终止错误,单条出错不会打断循环,两者行为存在差异。
  • 现有Try/Catch块作用范围覆盖了整个循环,但Catch块完全为空,错误发生后没有任何提示、也没有日志记录,直接静默终止,无法感知具体报错点。
  • 循环内的查询逻辑没有做对象存在性校验,任意一种常见场景都会触发错误终止:
    • 输入行拼接得到的$ClusterName对应集群不存在
    • 目标集群下没有名称匹配*190*规则的虚拟机
    • 查询得到的$VM对象为空时,直接传入Get-HardDisk会触发参数绑定错误
  • 额外逻辑问题:脚本启动日志写在了foreach循环内部,每处理一行就会重复记录一次启动信息,不符合日志逻辑。
修复方法

按以下规则调整代码即可:

  1. 配置全局错误策略,确保所有错误可被捕获,单条条目处理失败不终止整个脚本
  2. 增加空行过滤逻辑,跳过输入文件里的空白行,避免拼接无效集群名
  3. 每一步查询后增加对象存在性校验,空对象提前记录日志并跳过当前轮次
  4. 补全Catch块的错误日志逻辑,单条条目处理出错时记录错误信息,继续处理下一行
  5. 将脚本启动日志挪到循环外部,避免重复记录

修正后的核心逻辑参考:

# Create log file directory
New-Item -Path "C:\scripts\logs" -ItemType "directory" -ErrorAction SilentlyContinue

# Set script name
$ScriptName = "Hard_Disk_Count.ps1"

# Set script log file
$LogFile = "C:\scripts\logs\Hard_Disk_Count.log"

# Clear script log file
Clear-Content -Path "C:\scripts\logs\Hard_Disk_Count.log" -ErrorAction SilentlyContinue

# Import VMware modules
Write-Host "Importing VMWare modules." -ForegroundColor Cyan
Import-Module VMware.VumAutomation
Import-Module VMware.VimAutomation.Core
Import-Module VMware.VimAutomation.Storage
Import-Module VMware.VimAutomation.Common
Import-Module VMware.VimAutomation.License

# Connect to a vCenter
$VIServer = "example"
Connect-VIServer -Server $VIServer

# 全局错误策略配置
$ErrorActionPreference = "Stop"

Try {
    # Prompt for confirmation that input file is updated
    $confirmation = Read-Host "Please confirm that the text file located at 'C:\scripts\input.txt' contains the correct information.`nEnter 'y' to proceed."
    if ( $confirmation -eq 'y' ) {
        # 读取输入文件,过滤空行
        $InputFile = Get-Content "C:\scripts\input.txt" -Encoding UTF8 | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
        
        # 启动日志挪到循环外
        Write-Host "Script $ScriptName started. Log file located at $LogFile." -ForegroundColor Cyan
        "$(Get-Date) - Script $ScriptName started." >> $LogFile

        foreach( $I in $InputFile ){        
            try {
                $ClusterName = "${I}_Cluster"
                # 校验集群存在性
                $cluster = Get-Cluster -Name $ClusterName
                if(-not $cluster){
                    "$(Get-Date) - 跳过条目 $I : 集群 $ClusterName 不存在" >> $LogFile
                    continue
                }

                $VM = $cluster | Get-VM | Where-Object { $_.Name -like "*190*" }
                if(-not $VM){
                    "$(Get-Date) - 跳过条目 $I : 集群 $ClusterName 下无匹配*190*规则的虚拟机" >> $LogFile
                    continue
                }

                $Disks = Get-HardDisk -VM $VM
                $DiskCount = $Disks.count
                "$(Get-Date) - 统计结果:VM $($VM.Name), 硬盘数量 $DiskCount" >> $LogFile
            }
            catch {
                # 记录单条错误,不中断循环
                $err = $_.Exception.Message
                "$(Get-Date) - 处理条目 $I 失败:$err" >> $LogFile
                Write-Host "处理 $I 失败:$err" -ForegroundColor Red
            }
        }

    }

}

Catch {
    # 全局错误处理,覆盖连接vCenter失败、读输入文件失败这类全局异常
    $err = $_.Exception.Message
    "$(Get-Date) - 脚本全局错误:$err" >> $LogFile
    Write-Host "脚本运行出错:$err" -ForegroundColor Red
    # 这里补充原有的发邮件逻辑即可
}

调整后如果运行仍有异常,可以直接打开日志文件查看对应条目的报错信息,就能定位是集群不存在、权限不足还是VM查询规则不匹配的具体问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 19:48:31