Use Export-Csv instead of Write-Output/Out-File

2020-04-16 18:26发布

I have the following "ping script" in which I would like to use an array along with the Export-Csv cmdlet to write the output to a CSV file rather than a txt file.

I first tried piping Write-Output to Export-Csv until reading that you cannot pipe strings to Export-Csv and must convert them into objects first.

I don't quite understand how to work with arrays in 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
2条回答
冷血范
2楼-- · 2020-04-16 18:57

you can create a $pingresult array as:

[string[]] $pingresult= @()

then to populate it simply do:

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

or

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

depending on the conditional.

finally you can export the array to csv:

convertfrom-csv -inputobject $pingresult | export-csv -path ... 
查看更多
够拽才男人
3楼-- · 2020-04-16 19:03

Of course you can pipe strings into Export-Csv. It's just that the result probably won't be what you expect, since Export-Csv exports the properties of the input objects as the fields of the output file. ;) String objects only have one property (Length), so you'd end up with an output file listing the lengths of the input strings.

To get an output CSV that lists the hostname (or IP address) along with the ping result you need to construct objects with 2 properties. The best way to do this in PowerShell is a pipeline:

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

Since you basically just want to add a property to the input data you can take an even simpler approach and add the ping result with a calculated property:

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

Appending to an array in a loop is not recommended, because appending essentially creates a new array with increased size, copies all elements from the old array, then adds the new elements to the new (empty) slots and releases the old array.

查看更多
登录 后发表回答