简体   繁体   English

Powershell - 正确导出 CSV 文件

[英]Powershell - Export CSV file correctly

I hope someone can help me with this.我希望有人能帮我解决这个问题。 We want to see which computers have a HDD and SDD.我们想看看哪些计算机有 HDD 和 SDD。 I have an excel.csv of the computers.我有一个 excel.csv 的计算机。 I import the computers.我进口电脑。 But when I export them I never see the csv or its incomplete.但是当我导出它们时,我从未看到 csv 或其不完整的。 Can you tell what part of my script is incorrect.你能告诉我脚本的哪一部分是不正确的。 Thank you谢谢

$computers = Import-csv -path "C:\Temp\MediaType\Computers.csv" 
foreach ($computer in $computers) { 
    Write-Host "`nPulling Physical Drive(s) for $computer"
    if((Test-Connection -BufferSize 32 -Count 1 -ComputerName $computer -Quiet)){ 
        Invoke-Command -ComputerName $computer -ScriptBlock { 
            Get-WmiObject -Class MSFT_PhysicalDisk -Namespace root\Microsoft\Windows\Storage | Select-Object sort -Property PSComputerName, Model, SerialNumber, MediaType
            Export-Csv C:\Temp\devices.csv
        }
    }
}

Continuing from my comment.继续我的评论。 . . . . as is, you would be exporting the results to the remote machine.照原样,您会将结果导出到远程机器。 That's if it was piped properly.那是如果它被正确地管道 You're currently missing a pipe ( | ) before Export-Csv .您当前在Export-Csv之前缺少管道 ( | )。

Also, there's no need to invoke the command, as Get-WMIObject has a parameter for remote computers: -ComputerName .此外,无需调用该命令,因为Get-WMIObject具有用于远程计算机的参数: -ComputerName It's also a deprecated cmdlet that has been replaced by Get-CimInstance .它也是一个已弃用的 cmdlet,已被Get-CimInstance取代。

$ExportTo  = "C:\Temp\devices.csv" 
$computers = Import-csv -path "C:\Temp\MediaType\Computers.csv" 
    foreach ($computer in $computers) 
    { 
        Write-Host "`nPulling Physical Drive(s) for $computer" 
        if (Test-Connection -BufferSize 32 -Count 1 -ComputerName $computer -Quiet) {
         
            Get-CimInstance -ClassName MSFT_PhysicalDisk -Namespace root\Microsoft\Windows\Storage -ComputerName $computer | 
                Select-Object -Property PSComputerName, Model, SerialNumber, MediaType | 
                Export-Csv -Path $ExportTo -Append -NoTypeInformation

        } 
    }

Side Note : Get-CimInstance accepts an array of strings, meaning you can pass the entirety of $Computers to it.旁注Get-CimInstance接受字符串数组,这意味着你可以整体通过$Computers给它。 This should allow it to perform the the query in parallel , vs serial ( one at a time ):这应该允许它并行执行查询,而不是串行一次一个):

$ExportTo  = "C:\Temp\devices.csv" 
$computers = Import-csv -path "C:\Temp\MediaType\Computers.csv" 

Get-CimInstance -ClassName MSFT_PhysicalDisk -Namespace root\Microsoft\Windows\Storage -ComputerName $computers -ErrorAction SilentlyContinue | 
    Select-Object -Property PSComputerName, Model, SerialNumber, MediaType |
    Export-Csv -Path $ExportTo -Append -NoTypeInformation

Performing queries one at a time doesn't necessarily mean it's bad.一次执行一个查询并不一定意味着它很糟糕。 You can actually have more control over the control of flow for your script.实际上,您可以更好地控制脚本的流程

To specifically answer the question:具体回答这个问题:

How do I correctly export a CSV file (use Export-Csv )?如何正确导出 CSV 文件(使用Export-Csv )?

