0

我正在使用下面的脚本来获取有关多个远程服务器的端口状态的详细信息。

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 文件服务器导致以下错误。CSV 文件中缺少大约 6% 的结果:

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.WriteErrorCommand + PSComputerName : [localhost]

我们怎样才能解决这个问题?

4

2 回答 2

1

因为您使用并行处理,所以当多个线程尝试输出到您的 csv 文件时可能会发生冲突(根据错误判断您会遇到文件锁)

相反,尝试输出到单个临时文件(具有唯一名称),最后将这些文件合并到一个报告中(并删除临时文件)

例如,在 foreach 循环中添加一个计数器($x),每次迭代都会递增( $x++ ),然后将结果输出到 -Path "C:\Temp\Results_$x.csv"

于 2018-08-10T11:45:22.533 回答
1

您需要使用互斥锁来锁定文件 I/O 操作。修改您的序列,如下所示:

    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();
    }
于 2020-05-25T04:27:25.090 回答