[英]Make Powershell script continue running to next task whilst displaying a countdown timer
I'm trying to execute a script in Powershell that has "time left" to run a script but also want it to continue with the next task (executing policies to Users and exporting results to.csv).我正在尝试在 Powershell 中执行一个脚本,该脚本有“剩余时间”来运行脚本,但也希望它继续执行下一个任务(对用户执行策略并将结果导出到.csv)。 The Timer must also stop when the script Ends. Timer 也必须在脚本结束时停止。 Currently, the time counts down to 0, then the script continues.目前,时间倒计时到 0,然后脚本继续。 The Script works but I want to be able to execute 2 processes at once.该脚本有效,但我希望能够一次执行 2 个进程。 Please help.请帮忙。
Above the screenshot, Timer Counts down 1st before continuing to process the next part of the script.在屏幕截图上方,计时器倒计时 1 次,然后继续处理脚本的下一部分。 How do we get it to run both at once?我们如何让它同时运行呢?
Once the time has counted down to 0, then the above process runs.一旦时间倒计时到 0,则上述过程运行。
$Variable = Import-CSV -Path
"C:\Users\MicrosoftTeams\locationbasedpolicy1.csv"
$ApproxTime = 10
for ($seconds=$ApproxTime; $seconds -gt -1; $seconds--){
Write-Host -NoNewLine ("`rTime Left: " + ("{0:d4}" -f $seconds))
Start-Sleep -Seconds 1
}
foreach ($U in $Variable){
$user = $U.userPrincipalName
Grant-CSTeamsEmergencyCallingPolicy -policyname ECP-UK-All-Users
-identity $user
Write-Host "$($user) has been assigned Policy!"
}
Note: Your screenshot implies that you're using PowerShell (Core) 7+, which in turn implies that you can use Start-ThreadJob
for thread -based background jobs.注意:您的屏幕截图暗示您正在使用 PowerShell (Core) 7+,这反过来意味着您可以使用Start-ThreadJob
进行基于线程的后台作业。
With notable limitations - which may or may not be acceptable - you can do the following:有明显的限制- 这可能是也可能不是可接受的 - 您可以执行以下操作:
Use timer events to update your countdown display message, on a fixed console line that is temporarily restored.使用计时器事件在临时恢复的固定控制台线路上更新倒计时显示消息。
Run the commands via Start-ThreadJob
, relaying their output;通过Start-ThreadJob
运行命令,中继他们的 output; running in a separate thread is necessary in order for the countdown display in the foreground thread to update relatively predictably.为了使前台线程中的倒计时显示能够相对可预测地更新,必须在单独的线程中运行。
The problem with progress messages being emitted from a thread job is that they print on successive lines for every Receive-Job
call - and there is no workaround that I'm aware of.从线程作业发出的进度消息的问题在于,它们会在每个Receive-Job
调用的连续行上打印 - 而且我不知道没有解决方法。
You can forgo progress messages by setting $ProgressPreference = 'SilentlyContinue'
in the thread job's script block, but you'll obviously lose detailed progress feedback;您可以通过在线程作业的脚本块中设置$ProgressPreference = 'SilentlyContinue'
来放弃进度消息,但您显然会丢失详细的进度反馈; the best you could do is provide a "still alive" kind of progress message in the foreground loop.您能做的最好的事情是在前台循环中提供“仍然存在”的进度消息。
The following self-contained sample code shows this technique:以下独立的示例代码展示了这种技术:
Invoke-WebRequest
is used to download a file (the file is cleaned up afterwards).作为显示进度消息的示例命令, Invoke-WebRequest
用于下载文件(该文件随后被清理)。$countDownSecs = 10
# Create a timer that will fire every second once started.
$timer = [System.Timers.Timer]::new(1000)
# Register a handler for the timer's "Elapsed" event, and pass the
# the current cursor position and the projected end timestamp to the -Action script block.
$eventJob = Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action {
# Save the current cursor position
$currCursorPos = $host.UI.RawUI.CursorPosition
# Restore the cursor position for the countdown message.
$host.UI.RawUI.CursorPosition = $Event.MessageData.CountDownCursorPos
[Console]::Write((
'Time Left: {0:d4}' -f [int] ($Event.MessageData.CountDownTo - [datetime]::UtcNow).TotalSeconds
))
# Restore the cursor position
$host.UI.RawUI.CursorPosition = $currCursorPos
} -MessageData @{
CountDownCursorPos = $host.UI.RawUI.CursorPosition
CountDownTo = [datetime]::UtcNow.AddSeconds($countDownSecs)
}
# Write the initial countdown message now, both for instand feedback and to
# "reserve" the console line for future updates.
Write-Host ('Time Left: {0:d4}' -f $countDownSecs)
# Start the timer.
$timer.Start()
# Run a command that uses progress display (Write-Progress)
# in a parallel thread with Start-ThreadJob and track its
# progress.
try {
$tmpFile = New-TemporaryFile
# Run the command(s) in a thread job.
# That way, the timer events are processed relatively predictably in the foreground thread.
$jb = Start-ThreadJob {
# Activate the next line to silence progress messages.
# $ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -OutFile $using:tmpFile https://github.com/PowerShell/PowerShell/releases/download/v7.2.6/powershell-lts_7.2.6-1.deb_amd64.deb
}
# Wait for the thread job to finish, relaying output on an ongoing basis.
while ($jb.State -in 'NotStarted', 'Running') {
# Note: While Receive-Job is necessary even for progress messages, such messages:
# (a) cannot be captured or redirected
# (b) invariably print on successive lines for every Receive-Job call;
# even trying to restore the cursor position after every Receive-Job call doesn't help.
$jb | Receive-Job
Start-Sleep -Milliseconds 50
}
} finally {
# Stop timer and remove the jobs and the temp. file
$timer.Stop()
$jb, $eventJob | Remove-Job -Force
$tmpFile | Remove-Item
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.