3

My Powershell code doesn't evaluate the $agent variable:

foreach ($agent in $agentcomputers) {
    Write-Output 'Starting agent on '$agent
    # psexc to start the agent
    Start-Job -ScriptBlock {& psexec $agent c:\grinder\examples\startAgent.cmd}
}

This link is similar to my problem, except I'm not calling an external Powershell script.

I tried adding that in, using $args[0] for $agent, and adding the -ArgumentList parameters, but that didn't work.


Edits/Replies

$agentcomputers is just a list of computer names - each on its own line:

$agentcomputers = Get-Content c:\grinder-dist\agent-computers.txt

I have also tried this - and $args[0] doesn't evaluate:

Start-Job -ScriptBlock {& psexec $args[0] c:\grinder\examples\startAgent.cmd} -ArgumentList @($agent)
alex
  • 6,818
  • 9
  • 52
  • 103
Sam
  • 7,543
  • 7
  • 48
  • 62
  • You will need to use the ArgumentList parameter either using the `$args` array or a param block. – Andy Arismendi Apr 17 '12 at 18:06
  • You might also change the scope of your $agent variable, I think: $global:agent. – David Brabant Apr 17 '12 at 18:08
  • 1
    @DavidBrabant the global scope won't work since it's executed in a seperate PowerShell.exe process. The data is serialized and passed to the background process. – Andy Arismendi Apr 17 '12 at 18:11
  • How are you sure that $agent isn't evaluated? If you change psexec with a test write-output $agent you have same behaviour? No error output? – CB. Apr 17 '12 at 19:03
  • It seems as if the $agent is being omitted altogether. The PSExec command runs the process on my local computer. – Sam Apr 17 '12 at 19:57
  • @AndyArismendi - can you look at the second edit above with the -ArgumentList parameter? – Sam Apr 17 '12 at 19:59
  • 2
    You may need backslashes acording to psexec's [documentation](http://technet.microsoft.com/en-us/sysinternals/bb897553) `"\\$args[0]"`. Make sure the command works by itself without a background job. – Andy Arismendi Apr 17 '12 at 20:01
  • yes, I realized that after @Christian comment and looking at it a bit harder. Thanks so much. – Sam Apr 17 '12 at 23:46

2 Answers2

11

Here are 3 different ways I would do it. First, all aligned and pretty.

$agents = Get-Content c:\grinder-dist\agent-computers.txt
$jobs = {
     Param($agent)
         write-host "Starting agent on" $agent
         & psexec \\$agent c:\grinder\examples\startAgent.cmd
}
foreach($agent in $agents) {
     Start-Job -ScriptBlock $jobs -argumentlist $agent | Out-Null
}
Get-Job | Wait-Job | Receive-Job

Or you could just put it all on one line without creating any variables.

(Get-Content c:\grinder-dist\agent-computers.txt) | %{ Start-Job -ScriptBlock { param($_) write-host "Starting agent on" $_; & psexec \\$_ c:\grinder\examples\startAgent.cmd } -argumentlist $_ | Out-Null }
Get-Job | Wait-Job | Receive-Job

And in this final example, you could manage how many threads are run concurrently by doing it this way.

$MaxThreads = 5
$agents = Get-Content c:\grinder-dist\agent-computers.txt
$jobs = {
     Param($agent)
         write-host "Starting agent on" $agent
         & psexec \\$agent c:\grinder\examples\startAgent.cmd
}
foreach($agent in $agents) {
     Start-Job -ScriptBlock $jobs -argumentlist $agent | Out-Null
     While($(Get-Job -State 'Running').Count -ge $MaxThreads) {
          sleep 10
     }
     Get-Job | Wait-Job | Receive-Job
} 
T.CK
  • 411
  • 4
  • 6
4

Here is the solution. As Andy said, I needed to use $args array with the -ArgumentList parameter. This other thread was helpful: Powershell: passing parameters to a job

foreach($agent in $agentcomputers){
$agentslash = "\\"+$agent
$args = ($agentslash,"c:\grinder\examples\startAgent.cmd")
Write-Output 'Starting agent on '$agent

#psexc to start the agent
$ScriptBlock = {& 'psexec' @args } 

Start-Job -ScriptBlock $ScriptBlock -ArgumentList $args

}
Community
  • 1
  • 1
Sam
  • 7,543
  • 7
  • 48
  • 62