如何使用 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
问题
我正在尝试使用 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