Существует два распространенных подхода к таким вещам:
Используйте цикл foreach
и соберите данные в переменную, затем экспортируйте эту переменную в CSV.
$data = foreach ($server in (Get-Content 'input.txt')) {
# do stuff here, then build a custom object from the results
New-Object -Type PSObject -Property @{
'ComputerName' = $server
...
}
}
$data | Export-Csv 'output.csv' -NoType
Используйте цикл ForEach-Object
, в котором вы читаете ввод из конвейера и передаете вывод в Export-Csv
через конвейер.
Get-Content 'input.txt' | ForEach-Object {
# do stuff here, then build a custom object from the results
New-Object -Type PSObject -Property @{
'ComputerName' = $_
...
}
} | Export-Csv 'output.csv' -NoType
Первый подход обеспечивает лучшую производительность, но имеет недостаток, заключающийся в том, что все данные считываются в память (циклы foreach
не могут записывать в конвейер).Если у вас есть большие объемы данных, которые могут привести к исчерпанию памяти.
Последний подход устойчив к истощению памяти, поскольку конвейер обычно обрабатывает один объект за раз.Общая обработка выполняется медленнее, чем цикл foreach
.
Какой из этих двух подходов лучше всего подходит для данного сценария, зависит от фактических данных, которые вы обрабатываете.
Я бы не рекомендовалпомещая Export-Csv
в вашу функцию обработки, по крайней мере, не делая ее необязательной.С одной стороны, это не очень хорошая практика с точки зрения производительности.При вызове функции в цикле файл должен быть открыт повторно.Лучше всего открыть его один раз и закрыть после того, как все данные записаны.Кроме того, вы получаете гибкость, отделяя обработку от вывода.Пусть ваша функция возвращает «сырые» данные, и вы можете делать с ними все, что вам нужно (запись в CSV, отображение пользователю, передача в другое приложение, ...).
Пусть ваша функция принимаетвход конвейера, например, такой:
function Invoke-Foo {
[CmdletBinding()]
Param(
[Parameter(
Position=0,
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true
)]
$InputObject,
...
)
Begin {
# initialize stuff here
}
Process {
$InputObject | ForEach-Object {
# do stuff here, then build a custom object from the results
New-Object -Type PSObject -Property @{
...
}
}
}
End {
# cleanup goes here
}
}
, и вы можете использовать его в foreach
петле
$data = foreach ($server in (Get-Content 'input.txt')) {
Invoke-Foo $server
}
$data | Export-Csv 'output.csv' -NoType
, а также в конвейере:
Get-Content 'input.txt' | Invoke-Foo | Export-Csv 'output.csv' -NoType
Если по какой-то причине у вас должна быть возможность записывать данные в файл из функции, я бы, вероятно, изменил функцию следующим образом:
function Invoke-Foo {
[CmdletBinding()]
Param(
...
[Parameter(Mandatory=$false)]
[string]$Path,
[Parameter(Mandatory=$false)]
[switch]$Append,
...
)
...
Process {
$InputObject | ForEach-Object {
# do stuff here, then build a custom object from the results
$obj = New-Object -Type PSObject -Property @{
...
}
if ($PSBoundParameters.ContainsKey('Path')) {
$obj | Export-Csv $Path -NoType -Append:$Append.IsPresent
} else {
$obj
}
}
}
...
}