powershellfunctionloopswhile-loopuntil-loop

PowerShell: How can you collect the amount of tasks that are running in a Do/Until loop?


Afternoon all,

I've got a script that runs scheduled tasks on some remote computers through Cimsessions.

Start-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name>"

I then have a timer that runs in a Do/Until loop until the tasks are completed. However, the loop ends when one server has completed the task even if others have finished. Is there a way I can re-write my loop to continue until all servers have registered that their task is not running

$StartTime = Get-Date
Do{
    $ElapsedTime = (Get-Date) - $StartTime
    $TotalTime = "{0:HH:mm:ss}" -f ([datetime]$ElapsedTime.Ticks)
    $CurrentLine = $host.UI.RawUI.CursorPosition
    Write-Output "Running Scheduled Task... [Total Elapsed Time: $(stc $TotalTime yellow)]"
    sleep -s 2
    $host.UI.RawUI.CursorPosition = $CurrentLine

}Until((Get-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name").State -ne 'Running')

Note: the line of code $(stc $TotalTime yellow) is just a custom function that changes the color of the text to yellow


Solution

  • The condition:

    Until((Get-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name>").State -ne 'Running')
    

    Is saying, "run this loop and stop as soon as there is one object with it's State property not equal to Running". What you want instead is, "run this loop while there are objects having the State property equal to Running", hence the condition should be:

    # with `-contains`
    while((Get-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name>").State -contains 'Running')
    
    # with `-in`
    while('Running' -in (Get-ScheduledTask -CimSession $CimSessions -TaskName "<Task-Name>").State)
    

    As aside, you could greatly simplify the task of $ElapsedTime = (Get-Date) - $StartTime by leveraging the StopWatch Class. Here is a little example:

    $timer = [System.Diagnostics.Stopwatch]::StartNew()
    do {
        $timer.Elapsed.ToString('hh\:mm\:ss')
        Start-Sleep 1
    } until($timer.Elapsed.Seconds -ge 5)