You might want to read about PowerShell pipelines and PowerShell cmdlets .您可能想阅读有关PowerShell 管道PowerShell cmdlet 的信息
Basically, a cmdlet is a single command that participates in the pipeline semantics of PowerShell.基本上,cmdlet 是参与 PowerShell 管道语义的单个命令。 A well written cmdlet is implemented for the Middle of a Pipeline which means that it processes (" streams ") each individual item received from the previous cmdlet and passes it immediately to the next cmdlet (similar to how items are processed in an assembly line where you can compare each assembly station as a cmdlet). 为流水线中间实现了一个写得很好的 cmdlet 这意味着它处理(“”)从前一个 cmdlet 接收到的每个单独的项目,并立即将其传递给下一个 cmdlet(类似于在装配线上处理项目的方式)您可以将每个装配站作为一个 cmdlet 进行比较)。

To better show this, I have created an easier minimal, complete and verifiable example (MVCE) and replaced your remote command ( Invoke-Command ... ) which just an fake [pscustomobject]@{ ... } object.为了更好地展示这一点,我创建了一个更简单、完整且可验证的示例 (MVCE),并替换了您的远程命令 ( Invoke-Command ... ),它只是一个假的[pscustomobject]@{ ... }对象。
With that;接着就,随即;

  • I have used Get-Content rater then Import-Csv as your example suggest that Computers.csv is actually a text file which list of computers and not a Csv file which would require a (eg Name ) header and a using this property accordingly (like Computer.Name ).我使用Get-Content ratingr 然后Import-Csv作为您的示例表明Computers.csv实际上是一个文本文件,其中包含计算机列表,而不是一个需要(例如Name )标头和相应使用此属性的Csv文件(例如Computer.Name .名称)。
  • To enforce the pipeline advantage/understanding, I am also using the ForEach-Object cmdlet rather than the the foreach statement which is [ usually faster] consider faster but which is probably not the case here as for the foreach statement requires to load all $Computers into memory where a well written pipeline will immediately starts ( remotely ) processing the first computer.为了加强管道优势/理解,我还使用了ForEach-Object cmdlet而不是foreach语句,后者 [通常更快] 考虑更快,但这里可能不是这种情况,因为foreach语句需要加载所有$Computers到内存中,编写良好的管道将立即开始(远程)处理第一台计算机。

Now, coming back on the question " How do I correctly export a CSV file " which a better understanding of the pipeline, you might place it here:现在,回到问题“我如何正确导出 CSV 文件”,可以更好地理解管道,您可以将它放在这里:

Get-Content .\Computers.txt |ForEach-Object {
    [pscustomobject]@{
        PSComputerName = $_
        Model          = "Model"
        SerialNumber   = '{0:000000}' -f (Get-Random 999999)
        MediaType      = "MydiaType"
    } |Export-Csv .\Devices.csv -Append
}

As commented by @lit , this would require the -Append switch which might not be desired as every time you rerun your script this would append the results to the .\\Devices.csv file.正如@lit所评论的那样,这将需要-Append开关,这可能是不需要的,因为每次重新运行脚本时,这会将结果附加到.\\Devices.csv文件。
Instead you might actually want do this:相反,您可能实际上想要这样做:

Get-Content .\Computers.txt |ForEach-Object {
    [pscustomobject]@{
        PSComputerName = $_
        Model          = "Model"
        SerialNumber   = '{0:000000}' -f (Get-Random 999999)
        MediaType      = "MydiaType"
    }
} |Export-Csv .\Devices.csv

Note the differences: the Export-Csv is placed outside the loop and the -Append switch is removed.请注意不同之处: Export-Csv被放置在循环之外并且-Append开关被移除。

Explanation解释
As with eg the ForEach-Object cmdlet, the Export-Csv cmdlet has internally Begin , Process and End blocks .与例如ForEach-Object cmdlet 一样, Export-Csv cmdlet 在内部具有BeginProcessEnd In the Begin block , the Export-Csv cmdlet prepares the csv file with header etc. and overwrites any existing file.Begin块中, Export-Csv cmdlet 准备带有标题等的csv文件覆盖任何现有文件。 In the Process block (which runs for each item received from the pipeline) it adds each line (data record) to the file.Process块(为从管道接收的每个项目运行)中,它将每一行(数据记录)添加到文件中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM