Task Scheduling and Powershell's Start-Job - powershell

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

Related

Kill a threadjob using debug-job

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?

How can I run powershell in the background if I want execution policy Bypass?

I have this batch file which runs the powershell script.
I want to run it the background but if I run with "windowstyle hidden" still visible.
powershell -ExecutionPolicy ByPass -windowstyle hidden -File "C:\script.ps1"
You can run, e.g. long running scripts, as a jobs.
To start it you run
$job = Start-Job -ScriptBlock {Get-Process}
this will start the Get-Process cmdlet in the background. The script can be also some custom made script or a longer script, it doesn't need to be a one-liner.
You can check its status by running
$job | Get-Job
and to receive the output you run
$job | Receive-Job
just note that once the data is received, it's lost. You can only receive it once, after that it's up to you to save it in a variable or later processing.
Finally to remove the job from the queue you run
$job | Remove-Job
I use the following function:
function bg() {
Start-Process `
-WorkingDirectory (Get-Location) `
-NoNewWindow `
-FilePath "powershell" `
-ArgumentList "-NoProfile -command `"$args`" "
}
It starts a new powershell instance which is executed in background and allows the usage of cmdlets.
You call it like:
bg "Start-Sleep 2; get-location; write 'done' "

Powershell build step, fire and forget?

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?

powershell loop for periodical checking running process

I'm trying to create a PowerShell script (loop) for periodical checking if some other PowerShell script with specific command is running. If not I start it.
This is what I have:
$processInfo = Get-WmiObject Win32_Process -Filter "name = 'powershell.exe'" | select CommandLine | Out-String -width 200
while($true) {
if ($processInfo -NotLike '*specific_path*') {
Write-Host 'process not running'
Start-Process powershell -argument '-f X:\specific_path\other_script.ps1'
}
else { Write-Host 'process is running' }
Start-Sleep -Seconds 60
}
The script correctly detects running or not running process when started. but when situation changes during the script run, it does not detect it.
Also, when script starts, detects that the other script is not running, it starts it correctly but then it does not see it already running and starts it again and again.
So the only problem I have (I believe) is how to get "fresh" data about running processes. Any ideas? Many thanks!

Fail a Scheduled Task When PS Script Fails

I run a PowerShell script using Task Scheduler and my issue is that when that script fails, the scheduled Task does not fail and therefore I do not get notified.
So when I run this script on PowerShell:
Add-PsSnapIn VeeamPSSnapIn
$Job = Get-VBRJOB -name "Whatever"
Start-VBRJOB -job $Job
I get the following exception:
However, when I run it using a scheduled task, the task does not fail.
How can I get it to fail when the script fails?
Reason I want it to fail is because when it fails, I get notified by Email. If you have any other way of doing it, like logging an event that can trigger the alert, this would be good too.
I'm using Windows Server 2008 R2.
Thanks,
Do you try to put you code into a try/catch statement ?
try
{
Add-PsSnapIn VeeamPSSnapIn
$Job = Get-VBRJOB -name "Whatever"
Start-VBRJOB -job $Job
$returnCode = 0
}
catch
{
$message = $_.exception.message
$returnCode = 1
}
return $returnCode
In my case I directly send email from the script with the message.
I ended up doing this
Add-PsSnapIn VeeamPSSnapIn
$Job = Get-VBRJOB -name "Type the job name here"
$error.clear() #To make sure I'm checking next statement only
Start-VBRJOB -job $Job
if ($error.count -gt 0)
{
Write-EventLog –LogName Application –Source “My Company” –EntryType Error –EventID 1 –Message “Whatever Message You Want"
}
Then I used Task Scheduler to send Emails when Error 1 from source "My Company" is logged.
Note: You need to create the events source "My Company" using this command on PowerShell:
New-EventLog –LogName Application –Source “My Company”
Hope this helps someone.
Ahmad