Dixon Joseph Dalmeida
Dixon Joseph Dalmeida

Reputation: 322

How can i write logs to single file using foreach-object parallel?

Issue

I am trying to write logs to a single log file using the PSlogging PowerShell module.

The Script is using the Foreach-object parallel.

The script works, But sometimes the script gets stuck in between.

Please help me to resolve it? Is there a better way to achieve this?

Powershell core 7

code

#Script Version
$sScriptVersion = '1.0'

$sScriptVersion = '1.0'
$sLogName = 'custom.log'
#Log File Info
$sLogPath = "C:\Users\Dixon\Desktop\automation\azure\log"
$sLogFile = Join-Path -Path $sLogPath -ChildPath $sLogName

Start-Log -LogPath  $sLogPath -LogName $sLogName  -ScriptVersion $sScriptVersion

$allServers = $(Get-AzVM -Status) 

try {
    $allServers | ForEach-Object -parallel {

        $sScriptVersion = '1.0'
        $sLogName = "parallel-" + $_.Name +".log"
        #Log File Info
        $sLogPath = "C:\Users\Dixon\Desktop\automation\azure\log"
        $sLogFile = Join-Path -Path $sLogPath -ChildPath $sLogName

        Import-Module .\modules\pwshAzMod\pwshAzMod.psd1 -Force

        $version = "1.0.11"
       
        
        $vmName = $_.Name
        $vmLocation = $_.Location
        $vmResourceGroupName = $_.ResourceGroupName
        $powerState = $_.PowerState | Out-String
        if ($powerState -match "running") {
            if ($_.OSProfile.WindowsConfiguration) {
                Write-LogInfo -LogPath $sLogFile -Message  "Start --- Windows Servers --- $vmResourceGroupName $vmLocation $vmName $version $powerState"
                Write-LogInfo -LogPath $sLogFile -Message  "Done --- Windows Servers --- $vmResourceGroupName $vmLocation $vmName $version"
            } 
            elseif ($_.OSProfile.LinuxConfiguration) {
 
                $extensionName = "CustomScript"
                Write-LogInfo -LogPath $sLogFile -Message  "Start --- Linux Servers --- $vmResourceGroupName $vmLocation $vmName $version $powerState"
                Write-LogInfo -LogPath $sLogFile -Message  "Done --- Linux Servers --- $vmResourceGroupName $vmLocation $vmName $version"
            }
            else {
                Write-LogInfo -LogPath $sLogFile -Message  "OS Type not handled"
            }
        }
        else {
            if ($_.OSProfile.WindowsConfiguration) {
                Write-LogInfo -LogPath $sLogFile -Message  "Deallocated --- Windows Servers --- $vmResourceGroupName $vmLocation $vmName $version $powerState"
            }
            elseif ($_.OSProfile.LinuxConfiguration) {
                Write-LogInfo -LogPath $sLogFile -Message  "Deallocated --- Linux Servers --- $vmResourceGroupName $vmLocation $vmName $version $powerState"
            }
            else {
                Write-LogInfo -LogPath $sLogFile -Message "Deallocated --- Other Servers --- $vmResourceGroupName $vmLocation $vmName $version $powerState"
            }
        }
    }  -ThrottleLimit 5
}
catch {
    $errorMessage = $_
    $errorMessage
}
finally {
    Get-Content $sLogPath/parallel-*.log | Add-Content $sLogFile
    Remove-Item –path $sLogPath\*  -Filter parallel*
    Stop-Log -LogPath $sLogFile
}

Upvotes: 0

Views: 1810

Answers (2)

js2010
js2010

Reputation: 27423

It won't be in order unless you sort it:

1..10 | foreach-object -Parallel { sleep 1;$_ } | set-content file.txt

Upvotes: 1

Dragoon
Dragoon

Reputation: 883

I stumbled upon this via google and didn't like any of the solutions I found, so I made up my own for logging that you might want to try. This example is how to write to a text file in the current directory safely in a foreach parallel loop:

$tw = [System.IO.TextWriter]::Synchronized([System.IO.File]::AppendText("$PSScriptRoot\log.txt"))

0..100 | Foreach-Object -Parallel {
  $writer = $Using:tw
  $writer.WriteLine("hello $_")
}
$tw.Close()

Optionally wrap the whole thing in a try/finally with the $tw.Close() in the finally block to ensure that the log file buffer gets flushed and then closed if the script is interrupted.

The TextWriter object handles the locking for you and works just like a StreamWriter object. Note that this is assuming you aren't trying to also read from the file in any of the threads, for that you'd need something a lot more complex.

Upvotes: 2

Related Questions