Проблема при экспорте вывода в 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();
    }
Другие вопросы по тегам