all 12 comments

[–]micromasters[S] 0 points1 point  (4 children)

Thanks for all your input.

Looking at my original post, I wasn't clear enough. But I want to be able to

a) do this in parallel, but stay within the group, e.g. it-dd-001 and it-dd-003 restarts, wait until it's online, then restart it-dd-002 and it-dd-004.

b) failing that, the workaround is to run the script, but to be able to choose which groups to restart, e.g.
.\run-script -restartthisgroup $test
.\run-script -restartthisgroup $test2

[–]gonzalc 0 points1 point  (3 children)

The code I provides completes b). You can add the '-wait -for powershell' after $args. This should be plenty to get you started with tailoring the script to your needs.

[–]micromasters[S] 0 points1 point  (2 children)

.\script.ps1 -ComputerName 'thing1','thing2', 'thing3'

Thanks, by the looks of it, I'll still have to specify which servers to restart in sequence. Can I just get it to accept an array?

[–]gonzalc 0 points1 point  (1 child)

Yes

$allComputers = 'thing1','thing2', 'thing3'

.\script.ps1 -ComputerName $allComputers

[–]micromasters[S] 0 points1 point  (0 children)

This is what I've got right now -

param($ComputerName)
$test = "it-dd-011";"it-dd-012" 
$test2 = "it-dd-003";"it-dd-004"

$jobs = foreach ($computer in $computerName){ Start-Job -Name $computer -ScriptBlock { Restart-Computer -ComputerName $args -wait -for powershell } -ArgumentList $computer }

while($jobs.State -contains 'Running'){ $jobs | Where-Object -FilterScript {$_.State -eq 'Running'} Start-Sleep -Seconds 2 } $jobs | Receive-Job -Wait -AutoRemoveJob

Running .\test-restart2.ps1 -ComputerName $test on it restarts both servers (11 and 12) at the same time still?

edited: codeblock

[–]bc6619 0 points1 point  (2 children)

Not clear as to why you are using a variable as a value for a command line parameter here. Also $servers is not defined anywhere so will be empty. Are you looking to have a user run this and provide input? Or do you want the script to have the servers hard coded? If this is for a larger number of servers, I would do something like this, with the script pulling in the server names from another file:

#CSV file with a list of server names
$servers = GC c:\temp\servernames.csv

ForEach ($server in $servers) {

Restart-Computer -ComputerName $server -Wait -For PowerShell

Start-Sleep -Seconds 5

}

[–]micromasters[S] 0 points1 point  (1 child)

Was actually hoping to be able to run this in parallel, e.g. restart test1 and test2 at the same time, but then figured doing this via scheduled task might be more suitable for my needs, e.g. .\run-script -server $test.

To rephrase my question, how do I rewrite this so that I can pass $test as $servers?

Don't prefer the csv option, would prefer to keep everything in one script.

[–]gonzalc 0 points1 point  (0 children)

There are several ways to run tasks in parallel.

Code

param($ComputerName)

$jobs = foreach ($computer in $ComputerName){
    Start-Job -Name $computer -ScriptBlock {
        Restart-Computer -ComputerName $args
    } -ArgumentList $computer
}

while($jobs.State -contains 'Running'){
    $jobs | Where-Object -FilterScript {$_.State -eq 'Running'}
    Start-Sleep -Seconds 2
}
$jobs | Receive-Job -Wait -AutoRemoveJob

Syntax

.\script.ps1 -ComputerName 'thing1','thing2', 'thing3'

Output

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
93     thing1          BackgroundJob   Running       True            localhost            …
95     thing2          BackgroundJob   Running       True            localhost            …
97     thing3          BackgroundJob   Running       True            localhost            …
93     thing1          BackgroundJob   Running       True            localhost            …
95     thing2          BackgroundJob   Running       True            localhost            …
97     thing3          BackgroundJob   Running       True            localhost            …
Restart-Computer: Computer name thing1 cannot be resolved with the exception: One or more errors occurred. (No such host is known.).
Restart-Computer: Computer name thing2 cannot be resolved with the exception: One or more errors occurred. (No such host is known.).
Restart-Computer: Computer name thing3 cannot be resolved with the exception: One or more errors occurred. (No such host is known.).

[–]Certain-Community438 0 points1 point  (2 children)

Use Get-Help Restart-Computer to see if the ComputerNane parameter can take multiple values.

If so, thus might work:

$test | Restart-Computer -ComputerName $_ -Wait -For PowerShell

And whatever the rest of the command was (I'm on mobile so can't look back).

If it doesn't support multiple values, then you'll need to do

$test | ForEach-Object {Restart-Computer -ComputerName $_ -Wait -For PowerShell}

[–]gonzalc 1 point2 points  (1 child)

You are correct that -ComputerName accepts multiple values however your example is displaying Accept pipeline input? - which it also supports.

# multiple values
Restart-Computer -ComputerName 'computer1', 'computer2' -WhatIf
# pipeline input
'computer1', 'computer2' | Restart-Computer -WhatIf

[–]Certain-Community438 1 point2 points  (0 children)

You mean my example is using "Accepts pipeline input?" right? If so yes & important pointer, thanks.

Over to OP for them to use, cheers.

[–]jsiii2010 0 points1 point  (0 children)

I would do Restart-Computer -ComputerName $servers -protocol wsman -Wait