Проблема при экспорте вывода в CSV в PowerShell Parallel Workflow
Я использую приведенный ниже скрипт, чтобы получить подробную информацию о состоянии порта нескольких удаленных серверов.
Workflow Test-OpenPortWF
{
[CmdletBinding()]
param
(
[Parameter(Position=0)]
[String[]]$Target,
[Parameter(Mandatory=$true, Position=1)]
[int]$Port
)
If(Test-Path -Path C:\Temp\Results.csv -ErrorAction SilentlyContinue){ Remove-Item -Path C:\Temp\Results.csv -Force }
If(Test-Path -Path C:\Temp\Report.csv -ErrorAction SilentlyContinue){ Remove-Item -Path C:\Temp\Report.csv -Force }
foreach -parallel -throttle 50 ($t in $Target)
{
Sequence
{
$Out = Test-NetConnection -ComputerName $t -Port $Port -WarningAction SilentlyContinue | Select ComputerName,RemoteAddress,RemotePort,@{N="PortTestSucceeded"; E={$_.tcpTestSucceeded}}
Start-Sleep -Milliseconds 100
$Out | Export-Csv -Path C:\Temp\Results.csv -NoTypeInformation -Append
}
}
InlineScript
{
Import-Csv c:\Temp\Results.csv | Select ComputerName,RemoteAddress,RemotePort,PortTestSucceeded | Export-Csv c:\Temp\Report.csv -NoTypeInformation
Remove-Item c:\Temp\Results.csv -Force
Write-Host "Execution completed! Check Report.csv for output."
}
}
# Example use for multiple servers for one port 5985 and export results to CSV file.
# Assuming all target servers are found in c:\temp\Servers.txt (new line separated)
#
# PS C:\Temp> Test-OpenPortWF -Target (Get-Content .\Servers.txt) -Port 5985
В основном это работает, но не может дать полные результаты, потому что, поскольку мы запускаем это как параллельный рабочий процесс, если два сервера завершают обработку одновременно, он попытается записать результаты в файл CSV одновременно для обоих серверы, что приводит к ошибке ниже. И около 6% результатов отсутствуют в файле CSV:
Microsoft.PowerShell.Utility \ Write-Error: процессу не удается получить доступ к файлу "C:\Temp\Results.csv", поскольку он используется другим процессом. В Test-OpenPortWF:54 char:54 + + CategoryInfo: NotSpecified: (:) [Write-Error], CmdletInvocationException + FullyQualifiedErrorId: System.Management.Automation.CmdletInvocationException,Microsoft.PowerShell.Commands.WriteErhostCameName +ameCompName: +
Как мы можем обойти эту проблему?
1 ответ
Поскольку вы используете параллельную обработку, могут возникнуть конфликты, когда несколько потоков пытаются вывести в ваш файл CSV (вы столкнулись с блокировками файлов, судя по ошибке)
Вместо этого попробуйте вывести в отдельные временные файлы (с уникальными именами) и в конце объединить эти файлы в один отчет (и удалить временные файлы).
Например, добавьте счетчик ($x) в цикл foreach, который увеличивается с каждой итерацией ( $x++), затем выведите результаты в -Path "C:\Temp\Results_$x.csv"
Вам нужно использовать мьютекс, чтобы заблокировать операцию ввода-вывода файла. Измените свою последовательность как таковую:
Sequence
{
$Out = Test-NetConnection -ComputerName $t -Port $Port -WarningAction SilentlyContinue | Select ComputerName,RemoteAddress,RemotePort,@{N="PortTestSucceeded"; E={$_.tcpTestSucceeded}}
$mutex = New-Object System.Threading.Mutex $false, 'NetConnectionTest'
$mutex.WaitOne() > $null;
$Out | Export-Csv -Path C:\Temp\Results.csv -NoTypeInformation -Append
$mutex.ReleaseMutex();
}