将Powershell输出附加到Excel文件

我正在写一个powershell脚本,将从工作中归档的外部硬盘(通过USB硬盘底座连接)收集一些信息,我希望脚本将这个信息添加到Excel文件作为最后一个步骤之一。 我对Powershell有些熟悉,但与使用Powershell处理Excel文件不太一样。

基本上,脚本需要能够确定工作表中的第一个空行,然后将一些信息粘贴到该行的列A,B,C等中。 我已经find了几个不同的方法来做这件事,但由于某些原因,将持有行号添加信息总是似乎是空的variables。 我不知道如果我做错了什么,所以任何意见将不胜感激。

这有点长,但是这里是我的脚本在当前状态。 底部2部分(标记为“将信息附加到Excel文档…”)是我发现的脚本示例(和源链接),据说我正在尝试做什么。

先谢谢您的帮助。

 CLS
 ($ null = reg.exe卸载HKLM \ EXTERNAL)2> $ null
  #IF($ AdminCred -eq $ null){新variables-Name AdminCred -Value(Get-Credential -UserNamepipe理员-Message“inputpipe理员帐户的密码”)-Scope Global -Force}
 $ null = reg.exe加载HKLM \ EXTERNAL D:\ Windows \ System32 \ Config \ SYSTEM 

if($ LASTEXITCODE -eq 0){
#find主机名
新variables-Name主机名-Value((Get-ItemProperty -Path HKLM:\ EXTERNAL \ ControlSet001 \ Control \ ComputerName \ ComputerName).ComputerName)-Scope Global -Force
[GC] ::收集()
IF($ LASTEXITCODE -ne 0){写主机LastExitCode是$ LASTEXITCODE}
$ null = reg.exe卸载HKLM \ EXTERNAL

#Find the serial number Clear-Variable -Name SerialNumber -Scope Global -Force New-Variable -Name SerialNumber -Value (Read-Host "Please enter the HDD's serial number.") -Scope Global -Force # I was originally trying to programatically gather the serial number of the HDD, but that is an issue for another post. # $Disks = Get-WMIObject -class win32_PhysicalMedia # $SerialNumber = foreach($Disk in $Disks) {IF ($Disk.SerialNumber -ne ' WD-WCC2EAV91692') {Write-Host $Disk.SerialNumber}} #Find usernames $Win7 = Test-Path D:\Users $WinXP = Test-Path 'D:\Documents and Settings' IF ($Win7 -eq 'True') {$Win7Users = (Get-ItemProperty -Path D:\Users\* -Exclude ADMINI~1,Administrator,Public,TEMP,UpdatusUser,'All Users',User).name} IF ($WinXP -eq 'True') {$WinXPUsers = (Get-ItemProperty -Path 'D:\Documents and Settings\*' -Exclude ADMINI~1,Administrator,Public,TEMP,UpdatusUser,'All Users',User).name} #Display Hostname and Usernames Write-Host Hostname: -ForegroundColor Green $hostname Write-Host Write-Host Serial Number: -ForegroundColor Green $SerialNumber Write-Host Write-Host User List: -ForegroundColor Green $Win7Users $WinXPUsers #Print the output Out-File -FilePath C:\HDDinfo.txt -InputObject (New-Object -TypeName String -ArgumentList "Hostname:") Out-File -FilePath C:\HDDinfo.txt -InputObject $Hostname -Append Add-Content -Path C:\HDDinfo.txt `n Out-File -FilePath C:\HDDinfo.txt -InputObject (New-Object -TypeName String -ArgumentList "Serial Number:") -Append Out-File -FilePath C:\HDDinfo.txt -InputObject $SerialNumber -Append Add-Content -Path C:\HDDinfo.txt `n Out-File -FilePath C:\HDDinfo.txt -InputObject (New-Object -TypeName String -ArgumentList "User List:") -Append Out-File -FilePath C:\HDDinfo.txt -InputObject $Win7Users -Append Out-File -FilePath C:\HDDinfo.txt -InputObject $WinXPUsers -Append Out-Printer \\servername\printername -InputObject (Get-Content C:\HDDinfo.txt) #Append the info to an Excel document - Possible method 1 # http://stackoverflow.com/questions/8452408/using-powershell-to-append-a-table-to-the-end-of-an-excel-file-the-last-row $ExcelPath = "C:\HDDInfo.xlsx" $xldown = -4121 # see: http://msdn.microsoft.com/en-us/library/bb241212(v=office.12).aspx $xlup = -4162 $Excel = New-Object -ComObject Excel.Application $Excel.Visible = $False $ExcelWorkBook = $Excel.Workbooks.Open($ExcelPath) $ExcelWorkSheet = $Excel.WorkSheets.item("Sheet1") $ExcelWorkSheet.activate() # Find the last used cell {$lastRow = $ExcelWorkSheet.Cells.Range("A1048576").End($xlup).row $nextRow = $lastRow + 1 $range = $ExcelWorkSheet.Range("A$nextRow") $ExcelWorkSheet.Paste($range)} # Append info to the spreadsheet $ExcelWorkSheet.Cells.Item($row,1) = 'COLUMN 1 Text' $ExcelWorkSheet.Cells.Item($row,2) = 'COLUMN 2 Text' $ExcelWorkSheet.Cells.Item($row,3) = 'COLUMN 3 Text' $ExcelWorkSheet.Cells.Item($row,4) = 'COLUMN 4 Text' $ExcelWorkSheet.Cells.Item($row,5) = 'COLUMN 5 Text' # Save and close $ExcelWorkBook.Save() $ExcelWorkBook.Close() $Excel.Quit() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel) Stop-Process -Name EXCEL -Force #Append the info to an Excel document - Possible method 2 # http://www.adamtheautomator.com/powershell-excel-worksheet/ $excel_file_path = 'C:\HDDInfo.xlsx' # Instantiate the COM object $Excel = New-Object -ComObject Excel.Application $ExcelWorkBook = $Excel.Workbooks.Open($excel_file_path) $ExcelWorkSheet = $Excel.WorkSheets.item("sheet1") $ExcelWorkSheet.activate() # Find the first row where the first 7 columns are empty $row = ($ExcelWorkSheet.UsedRange.Rows | Where-Object { ($_.Value2 | Where-Object {$_ -eq $null}).Count -eq 7 } | select -first 1).Row $ExcelWorkSheet.Cells.Item($row,1) = 'COLUMN 1 Text' $ExcelWorkSheet.Cells.Item($row,2) = 'COLUMN 2 Text' $ExcelWorkSheet.Cells.Item($row,3) = 'COLUMN 3 Text' $ExcelWorkSheet.Cells.Item($row,4) = 'COLUMN 4 Text' $ExcelWorkSheet.Cells.Item($row,5) = 'COLUMN 5 Text' # Save and close $ExcelWorkBook.Save() $ExcelWorkBook.Close() $Excel.Quit() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel) Stop-Process -Name EXCEL -Force }

好吧,CSV是好的,但是当呈现数据或者与其他人共享时,它不是很好,所以我完全想把数据转储到Excel。 要将数据添加到Excel工作表中,我强烈build议有一个对象数组来启动,然后使用ConvertTo-CSV cmdlet, Clip并粘贴到Excel中。

你并没有真正说明你想要粘贴到Excel中,但是我将假设HostName,Serial#和用户。 由于用户列表是一个数组,所以我将它join到一个string中,以便Excel不会为此而烦恼,并粘贴大量的空行。

那么让我们把这个信息放到一个对象中。 有几种方法可以做到这一点,但我更喜欢(应该在PS v3及更高版本上工作)的方式是这样的:

 $Record = [PSCustomObject]@{ 'Hostname' = $Hostname 'Serial Number' = $Serialnumber 'Users' = $(If($XPUsers){$XPUsers}Else{$Win7Users}) -join ', ' } 

现在,如果我们将其转换为ConvertTo-Csv并使用-NoTypeInformation开关使其制表符分隔,则会出现如下所示的内容:

 PS C:\Temp> $Record|ConvertTo-Csv -del "`t" -notype "Hostname" "Serial Number" "Users" "Computer001" "42K6NNZ" "TMTech, Andrew" 

现在,如果您不希望将标题行粘贴到您的Excel文件中,那么每次我们将其传送到Select -Skip 1并解决该问题。 但是现在我们将包括它。 这里是我将用于获取该信息到Excel中的代码。

 #Launch Excel $XL = New-Object -ComObject Excel.Application #Open the workbook $WB = $XL.Workbooks.Open("C:\HDDInfo.xlsx") #Activate Sheet1, pipe to Out-Null to avoid 'True' output to screen $WB.Sheets.Item("Sheet1").Activate() | Out-Null #Find first blank row #, and activate the first cell in that row $FirstBlankRow = $($xl.ActiveSheet.UsedRange.Rows)[-1].Row + 1 $XL.ActiveSheet.Range("A$FirstBlankRow").Activate() #Create PSObject with the properties that we want, convert it to a tab delimited CSV, and copy it to the clipboard $Record = [PSCustomObject]@{ 'Hostname' = $Hostname 'Serial Number' = $Serialnumber 'Users' = $(If($XPUsers){$XPUsers}Else{$Win7Users}) -join ', ' } $Record | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | Clip #Paste at the currently active cell $XL.ActiveSheet.Paste() | Out-Null # Save and close $WB.Save() | Out-Null $WB.Close() | Out-Null $XL.Quit() | Out-Null #Release ComObject [System.Runtime.Interopservices.Marshal]::ReleaseComObject($XL) 

现在,你可能不得不改变自定义对象,但应该做你想做的。 如果您的脚本一次处理多个项目,则可以制作一组对象,并以这种方式将其全部粘贴到Excel中。

编辑:好的,在哪里跳过标题,并将名称粘贴到自己的单元格中…

正如我所说,你会pipe道:

 `$Record|ConvertTo-Csv -del "`t" -notype` 

进入|Select -Skip 1 。 这可能会让我感到困惑,因为那时我把它放进了| Clip | Clip ,但是如果考虑pipe道是如何工作的,以及每个pipe道如何从前一个段获取输出,那么将ConvertTo-CSVpipe道Select -Skip 1Select -Skip 1 ConvertTo-CSV Select -Skip 1以便跳过第一行(这是标头的位置),然后通过pipe道Clip将结果复制到剪贴板中。当您将其分解时,这是有意义的。 该命令将如下所示:

 $Record | ConvertTo-Csv -del "`t" -notype | Select -Skip 1 | Clip 

现在,将每个用户粘贴到他们自己的单元格中,您需要更具体。 你想水平跨越单元格,还是垂直? 如果你想跨越水平,那么事情就变得复杂了。 基本上我们要做的是创build对象,然后使用Add-Member将属性添加到对象,每个用户一个。

 #Create PSObject with the properties that we want, convert it to a tab delimited CSV, and copy it to the clipboard $Record = [PSCustomObject]@{ 'Hostname' = $Hostname 'Serial Number' = $Serialnumber } #Compile users, and add a member to the object for each user [Array]$Users = If($WinXPUsers){$WinXPUsers}Else{$Win7Users} For($i = 0; $i -lt $Users.Count; $i++){ $Record | Add-Member "User$i" $Users[$i] } $Record | ConvertTo-Csv -Delimiter "`t" -NoTypeInformation | Select -Skip 1 | Clip 

这将创build一个这样的条目(标题留在参考,他们不会出现在Excel中):

 Hostname Serial Number User0 User1 -------- ------------- ----- ----- Computer001 42K6NNZ TMTech Andrew 

如果要垂直列出每个用户,可以为每个用户做一个对象,但只在第一个用户上包含主机和S / N。

 [Array]$Users = If($WinXPUsers){$WinXPUsers}Else{$Win7Users} [Array]$Record = [PSCustomObject]@{ 'Hostname' = $Hostname 'Serial Number' = $Serialnumber 'Users' = $Users[0] } $Record += $Users | Select -Skip 1 | ForEach{[PSCustomObject]@{ 'Hostname' = '' 'Serial Number' = '' 'Users' = $_ }} 

这将输出这样的东西(标题留在参考,他们不会出现在Excel中):

 Hostname Serial Number Users -------- ------------- ----- Computer001 42K6NNZ TMTech Andrew