Start-Job script block-- how to call cmdlets with arguments? - powershell

I'm new to the Start-Job cmdlet and am having trouble calling a script block with cmdlets in it that take arguments. Here's what I have so far:
Start-Job -ScriptBlock {
$ServiceObj = Get-Service -Name $ServiceName -ComputerName $Computer -ErrorAction Stop
Stop-Service -InputObj $ServiceObj -erroraction stop
}
I'm seeing errors when I run receive-job that the -ComputerName argument is null or empty, and the -InputObj argument is null or empty. In neither case is that so. The snippet above is being called from inside two foreach loops:
foreach($Computer in $ComputerNames) {
foreach($ServiceName in $ServiceNames) {
#..call snippet above
}
}
I've tried using the -ArgumentList when calling my script block but no luck there either. I'm sure I'm missing something?

You do need to use ArgumentList (unless you're on PowerShell V3) e.g.:
Start-Job -ScriptBlock {param($ComputerName)
$ServiceObj = Get-Service -Name $ServiceName -CN $ComputerName -ErrorAction Stop
Stop-Service -InputObj $ServiceObj -erroraction stop
} -ArgumentList $Computer
If you're using PowerShell V3, you can use the using variable qualifier e.g.:
Start-Job -ScriptBlock {
$ServiceObj = Get-Service -Name $ServiceName -CN $using:Computer -ErrorAction Stop
Stop-Service -InputObj $ServiceObj -erroraction stop
}

Related

Background jobs stops after a few minutes

See below a simplified version of my PowerShell code.
$cred = Import-Clixml d:\cred.xml
Invoke-Command -ComputerName $computer -Authentication Credssp -Credential $cred -InDisconnectedSession -SessionOption #{OutputBufferingMode="Drop";IdleTimeout=2147483647} -Scriptblock {
$start_job = Start-Job -Scriptblock {
foreach ($user in $list) {
$a = Get-ChildItem -LiteralPath $user -Recurse -Force
Write-Output "$a.Count" | Out-File c:\test.log -Append
} -ArgumentList $list
}
I would send a list of maybe 30 names but after a few minutes of scanning the operations would stop without any error reported, it seems as if the Start-Job is blocked or suspended as the Invoke-Command is still running.
any idea on how to check or bypass this limitation?

Running Batch Script on remote Server via PowerShell

I need to connect to some remote servers from a client (same domain as the servers) once connected, I need to run a batch file:
I've done so with this code:
$Username = 'USER'
$Password = 'PASSWORD'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
try {
Invoke-Command -ComputerName "SERVER1" -Credential $Cred -ScriptBlock -ErrorAction Stop {
Start-Process "C:\Users\nithi.sundar\Desktop\Test.bat"
}
} catch {
Write-Host "error"
}
This script does not give any errors, but it doesn't seem to be executing the batch script.
any input on this would be greatly appreciated.
Try replacing
invoke-command -computername "SERVER1" -credential $Cred -ScriptBlock -ErrorAction stop { Start-Process "C:\Users\nithi.sundar\Desktop\Test.bat" }
with
Invoke-Command -ComputerName "Server1" -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'C:\Users\nithi.sund
ar\Desktop\Test.bat'"}
It's not possible that the code you posted ran without errors, because you messed up the order of the argument to Invoke-Command. This:
Invoke-Command ... -ScriptBlock -ErrorAction Stop { ... }
should actually look like this:
Invoke-Command ... -ErrorAction Stop -ScriptBlock { ... }
Also, DO NOT use Invoke-Expression for this. It's practically always the wrong tool for whatever you need to accomplish. You also don't need Start-Process since PowerShell can run batch scripts directly:
Invoke-Command -ComputerName "SERVER1" -ScriptBlock {
C:\Users\nithi.sundar\Desktop\Test.bat
} -Credential $Cred -ErrorAction Stop
If the command is a string rather than a bare word you need to use the call operator, though:
Invoke-Command -ComputerName "SERVER1" -ScriptBlock {
& "C:\Users\nithi.sundar\Desktop\Test.bat"
} -Credential $Cred -ErrorAction Stop
You could also invoke the batch file with cmd.exe:
Invoke-Command -ComputerName "SERVER1" -ScriptBlock {
cmd /c "C:\Users\nithi.sundar\Desktop\Test.bat"
} -Credential $Cred -ErrorAction Stop
If for some reason you must use Start-Process you should add the parameters -NoNewWindow and -Wait.
Invoke-Command -ComputerName "SERVER1" -ScriptBlock {
Start-Process 'C:\Users\nithi.sundar\Desktop\Test.bat' -NoNewWindow -Wait
} -Credential $Cred -ErrorAction Stop
By default Start-Process runs the invoked process asynchronously (i.e. the call returns immediately) and in a separate window. That is most likely the reason why your code didn't work as intended.

Restart a service in the background using Powershell

I'm trying to restart a service in the background, then monitor the if the service has been restarted. If the service has not started as a while, then the service is to be restarted.
I'm having issues with restarting the service in the background the start-job command does run so thats where i'm most probably going wrong. the restart-service and do command work correctly, just cant get it to run in the background.
$a = "Restart-Service -InputObject $(get-service -ComputerName $Server -Name Service)"
start-job -scriptblock {$a}
do {
($Check = (Get-Service -ComputerName $RadSvr -Name IAS).status -eq "Running") }
Until ($check -eq $true)
After playing around, I noticed the script ran in the background if i didnt use variables in the Start-Job. so if i changed the start-job to include the IP address of a server
start-job -scriptblock { Restart-Service -InputObject $(get-service -ComputerName 10.10.10.10 -Name Service) }
anyone know how to make variable work?
Use Wait-Job to wait for the job to complete.
$a = "Restart-Service -InputObject $(get-service -ComputerName $Server -Name Service)"
$job = start-job -scriptblock {$a}
Wait-Job $job
Maybe you can simplify your code a little bit by using process functions
$service = Get-Service -Name $servicename -ComputerName $targetcomputer
$service.Stop();
$maxTimeout = "00:03:00"
$service.WaitForStatus('Stopped', $maxTimeout);
# check again the status and eventually perform another action
I got the script working. I needed to add param and -argumentlist in the start-job
start-job -scriptblock {param($Server) Restart-Service -InputObject $(get-service -ComputerName $Server -Name Service)} -Argumentlist $Server

Stop remote service using PowerShell

I've a script that stops remote services through WMI:
(get-service -ComputerName $server_ip -Name $service).Stop()
I want to force a service after five tries. I have build a counter, but what is the command to force a stop?
If you have winRM enabled you can use the following:
Invoke-Command -ComputerName server1 -ScriptBlock {
Stop-Service $args[0] -Force } -ArgumentList $service
If by "force a stop" you mean you want to forcibly terminate (i.e. kill) the service process you could try killing the process via its PID:
$server = '1.2.3.4'
$service = 'name'
Invoke-Command -Computer $server -ScriptBlock {
param($svc)
$Error.Clear()
1..5 | % {
Stop-Service -Name $svc
if ($?) { break } # exit from loop if previous command succeeded
}
if ($Error.Count -eq 5) {
$pid = (Get-WmiObject Win32_Service -Filter "Name='$svc'").ProcessId
(Get-Process -Id $pid).Kill()
}
} -ArgumentList $service
Running the code via Invoke-Command is to avoid multiple remote connections.
This should work even for services that have the NOT_STOPPABLE flag set.

invoke-expression inside scriptblock of invoke-command not working

I've got the following script
$name = (Invoke-Command -ComputerName "STW111" -Credential $cred -ScriptBlock { Invoke-Expression "C:\PSS\User Tool\UserTool.exe"} -AsJob).Name
Wait-Job -Name $name
This not working, however, if I move the usertool to c:\pss\, it works fine.
$name = (Invoke-Command -ComputerName "STW111" -Credential $cred -ScriptBlock { Invoke-Expression "C:\PSS\UserTool.exe"} -AsJob).Name
Wait-Job -Name $name
I really need to get to grips with escaping in Powershell.
Any ideas?
TIA
try this:
Invoke-Expression "& 'C:\PSS\User Tool\UserTool.exe'"