PowerShell 批量文件分发脚本
最近遇到了一个需要批量处理的问题,需要从Excel文件去读取Excel中的计算机名称,手动一个个复制太不方便了;然后根据微软的Powershell命令,进行了学习,然后今天来分析一段实用的 PowerShell 脚本,它能从 Excel 读取计算机名,然后批量向这些计算机复制文件,大大提高工作效率。
加载必要的程序集
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
这行代码的作用是加载 Microsoft.Office.Interop.Excel 程序集。因为后续要对 Excel 文件进行操作,而这个程序集提供了与 Excel 交互的相关功能,有了它,脚本才能正常读取 Excel 中的数据。
定义路径
$sourceFolderPath = "文件路径"$excelFilePath = "C:\path\to\your\excel_file.xlsx"
这里分别定义了源文件夹路径和 Excel 文件路径。源文件夹路径指向了存放要复制文件的位置,Excel 文件路径则指定了包含计算机名列表的 Excel 文件所在之处,为后续的文件读取和复制操作明确了来源。
操作 Excel 应用
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $false
$workbook = $excel.Workbooks.Open($excelFilePath)
$worksheet = $workbook.Sheets.Item(1)
$usedRange = $worksheet.UsedRange
这部分代码首先创建了一个 Excel 应用实例,将其设置为不可见(Visible = $false)且不显示警告(DisplayAlerts = $false),这样可以在后台安静地进行操作,不干扰用户。然后打开指定的 Excel 工作簿,获取第一个工作表以及工作表的已使用范围,为读取计算机名做好准备。
读取计算机名
$computerNames = @()
$row = 2 # 从第2行开始(A2单元格)
while ($worksheet.Cells.Item($row, 1).Text -ne "") {
$computerName = $worksheet.Cells.Item($row, 1).Text
$computerNames += $computerName
$row++
}
脚本从 Excel 的 A2 单元格开始读取数据,将读取到的计算机名存储到数组$computerNames中,直到遇到空行为止。这样就获取了所有需要进行文件复制操作的目标计算机名称。
清理 Excel 资源
$workbook.Close()
$excel.Quit()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($worksheet) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
读取完计算机名后,关闭工作簿和 Excel 应用程序,并释放相关的 COM 对象,同时进行垃圾回收。这一系列操作是为了释放系统资源,避免资源占用和内存泄漏。
检查计算机连通性并复制文件
$ping = New-Object System.Net.NetworkInformation.Ping
foreach ($targetComputerName in $computerNames) {
$targetPath = "\\$targetComputerName\c$"
try {
$pingResult = $ping.Send($targetComputerName, 1000)
if ($pingResult.Status -ne "Success") {
Write-Output "计算机 $targetComputerName 无法访问,跳过..."
continue
}
} catch {
Write-Output "检查计算机 $targetComputerName 连通性时出错,跳过: $_"
continue
}
try {
if (!(Test-Path $targetPath -ErrorAction SilentlyContinue)) {
Write-Output "无法访问 $targetPath,跳过此计算机..."
continue
}
Copy-Item -Path "$sourceFolderPath\*" -Destination $targetPath -Recurse -Force
Write-Output "已将所有文件复制到 $targetPath"
} catch {
Write-Output "复制文件到 $targetPath 失败:$_"
}
}
首先创建 ping 对象用于检查计算机连通性。然后遍历所有读取到的计算机名,对每台计算机,先通过 ping 检查其是否可达,如果不可达则跳过。对于可达的计算机,再检查目标共享路径是否可访问,若不可访问也跳过。只有当计算机可达且目标路径可访问时,才将源文件夹中的所有文件复制到目标路径,并输出相应的操作结果。若过程中出现错误,也会及时捕获并输出错误信息。
完整代码
# 加载必要的程序集
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
# 源文件夹路径
$sourceFolderPath = "需要复制的文件夹路径"
# Excel文件路径
$excelFilePath = "Excel文件路径"
# 创建Excel应用实例
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $false
# 打开工作簿
$workbook = $excel.Workbooks.Open($excelFilePath)
# 获取第一个工作表
$worksheet = $workbook.Sheets.Item(1)
# 获取已使用范围
$usedRange = $worksheet.UsedRange
# 从A2开始读取计算机名,直到遇到空行为止
$computerNames = @()
$row = 2 # 从第2行开始(A2单元格)
while ($worksheet.Cells.Item($row, 1).Text -ne "") {
$computerName = $worksheet.Cells.Item($row, 1).Text
$computerNames += $computerName
$row++
}
# 关闭工作簿和Excel应用
$workbook.Close()
$excel.Quit()
# 释放COM对象
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($worksheet) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# 创建ping对象
$ping = New-Object System.Net.NetworkInformation.Ping
# 遍历计算机名并复制文件
foreach ($targetComputerName in $computerNames) {
# 目标路径
$targetPath = "\\$targetComputerName\c$"
# 检查计算机是否可达
try {
$pingResult = $ping.Send($targetComputerName, 1000) # 超时时间1秒
if ($pingResult.Status -ne "Success") {
Write-Output "计算机 $targetComputerName 无法访问,跳过..."
continue
}
} catch {
Write-Output "检查计算机 $targetComputerName 连通性时出错,跳过: $_"
continue
}
try {
# 检查目标共享是否可访问
if (!(Test-Path $targetPath -ErrorAction SilentlyContinue)) {
Write-Output "无法访问 $targetPath,跳过此计算机..."
continue
}
# 复制源文件夹中的所有文件到目标路径
Copy-Item -Path "$sourceFolderPath\*" -Destination $targetPath -Recurse -Force
Write-Output "已将所有文件复制到 $targetPath"
} catch {
Write-Output "复制文件到 $targetPath 失败:$_"
}
}