正在使用的PowerShell ForEach -parallel文件

时间:2015-04-22 12:42:59

标签: powershell foreach parallel-processing

我有一个带并行循环的简单工作流程,但在写出结果时遇到错误。因为写输出是并行的。我收到错误:

The process cannot access the file because it is being used by another process.

这是我的剧本:

workflow Get-ServerServices 
{
    $srvlst = Get-Content C:\TEMP\srvlst.txt

    foreach -parallel ($srv in $srvlst)
    {
         Get-Service -PSComputerName $srv | Out-File c:\temp\test.txt -Append

    }

}

任何想法?

4 个答案:

答案 0 :(得分:4)

我建议写出临时文件。您可以执行以下代码:

workflow Get-ServerServices 
{
    #Get the temp path of the context user
    $TempPath = Join-Path -Path $([System.IO.Path]::GetTempPath()) -ChildPath "ServerServices"
    New-Item -Path $TempPath -ItemType Directory # and create a new sub directory
    $srvlst = Get-Content C:\TEMP\srvlst.txt

    foreach -parallel ($srv in $srvlst)
    {
        $TempFileName = [System.Guid]::NewGuid().Guid + ".txt" #GUID.txt will ensure randomness
        $FullTempFilePath = Join-Path -Path $TempPath -ChildPath $TempFileName
        Get-Service -PSComputerName $srv | Out-File -Path $FullTempFilePath -Force #Write out to the random file
    }

    $TempFiles = Get-ChildItem -Path $TempPath
    foreach ($TempFile in $TempFiles) {
        Get-Content -Path $TempFile.FullName | Out-File C:\temp.txt -Append #concatenate all the files
    }

    Remove-Item -Path $TempPath -Force -Recurse #clean up
}

基本上你得到临时目录,附加一个新目录,在你的输出中添加一堆名为GUID的文本文件,将它们连成一个,然后删除所有这些文件

答案 1 :(得分:0)

根据变量创建test.txt文件名 - 那么你就没有冲突了。

在流程结束时收集所有单个文件并创建一个包含所有结果的文件 - 然后删除单个文件作为清理的一部分'

答案 2 :(得分:0)

您可以通过使用缓冲区并在最后输出缓冲区内容以更简单的形式执行此操作:

TRUNCATE TABLE `users_sched`;

请参阅technet“并行和序列语句中的变量”了解更多信息

答案 3 :(得分:0)

从 Powershell 6 开始,不再使用带有 Foreach-object 的工作流,参数传递也已更改,请参考下面的示例,看看是否有帮助。

# Default directory variable
$DefaultDir = "C:\temp\sample"

# Log file.
$LogFile = "$($DefaultDir)\Log\Log_$([DateTime]::Now.ToString("yyyyMMdd-HHmmss")).txt"

# Directory where all computers are listed.
$AllComputerFolder = "$($DefaultDir)\ListToCheck\pcs.txt"

# Scan the file that lists all machines to be scanned.
Get-Content $AllComputerFolder | ForEach-Object -Parallel { 
    
    # It will only scan for machines that are connected to the network.
    $TurnedOn = Test-Connection -BufferSize 8 -Count 1 -ComputerName $($_ -replace "\\", "") -Quiet

    # Will scan only for machines that are connected
    IF($TurnedOn -eq $True){

        # Run your script, notice the new way of passing parameters within Foreach-object: $using:DefaultDir
        $Return = ."$using:DefaultDir\Script\script.ps1" $_        
        
        # Writes in file the return of the processing of each machine.
        Add-Content -Path "$using:LogFile" -Value $Return 
    }ELSE{
        # Writes the return of machines with error to file
        Add-Content -Path "$using:LogFile" -Value "$($_) : $([DateTime]::Now.ToString("yyyyMMdd-HHmmss")) : Machine turned-off or out of the network"  
    }  

# Number of simultaneous threads
} -ThrottleLimit 20