简体   繁体   中英

Pass schtasks.exe output to foreach loop in PowerShell

I am using powershell5.1 and I am trying to grab a few tasks running on a remote server and see if any are running. IF there are any running then I will have the script sleep for a minute and then check again until all the tasks I am checking are in Ready status.

What I use to query the remote server:

$servers = "Server1"
""
foreach($server in $servers)
{
   Invoke-Command -ComputerName $server -ScriptBlock{ 
       schtasks /query /fo list /tn RandomTaskName
   }
}

Which then outputs this result:

HostName:      $server
TaskName:      \RandomTaskName
Next Run Time: 3/1/2022 11:40:00 AM
Status:        Running
Logon Mode:    Interactive/Background

So I add a pipe to FINDSTR "Status: Running"

schtasks /query /fo list /tn RandomTaskName | FIDNSTR "Status: Running"

That returns just the string. Then I try to add the output to a variable and do a foreach loop to see if a string contains "Status: Running"

$servers = "Server1"
foreach($server in $servers)
{
   Invoke-Command -ComputerName $provider -ScriptBlock{ 
       schtasks /query /fo list /tn RandomTaskName
       }
   $task = $_
   if ("Status: Running" -ccontains $task)
   {
       Wrtite-host "Task is still running"
   }
   else
     {
       Write-Host "Task is NOT running"
     }
}

Which results in nothing. When I comment out the "if" and "else" statements so only "$task=$_" is at the end, then it results in "Status: Running".

Anyone can give any insight as to how to grab the running status for a list of remote servers?

When I saw this question, it really peaked my curiosity. I'm working more with workstations than servers, but everything should be about the same.

This is entirely my approach to solve my own problems, so it may not fit your needs - sorry. But perhaps my code can give you some ideas on how to do what you want.

This code:

  1. Has a function called Invoke-InBackgroundOnMachines that takes an array of machines, a list of arguments, and a scriptblock.
  2. Invoke-InBackgroundOnMachines gets pipeline content from each remote machine that the scriptblock is ran on and returns it on the pipeline.
  3. Invoke-InBackgroundOnMachines checks to see if it can connect to each machine before trying to run the scriptblock on it. Machines that it cannot connect to are returned on the pipeline in a comma delimited text of "Machine", "NoConnection", "NoConnection". Machines that it can connect to are stored in the LiveMachines array, which is later handed to Invoke-Command, along with the scriptblock and argument list.
  4. The one thing I haven't figured out yet is how to best deal with computers that do not have WinRM enabled. Invoke-Command throws errors when it hits a computer with WinRM disabled. This is my first attempt at running remote script blocks, so still have a lot to figure out.
  5. The scriptblock itself wound up being a lot larger than I was expecting. But it does the job of returning the status of tasks in a comma delimited format.
  6. This is not properly tested code. I started with cervan12's code this morning and started writing. So keep that in mind.
# Used Example 8 from following URL
# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command?view=powershell-5.1
$SchTasksScriptBlock = {
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$TaskNameToFind
    )
    function CommaDelimited {
        param (
            [Parameter(Mandatory = $true, Position = 0)]
            [string[]]$Tokens
        )
        $Return = ''
        foreach ($Token in $Tokens) {
            $Return += ", `"$Token`""
        }
        $Return.Substring(2)
    }
    $STReturn = SCHTASKS /Query /FO LIST /TN $TaskNameToFind 2>$null
    if ($LASTEXITCODE -eq 0) {        
        $HostName = ''
        switch -Regex ($STReturn) {
            '(?i)^\s*hostname:\s*(?<HostName>.*)\s*$' {
                if ($HostName -ne '') { CommaDelimited $HostName, $TaskName, $Status }
                $HostName = $Matches.HostName
                continue
            }
            '(?i)^\s*taskname:\s*(?<TaskName>.*)\s*$' {
                $TaskName = $Matches.TaskName
                continue
            }
            '(?i)^\s*status:\s*(?<Status>.*)\s*$' {
                $Status = $Matches.Status
                continue
            }
            Default {
                continue
            }
        }
        if ($HostName -ne '') { CommaDelimited $HostName, $TaskName, $Status }
    } else {
        $HostName = HostName
        CommaDelimited $HostName, $TaskNameToFind, 'Missing'
    }
}
function Invoke-InBackgroundOnMachines {
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string[]]$Machines,
        [Parameter(Mandatory = $true, Position = 1)]
        [object[]]$ArgumentList,
        [Parameter(Mandatory = $true, Position = 2)]
        [scriptblock]$ScriptBlock
    )
    [string[]]$LiveMachines = @()
    foreach ($Machine in $Machines) {
        if(Test-Connection -ComputerName $Machine -Quiet) {
            $LiveMachines += $Machine
        } else {
            "`"$Machine`", `"NoConnection`",`"NoConnection`""
        }
    }
    If($LiveMachines.Count -gt 0) {
        $Session = New-PSSession -ComputerName $LiveMachines
        $null = Invoke-Command -Session $Session -ScriptBlock $ScriptBlock -AsJob -ArgumentList $ArgumentList
        Get-Job | Wait-Job | Receive-Job
    }
}

Example use:

$List = @(  'Machine1', 'Machine1' )
Invoke-InBackgroundOnMachines $List '\AlertusSecureDesktopLauncher' $SchTasksScriptBlock

Example results returned on the Pipeline:

"Machine1", "\AlertusSecureDesktopLauncher", "Ready"
"Machine2", "\AlertusSecureDesktopLauncher", "Ready"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM