如何使用 foreach-object parallel 将日志写入单个文件?

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

问题

我正在尝试使用 PSlogging PowerShell 模块将日志写入单个日志文件。

脚本正在使用 Foreach 对象并行。

脚本有效,但有时脚本会卡在中间。

请帮我解决一下?有没有更好的方法来实现这个?

Powershell 核心 7

代码

#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
}

我通过 google 偶然发现了这个并且不喜欢我找到的任何解决方案,所以我自己编写了您可能想尝试的日志记录。此示例是如何在 foreach 并行循环中安全地写入当前目录中的文本文件:

$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()

可选地用 finally 块中的 $tw.Close() 将整个内容包装在 try/finally 中,以确保日志文件缓冲区被刷新,然后在脚本被中断时关闭。

TextWriter 对象为您处理锁定,其工作方式与 StreamWriter 对象相同。请注意,这是假设您不尝试在任何线程中读取文件,因为您需要更复杂的东西。

除非你排序,否则它不会按顺序排列:

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