Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell ForEach -parallel file in use

I have a simple workflow with a parallel loop but i run into an error when writing out the result. Because the write-output is parallel. I get the error:

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

Here is my script:

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

    }

}

any idea?

like image 951
aston_zh Avatar asked Dec 01 '25 06:12

aston_zh


2 Answers

I would suggest writing out to temporary files. You could do something like the below code:

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
}

Basically you are getting the temp dir, appending a new directory, adding a bunch of GUID named text files with your output, concatenating them all into one, and then removing all of them

like image 119
SomeShinyObject Avatar answered Dec 03 '25 22:12

SomeShinyObject


You can do it in a simpler form by using a buffer and outputting buffer contents at the end:

workflow Get-ServerServices 
{
    $srvlst = Get-Content C:\TEMP\srvlst.txt
    $out = @()

    foreach -parallel ($srv in $srvlst)
    {
         $WORKFLOW:out += (Get-Service -ComputerName $srv)

    }

    Out-File c:\temp\test.txt -InputObject $out

}

see technet "Variables in Parallel and Sequence Statements" for more info

like image 20
Avner Avatar answered Dec 03 '25 22:12

Avner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!