英文:
Looping for-each and creating an excel sheet (.xlsx)
问题
我正在尝试创建一个从文本文件中的一组服务器中提取打印设备信息的脚本。脚本可以正常工作,但它只从一个服务器中提取一个设备,然后脚本就完成了。我尝试让它能够运行,并在另一个命令中循环执行,以汇总所有工作表的数据并查找服务器之间的不同之处。
clear-host
# 从文本文件获取服务器列表
$sites = Get-Content -Path "User\user$\user\Documents\Working Folder32023\test.txt"
$counter = 4
# 这里也一样
foreach ($site in $sites) {
$result = Get-Printer -ComputerName $site | Select Name, DriverName, PortName, ShareName
# 创建一个Excel对象
$ExcelObj = New-Object -comobject Excel.Application
$ExcelObj.Visible = $true
# 添加一个工作簿
$ExcelWorkBook = $ExcelObj.Workbooks.Add()
$ExcelWorkSheet = $ExcelWorkBook.Worksheets.Item(1)
# 重命名工作表
$ExcelWorkSheet.Name = $site
# 填充表头
$ExcelWorkSheet.Cells.Item(1, 1) = '设备名称'
$ExcelWorkSheet.Cells.Item(1, 2) = '驱动程序名称'
$ExcelWorkSheet.Cells.Item(1, 3) = '端口名称'
$ExcelWorkSheet.Cells.Item(1, 4) = '共享名称'
# 使表头加粗,设置字体大小和列宽
$ExcelWorkSheet.Rows.Item(1).Font.Bold = $true
$ExcelWorkSheet.Rows.Item(1).Font.size = 15
$ExcelWorkSheet.Columns.Item(1).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(2).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(3).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(4).ColumnWidth = 28
# 用从服务器获取的数据填充Excel单元格
$ExcelWorkSheet.Columns.Item(1).Rows.Item($counter) = $result.Name
$ExcelWorkSheet.Columns.Item(2).Rows.Item($counter) = $result.DriverName
$ExcelWorkSheet.Columns.Item(3).Rows.Item($counter) = $result.PortName
$ExcelWorkSheet.Columns.Item(4).Rows.Item($counter) = $result.ShareName
$counter++
}
# 保存报告并关闭Excel:
$ExcelWorkBook.SaveAs('\User\User\Documents\Working Folder32023\test.xlsx')
$ExcelWorkBook.Close($true)
希望这对您有所帮助。
英文:
I'm trying to create a script that pulls print device from a group of servers housed in a text file. The script works fine except it only pulls one device from one server then the script completes. I'm trying to get this to work then loop in another command to combine all the data from all the sheets and look for dissimilarities between the server(s).
clear-host
# Get list of servers from text file
$sites = Get-Content -Path "User\user$\user\Documents\Working Folder32023\test.txt"
$counter = 4
# And here
foreach ($site in $sites) {
$result = Get-Printer -ComputerName $site | Select Name, DriverName, PortName, ShareName
#Create an Excel object
$ExcelObj = New-Object -comobject Excel.Application
$ExcelObj.Visible = $true
# Add a workbook
$ExcelWorkBook = $ExcelObj.Workbooks.Add()
$ExcelWorkSheet = $ExcelWorkBook.Worksheets.Item(1)
# Rename the worksheet
$ExcelWorkSheet.Name = $site
# Fill in the head of the table
$ExcelWorkSheet.Cells.Item(1, 1) = 'Device Name'
$ExcelWorkSheet.Cells.Item(1, 2) = 'Driver Name'
$ExcelWorkSheet.Cells.Item(1, 3) = 'Port Name'
$ExcelWorkSheet.Cells.Item(1, 4) = 'Share Name'
# Make the table head bold, set the font size and the column width
$ExcelWorkSheet.Rows.Item(1).Font.Bold = $true
$ExcelWorkSheet.Rows.Item(1).Font.size = 15
$ExcelWorkSheet.Columns.Item(1).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(2).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(3).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(4).ColumnWidth = 28
# Fill in Excel cells with the data obtained from the server
$ExcelWorkSheet.Columns.Item(1).Rows.Item($counter) = $result.Name
$ExcelWorkSheet.Columns.Item(2).Rows.Item($counter) = $result.DriverName
$ExcelWorkSheet.Columns.Item(3).Rows.Item($counter) = $result.PortName
$ExcelWorkSheet.Columns.Item(4).Rows.Item($counter) = $result.ShareName
$counter++
}
# Save the report and close Excel:
$ExcelWorkBook.SaveAs('\User\User\Documents\Working Folder32023\test.xlsx')
$ExcelWorkBook.Close($true)
答案1
得分: 0
因为你在循环内部创建了一个新的 Excel COM 对象。将这部分放在循环上方,并在其中为每台服务器创建一个新的工作表并填充数据。
由于 Get-Printer
很可能返回多个对象,你也需要在其结果上循环。
尝试:
# 在这里使用完整的绝对路径
$outFile = 'X:\Somewhere\Documents\Working Folder32023\test.xlsx'
if (Test-Path -Path $outFile -PathType Leaf) { Remove-Item -Path $outFile -Force }
# 创建一个 Excel 对象
$ExcelObj = New-Object -comobject Excel.Application
$ExcelObj.Visible = $true
# 添加一个工作簿
$ExcelWorkBook = $ExcelObj.Workbooks.Add()
# 从文本文件获取服务器列表
$sites = Get-Content -Path "X:\Somewhere\Documents\Working Folder32023\test.txt";
foreach ($site in $sites) {
$counter = 2
# 添加一个工作表
$ExcelWorkSheet = $ExcelWorkBook.Sheets.Add()
# 将其设为活动工作表
$ExcelWorkSheet.Activate()
# 重命名工作表
$ExcelWorkSheet.Name = $site
# 填充表头
$ExcelWorkSheet.Cells.Item(1, 1) = '设备名称'
$ExcelWorkSheet.Cells.Item(1, 2) = '驱动程序名称'
$ExcelWorkSheet.Cells.Item(1, 3) = '端口名称'
$ExcelWorkSheet.Cells.Item(1, 4) = '共享名称'
# 将表头设置为粗体,设置字体大小和列宽
$ExcelWorkSheet.Rows.Item(1).Font.Bold = $true
$ExcelWorkSheet.Rows.Item(1).Font.size = 15
$ExcelWorkSheet.Columns.Item(1).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(2).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(3).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(4).ColumnWidth = 28
# 用从服务器获取的数据填充 Excel 单元格
Get-Printer -ComputerName $site | Select-Object Name, DriverName, PortName, ShareName | ForEach-Object {
$ExcelWorkSheet.Columns.Item(1).Rows.Item($counter) = $_.Name
$ExcelWorkSheet.Columns.Item(2).Rows.Item($counter) = $_.DriverName
$ExcelWorkSheet.Columns.Item(3).Rows.Item($counter) = $_.PortName
$ExcelWorkSheet.Columns.Item(4).Rows.Item($counter) = $_.ShareName
$counter++
}
}
# 保存报告并关闭 Excel:
$ExcelWorkBook.SaveAs($outFile)
$ExcelWorkBook.Close($true)
$ExcelObj.Quit()
# 清理使用过的 COM 对象
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkSheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkBook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelObj)
$null = [System.GC]::Collect()
$null = [System.GC]::WaitForPendingFinalizers()
<sup>注:如果将 $ExcelObj.Visible = $false
,代码将运行得更快。</sup>
英文:
That is because you are cfeating a new Excel COM object inside the loop.
Put that part above the loop, and inside create a new worksheet for each server and fill the data.
Because Get-Printer
may very well return more that one object, you need to loop over the results from that too.
Try
# use full absolute path here
$outFile = 'X:\Somewhere\Documents\Working Folder32023\test.xlsx'
if (Test-Path -Path $outFile -PathType Leaf) { Remove-Item -Path $outFile -Force }
# Create an Excel object
$ExcelObj = New-Object -comobject Excel.Application
$ExcelObj.Visible = $true
# Add a workbook
$ExcelWorkBook = $ExcelObj.Workbooks.Add()
# Get list of servers from text file
$sites = Get-Content -Path "X:\Somewhere\Documents\Working Folder32023\test.txt"
foreach ($site in $sites) {
$counter = 2
# Add a sheet
$ExcelWorkSheet = $ExcelWorkBook.Sheets.Add()
# make this the the active sheet
$ExcelWorkSheet.Activate()
# Rename the worksheet
$ExcelWorkSheet.Name = $site
# Fill in the head of the table
$ExcelWorkSheet.Cells.Item(1, 1) = 'Device Name'
$ExcelWorkSheet.Cells.Item(1, 2) = 'Driver Name'
$ExcelWorkSheet.Cells.Item(1, 3) = 'Port Name'
$ExcelWorkSheet.Cells.Item(1, 4) = 'Share Name'
# Make the table head bold, set the font size and the column width
$ExcelWorkSheet.Rows.Item(1).Font.Bold = $true
$ExcelWorkSheet.Rows.Item(1).Font.size = 15
$ExcelWorkSheet.Columns.Item(1).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(2).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(3).ColumnWidth = 28
$ExcelWorkSheet.Columns.Item(4).ColumnWidth = 28
# Fill in Excel cells with the data obtained from the server
Get-Printer -ComputerName $site | Select-Object Name, DriverName, PortName, ShareName | ForEach-Object {
$ExcelWorkSheet.Columns.Item(1).Rows.Item($counter) = $_.Name
$ExcelWorkSheet.Columns.Item(2).Rows.Item($counter) = $_.DriverName
$ExcelWorkSheet.Columns.Item(3).Rows.Item($counter) = $_.PortName
$ExcelWorkSheet.Columns.Item(4).Rows.Item($counter) = $_.ShareName
$counter++
}
}
# Save the report and close Excel:
$ExcelWorkBook.SaveAs($outFile)
$ExcelWorkBook.Close($true)
$ExcelObj.Quit()
# Clean up the used COM objects
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkSheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkBook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelObj)
$null = [System.GC]::Collect()
$null = [System.GC]::WaitForPendingFinalizers()
<sup>P.S. The code would run faster if you set $ExcelObj.Visible = $false
</sup>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论