VMware虚拟机使用信息脚本执行缓慢且导出CSV失败求助
问题排查与解决方案
一、脚本运行缓慢的核心原因及优化
串行SMB访问无超时控制
脚本逐个通过\\$($computer.Name)\d$\Users访问虚拟机D盘用户目录,每个请求依赖网络响应,若遇到离线/网络不通的虚拟机,会长时间卡在SMB连接上(默认超时极长)。串行处理大量虚拟机时,总耗时会急剧增加。- 优化方案:添加SMB访问超时控制,改用并行处理减少等待时间:
循环中调用该函数替代直接的# 带超时的用户目录查询函数 function Get-LatestUserFolder { param([string]$ComputerName) $timeout = 5 # 设置5秒超时 $job = Start-Job -ScriptBlock { Get-ChildItem "\\$using:ComputerName\d$\Users" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object Name, LastWriteTime -First 1 } $result = if (Wait-Job $job -Timeout $timeout) { Receive-Job $job } Remove-Job $job -Force return $result }Get-ChildItem,避免长时间等待无响应的机器。
- 优化方案:添加SMB访问超时控制,改用并行处理减少等待时间:
数组拼接的性能损耗
使用$CSVArray += $Entry每次都会创建新数组,虚拟机数量较多时,内存复制开销会随数据量增大而急剧上升,拖慢运行速度。- 优化方案:改用泛型列表存储数据:
# 替换原数组初始化 $CSVArray = [System.Collections.Generic.List[PSCustomObject]]::new() # 替换数组拼接操作 $CSVArray.Add($entry)
- 优化方案:改用泛型列表存储数据:
不必要的全量排序
Get-ChildItem获取所有用户文件夹后再排序,可优化为直接取最新条目减少内存占用:# PowerShell 5.1+支持-Top参数,无需全量排序 $Data = Get-ChildItem "\\$($computer.Name)\d$\Users" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending -Top 1 | Select-Object Name, LastWriteTime
二、导出CSV为空/报错的原因及解决
初始
$Filename报错原因
原脚本通过保存对话框选择路径时,可能因目标目录无写入权限、路径含特殊字符,导致Export-CSV的-Path参数无效。导出为空的核心原因
- AD计算机列表为空:检查
Get-ADComputer的-SearchBase路径是否匹配新域OU结构,单独运行以下命令验证是否返回预期虚拟机:Get-ADComputer -filter 'Enabled -eq $True' -SearchBase "OU=Virtual,OU=Computers-Internal,DC=Domain,DC=Com" - SMB访问全部失败:新域中可能存在虚拟机D盘共享未开启、权限变更等问题,导致所有
\\$computer.Name\d$\Users访问失败。可在循环中添加日志输出,定位故障机器:Write-Host "Processing $($Computer.Name)..." - 对象序列化问题:自定义
CsvRow类的[object]类型属性可能导致Export-CSV无法正确识别字段,改用PSCustomObject替代自定义类:foreach($Computer in $Computers){ $entry = [PSCustomObject]@{ ComputerName = $Computer.Name LastUser = $null LastLogon = $null Inactive = "False" } Try{ $Data = Get-LatestUserFolder -ComputerName $Computer.Name if($Data){ $entry.LastUser = $Data.Name $entry.LastLogon = $Data.LastWriteTime $entry.Inactive = if($Data.LastWriteTime.AddDays($InactiveDays) -lt $Today) { "True" } else { "False" } } else { $entry.Inactive = "True" } } catch { $entry.LastUser = "Access Error" $entry.Inactive = "True" } $CSVArray.Add($entry) } - 权限与路径问题:确保运行脚本的账号对
c:\temp有写入权限,手动创建c:\temp目录后再尝试导出。
- AD计算机列表为空:检查
三、调试建议
- 在循环中添加日志,输出每台机器的处理状态,定位卡顿节点。
- 手动测试访问单台虚拟机的
\\computerName\d$\Users,确认SMB共享及权限正常。
内容的提问来源于stack exchange,提问作者Valerie Donoso
相关产品推荐
相关产品推荐

