【问题标题】:How can I pipe Write-Output to Export-Csv?如何将 Write-Output 通过管道传输到 Export-Csv?
【发布时间】:2017-05-30 20:39:20
【问题描述】:

我有以下“ping 脚本”,我想在其中使用数组和 Export-Csv cmdlet 将输出写入 CSV 文件而不是 txt 文件。

我首先尝试通过管道将Write-Output 传递给Export-Csv,直到读到您无法将字符串传递给Export-Csv 并且必须先将它们转换为对象。

我不太明白如何在 PowerShell 中使用数组。

Param(
    [Parameter(Mandatory=$true, position=0)][string]$csvfile
)

$ColumnHeader = "Hostname"

Write-Host "Reading file" $csvfile
$ipaddresses = Import-Csv $csvfile | Select-Object $ColumnHeader

Write-Host "Started Pinging.."
foreach ($ip in $ipaddresses) {
    if (Test-Connection $ip.("Hostname") -Count 1 -Quiet) {
        Write-Output $ip.("Hostname") "Ping succeeded." |
            Out-File -FilePath "C:\temp\pingresults.txt" -Append
    } else {
        Write-Output $ip.("Hostname") "Ping failed." |
            Out-File -FilePath "C:\temp\pingresults.txt" -Append
    }
}

Write-Host "Pinging Completed."

【问题讨论】:

    标签: powershell


    【解决方案1】:

    当然,您可以将字符串通过管道传输到Export-Csv。只是结果可能不是您所期望的,因为Export-Csv 将输入对象的属性导出为输出文件的字段。 ;) 字符串对象只有一个属性 (Length),因此您最终会得到一个列出输入字符串长度的输出文件。

    要获得列出主机名(或 IP 地址)以及 ping 结果的输出 CSV,您需要构造具有 2 个属性的对象。在 PowerShell 中执行此操作的最佳方法是管道:

    Import-Csv $csvfile | ForEach-Object {
        New-Object -Type PSObject -Property ([ordered]@{
            Hostname = $_.Hostname
            Online   = [bool](Test-Connection $_.Hostname -Count 1 -Quiet)
        }
    } | Export-Csv 'C:\path\to\output.csv' -NoType
    

    由于您基本上只是想向输入数据添加一个属性,因此您可以采用更简单的方法并使用 calculated property 添加 ping 结果:

    Import-Csv $csvfile |
        Select-Object Hostname,
            @{n='Online';e={[bool](Test-Connection $_.Hostname -Count 1 -Quiet)}} |
        Export-Csv 'C:\temp\pingresults.csv' -NoType
    

    不建议在循环中追加到数组,因为追加本质上是创建一个大小增加的新数组,复制旧数组中的所有元素,然后将新元素添加到新(空)槽并释放旧数组.

    【讨论】:

    • 我认为您最好导入一些东西,对所有 IP/计算机名称运行一次 Test-Connection,然后解析结果。可以肯定的是,与每台机器运行一次 Test-Connection 相比,这种方式的开销会更少。
    • @Ansgar Wiechers - 我尝试了使用计算属性的第二个示例,但是我只获得了“主机名”和“在线”列标题,但没有填充其他数据。
    • @TheMadTechnician 如果总持续时间是一个问题,我会将连接测试作为作业运行(当然,运行空间或工作流也可以工作),并在将结果导出到 CSV 之前收集结果。
    • @Heisenberg 我对此表示怀疑。请update your question 提供示例输入和您使用的确切代码。
    • @Ansgar Wiechers - 我再次测试它并且它工作。自我提醒:早上喝咖啡后的测试总是比凌晨 1 点更好。非常感谢。您对涉及该主题的良好 PS 学习资源有什么建议,以便我可以更深入地研究一下?
    【解决方案2】:

    你可以创建一个 $pingresult 数组:

    [string[]] $pingresult= @()
    

    然后简单地填充它:

    $pingresult += ip.("Hostname")," ping succeeded" -join"" 
    

    $pingresult += ip.("Hostname")," ping failed" -join"" 
    

    取决于条件。

    最后你可以将数组导出到 csv:

    convertfrom-csv -inputobject $pingresult | export-csv -path ... 
    

    【讨论】:

    • 我是否在 for 循环之前定义数组?
    • 是的,在循环之前的任何地方,在 $columnheader 之后,让定义保持在一起
    • 这不会做 OP 想要的。完全没有。将字符串数组导入Export-Csv 会创建一个输出 CSV,其中包含数组中各个字符串的长度。
    • 这仍然不能满足 OP 的要求,因为主机名和响应仍然不是单独的字段,并且第一个数据行将成为 CSV 标头。请在发布答案之前测试您的代码。
    • 要使您的方法有效,您必须使用正确的分隔符 ($ip.Hostname, 'ping succeeded' -join ',') 加入主机名和响应,并在转换期间添加标头 (ConvertFrom-Csv ... -Header 'Hostname', 'Response')。但是您也可以完全放弃转换并将字符串直接写入输出文件 ('Hostname,Response', $pingresult | Set-Content output.csv)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-08
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多