Run powershell script on multiple servers parallelly - powershell

Probably a repetitive question, but need some to-the-point answers as I'm still learning. I want to run the PowerShell script on all remote servers- simultaneously, to install an application. I tried the below cmdlet but it's executing one after the other, and also would like to know the status or job output file. Any help is much appreciated. Thanks
$servers = Get-Content "C:\Dumps\Scripts\servers.txt"
foreach ($server in $servers) {
Invoke-Command -ComputerName $server -Filepath C:\Dumps\Scripts\CompleteSilent.ps1
}

Simply use $Servers as the -ComputerName argument. Invoke-Command will run them parallel.
You can adjust the Throttle on the parallelism with the -Throttle parameter.
Invoke-Command -ComputerName $Servers -Filepath C:\Dumps\Scripts\CompleteSilent.ps1
Note: If there are return objects and or screen echoes they may return disordered. It can be handled, but if this is an installation you may not encounter that particular issue.

Related

Remote CrowdStrike Uninstallation

I am trying to uninstall outdated crowdstrike using CsUninstallTool.exe on bunch of remote servers.
As we know we cannot directly uninstall crowdstrike, it require a maintenance code unique to host. The below script is working correctly for a single remote host but when I try to run same script, crowdstrike did not get uninstalled.
Also same script is asking for credentials after every loop and looking for optimal way to manage user session without asking cred again & again.
$servers = Get-Content 'C:\Users\PP\Desktop\CrowdStrike_Automation\servers.txt'
$maintenance_token = Get-Content 'C:\Users\PP\Desktop\CrowdStrike_Automation\maintenance_key.txt'
foreach ($server in $servers) {
Invoke-Command -ComputerName $server -Credential (Get-Credential) -ScriptBlock {
& "C:\Temp\CrowdStrike_Automation\Setup\CsUninstallTool.exe" MAINTENANCE_TOKEN=$using:maintenance_token /quiet
}
}
Any suggestion?

Powershell Invoke-GPUpdate - "No Logoff" possible?

Looking to run Invoke-GPUPdate -force to a group of remote computers and respond to the logoff prompt with "No".
Tried:
Echo "n" | invoke-gpupdate
Error:Invoke-gpupdate does not accept pipeline input
Command Used:
Invoke-GPUpdate -Computer $computer -RandomDelayInMinutes 0 -force
Unfortunately it looks like this cmdlet initiates/schedules a run of gpupdate that ends up happening separately (out of process), so there isn't much to do via PowerShell's standard ways of dealing with something like that, since the prompt doesn't come from within PowerShell. There's a -LogOff parameter, but it's a switch parameter which implies that its value is meant to be used just for doing the logoff. You can try it this way: -Logoff:$false but most likely it won't work to get rid of the prompt.
I think your best chance is not to use this cmdlet, but to instead use Invoke-Command with gpupdate.exe directly:
Invoke-Command -ComputerName $computer -ScriptBlock {
echo nn | gpupdate.exe /force
}
But this requires that PowerShell remoting is enabled on the machines you want to manage.

PowerShell remote session and Start-Job issue

I am trying to run following script with job but the code in the block only executes 1st command and exits. Job is displayed completed on my computer
$computers = get-adcomputer -filter * | where { ($_.DNSHostName -match 'server')}
foreach ($computer in $computers) {
$session = New-PSSession -ComputerName $computer.DNSHostName
Invoke-Command -Session $session -ScriptBlock {
Stop-Service W3SVC -Force
Remove-Item "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root" -Force -Recurse
Start-Service W3SVC
} -asjob -jobname IIS_Maintenance
Remove-PSSession -Session $session
}
If I comment out -asjob -jobname IIS_Maintenance job runs fine but it's synchronous. It takes several seconds to stop IIS but I am not sure why job is not waiting on that.
Thoughts?
Creating the session induces a lot of delay. Why did you chose to use the -Session instead of directly using -ComputerName ?
I think using the -ComputerName way will be more efficient to run with Start-Job. Either way, Since you are invoking the jobs on remote machines, your workstation would have no clue on the progress of the jobs.
If you want to track the progress of the jobs, you shouldn't be using Invoke-Command at all.
OK I figured it out... the point of confusion was:
1) I didn't know I can send block of code without Session and yes session implementation is slow
2) I also didn't know I send invoke-command to several computers are once without foreach. Thank you for that Ansgar Wiechers!

Run multiple PowerShell Invoke-Command

I have been working to automate my SQL patching. I have found that I can run the command below from my central server and it will perform the upgrade on the remote computer. My issue is that I can only run one command at a time until the command comes back with a response. I am trying to figure out how I can run this command against 100 different computers at one time and all the upgrades can be performed at once in parallel and not one by one.
Invoke-Command -computername SQLServer1 -command {D:\DBA\SQLPatching\SQL_2014\SP1\Patch-SQL2014_SP1.bat}
I would just be replacing the -computername parameter with my list of servers being patched.
Does anyone have any suggestions?
Invoke-Command -ComputerName $computers -ScriptBlock {D:\DBA\SQLPatching\SQL_2014\SP1\Patch-SQL2014_SP1.bat }
Assuming that bat file is in D on all the computers. Using invoke-command will run in parallel if you have a list of machines to pass to if.
If you instead used a ForEach $computer in $computers you would have it run one at a time.

Installing Windows Features on remote server 2012 using powershell 3.0

I am wondering which is best practice considering both examples will probably work. Using the built in help examples I have written a script to install windows features on remote servers. Here is my code:
$servers = ('server1', 'server2', 'server3', 'server4')
ForEach ($server in $servers) {
Install-WindowsFeature -Name Desktop-Experience -ComputerName $server -IncludeAllSubFeature -IncludeManagementTools -Restart
}
Would the above be preferred OR should I wrap the "Install-WindowsFeature ..." in an "Invoke-Command" block like the following?
Invoke-Command -ComputerName server1, server2, server3, server4 -command {
Install-WindowsFeature -Name Desktop-Experience -ComputerName $server -IncludeAllSubFeature -IncludeManagementTools -Restart
}
Thanks for your insight!
Personally I would use the latter (directly call Install-WindowsFeature -ComputerName $server rather than do a separate Invoke-Command) in this case for the following reasons:
You may be hard-coding the feature names now, but in the future you may want to put those in a variable. If you put them in a variable, you'll have to pass it as a parameter into the Invoke-Command's script block. This is entirely possible, but more work.
By using your own loop, you can write progress messages, logging, etc.
You gain nothing by using Invoke-Command in this case because you're running a single command on the remote computer (as opposed to running multiple commands with -ComputerName parameters vs. running multiple commands inside the script block).