I'm building kind of a framework which is running different scripts when an event occurs. The scripts should be pretty quick to execute (<1s). But if a script takes too long, I would like to kill it. If it has to be killed, I would like to know what it was doing at 'killtime'.
So, lets assume I have the following script:
$scriptblock = {
start-sleep 2
start-sleep 2
start-sleep 2
start-sleep 2
start-sleep 2
start-sleep 2
start-sleep 2
}
$job=start-threadjob -scriptblock $scriptblock
wait-job -job $job -Timeout 1
debug-job -job $job -BreakAll
If I run the above script, I can press:
l - to get the current line number
k - to get the callstack
q - to 'kill' the job
But, now to my question, how do I send characters (programmatically) to the debug-job cmdlet?
Or is there another way to extract current line number and callstack before killing?
Related
I have below command, $a have 20 URLs:
$a = #('http://10.10.10.101/Login.aspx',
'http://10.10.10.101/user/customers')
$startFulltime = (Get-Date)
foreach($a1 in $a){
start-job -ArgumentList $a1 -ScriptBlock{
param($a1)
Invoke-WebRequest $a1 -Method post -DisableKeepAlive -UseBasicParsing
-ArgumentList $a1
}}
Get-Job | Wait-Job
Getting Below Errors:
Wait-Job : The Wait-Job cmdlet cannot finish working, because one or more jobs are blocked waiting for user interaction. Process interactive job
output by using the Receive-Job cmdlet, and then try again.
At line:13 char:11
+ Get-Job | Wait-Job
+ ~~~~~~~~
+ CategoryInfo : Deadlock detected: (System.Manageme...n.PSRemotingJob:PSRemotingJob) [Wait-Job], ArgumentException
+ FullyQualifiedErrorId : BlockedJobsDeadlockWithWaitJob,Microsoft.PowerShell.Commands.WaitJobCommand
Reference Link : input objects in powershell jobs
Please help me to resolve error, thanks In Advance!!
The only obvious problem with your code - which may be a posting artifact - is that there's a second, extraneous -ArgumentList $a1 inside your Start-Job script block - but that would cause a different error, though potentially preempted by the one you're getting.
It sounds like one of your jobs unexpectedly prompts for user input, as implied by the error message.
Use of Receive-Job, as suggested in the error message, will bring interactive prompts to the foreground, allowing you to see and respond to them.
This should help you diagnose which job causes the problem and why; here's a simplified example:
# Start a job with a command that asks the user for interactive input
# (which isn't a good idea).
$job = Start-Job { Read-Host 'Enter something' }
# !! Error, because the job is waiting for interactive user input.
$job | Wait-Job
# OK - Receive-Job "foregrounds" the Read-Host prompt.
# Once you respond to it, the job finishes
# (and is automatically removed here, thanks to -Wait -AutoRemoveJob).
$job | Receive-Job -Wait -AutoRemoveJob
I am running the following powershell command in a build step using TFS 2018.
Start-Job -ScriptBlock {
Invoke-Command -FilePath \\MyServer\run.ps1 -ComputerName MyServer -ArgumentList arg1, arg2
}
Since I don't want the script to affect the build step it should simply fire and forget the script. Hence I am using Start-Job. But it seems that once the step is done the process is killed. Is there a way to maintain the process lifetime even though the build step is done or the build process is finished?
Additional information... the powershell script should run on the remote server. The script itself triggers an .exe with parameters.
To simply fire and forget, invoke the script with Invoke-Command -AsJob:
Invoke-Command -AsJob -FilePath \\MyServer\run.ps1 -ComputerName MyServer -Args arg1, arg2
Start-Sleep 1 # !! Seemingly, this is necessary, as #doorman has discovered.
This should kick off the script remotely, asynchronously, with a job getting created in the local session to monitor its execution.
Caveat: The use of Start-Sleep - possibly with a longer wait time -
is seemingly necessary in order for the remote process to be created before the calling script exits, but such a solution may not be fully robust, as there is no guaranteed timing.
Since you're not planning to monitor the remote execution, the local session terminating - and along with it the monitoring job - should't matter.
When do you want the script to stop running? You could use a do-while loop and come up with a <condition> that meets your needs.
Start-Job -ScriptBlock {
do{
Invoke-Command -FilePath \\MyServer\run.ps1 -ComputerName MyServer -ArgumentList arg1, arg2
Start-Sleep 2
}while(<condition>)
}
Alternatively, you could use the condition $true so it executes forever. You will have to stop the job later in the script when you no longer need it.
$job = Start-Job -ScriptBlock {
do{
Invoke-Command -FilePath \\MyServer\run.ps1 -ComputerName MyServer -ArgumentList arg1, arg2
Start-Sleep 2
}while($true)
}
Stop-Job $job
Remove-Job $job
I've added a Start-Sleep 2 so it doesn't lock up your CPU as no idea what the script is doing - remove if not required.
Why not something like this:
Invoke-Command -Filepath \\MyServer\Run.ps1 -Computername MyServer -Argumentlist Arg1,Arg2 -AsJob
$JobCount = (get-job).Count
Do
{
Start-Sleep -Seconds 1
$totalJobCompleted = (get-job | Where-Object {$_.state -eq "Completed"} | Where-Object {$_.Command -like "NAMEOFCOMMAND*"}).count
}
Until($totalJobCompleted -ge $JobCount)
#doorman -
PowerShell is natively a single threaded application. In almost all cases, this is a huge benefit. Even forcing multiple threads, you can see the child threads are always dependent on the main thread. If this wasn't the case, it would be very easy to create memory leaks. This is almost always a good thing as when you close the main thread, .Net will clean up all the other threads you may have forgotten about for you. You just happened to run across a case where this behaviour is not beneficial to your situation.
There are a few ways to tackle the issue, but the easiest is probably to use the good ol' command prompt to launch an independent new instance not based at all on your original script. To do this, you can use invoke-expression in conjunction with 'cmd /c'. See Below:
invoke-expression 'cmd /c start powershell -NoProfile -windowstyle hidden -Command {
$i = 0
while ($true) {
if($i -gt 30) {
break
}
else {
$i | Out-File C:\Temp\IndependentSessionTest.txt -Append
Start-Sleep -Seconds 1
$i++
}
}
}
'
This will start a new session, run the script you want, not show a window and not use your powershell profile when the script gets run. You will be able to see that even if you kill the original PowerShell session, this one will keep running. You can verify this by looking at the IndependentSessionTest.txt file after you close the main powershell window and see that the file keeps getting updated numbers.
Hopefully this points you in the right direction.
Here's some source links:
PowerShell launch script in new instance
How to run a PowerShell script without displaying a window?
Currently, I try to run a PowerShell-Script, which starts a few instances with Start-Job -name $jobname -Scriptblock { ... Code ...};
This PowerShell-Script should be executed every 15 minutes in the WIndows Task Schedule. I run this process with highest priviledges, and the Power-Shell-Script starts perfectly - the problem is:
The Code, which is executed by Start-Job doesn't work.
I think the problem is that the "Start-Job" can not work with the task schedule together.
Do you know how to solve that? Are there any settings to configure?
Thank you, SUT
If no any control at the end of script, Powershell will immediately exit once background job is created. So try to add below control code:
$runningJobs = Get-Job -State Running
while($runningJobs.Count -gt 0){
Start-Sleep -Seconds 1
$runningJobs = Get-Job -State Running
}
Write-Host "Done!" -ForegroundColor Red -BackgroundColor Black
I'm new to this Powershell lark, and I understood that Stop-Process should be sufficient to end a task. However, it didn't close the newly created window and it left me uncertain if the process had stopped or not.
But, after doing some ID checking, I discovered that the process ID had been removed from the list. Is it, therefore, best practice to call Stop-Process and then CloseMainWindow() ... or is CloseMainWindow() sufficient on its own?
Cls
$notepadId = Start-Process notepad -passthru
Echo "" "notepadId = "
Echo $notepadId.Id
Echo "" "Current Notepad tasks:"
Get-Process notepad
Start-Sleep -s 2
Echo "" "Stopping Task:"
Stop-Process $notepadId.Id -Force
Echo "" "Closing Window:"
(Get-Process -Id $notepadId.Id).CloseMainWindow()
Start-Sleep -s 2
Echo "" "Tasks remaining:"
Get-Process notepad
Pause
I don't know why it's not working for you, but here's how I'd write it:
Cls
$notepadProcess = Start-Process notepad -passthru
Start-Sleep -s 2
Stop-Process $notepadProcess
The return-value from Start-Process is actually a Process object, not just the ID. If you pass that process object to Stop-Process, it knows what to do. However, a few experiments suggest that Stop-Process is not synchronous, so if you do this:
Cls
$notepadProcess = Start-Process notepad -passthru
Start-Sleep -s 2
Stop-Process $notepadProcess
get-process Notepad -ErrorAction Ignore
You will probably still see the process listed, however a few hundred milliseconds sleep before the Get-Process command should be sufficent to eliminate it.
I have an executable at "C:\Users\Admin\Desktop\scraper\work.exe" and I'd like to do the following in Powershell.
Step 1: Run work.exe for an hour and stop
Step 2: Wait for half an hour
Repeat step 1
I hope there is a clean and simple solution. I have looked at Start-Process and Wait-Process with no success. Thanks.
You can start the process and grab the PID, then use that to stop it later. This will do what you asked forever (while 1).
While (1) {
$proc = Start-Process C:\Users\Admin\Desktop\scraper\work.exe -PassThru
Start-Sleep -Seconds (60*60)
Stop-Process $proc.Id -force
Start-Sleep -Seconds (30*60)
}
You can use Start-Sleep -s or -m
[Exampe and usage][1]https://technet.microsoft.com/en-us/library/ee177002.aspx