Powershell Workflow - Resume Suspended Job in Visible Window - powershell

I've put together a powershell workflow script that runs on the local machine and calls some other scripts. The other scripts include write-output messages to let operators know what's happening on the system.
This is important because if an operator uses the computer while the workflow is running, things might not work properly. It's also helpful in debugging the scripts if something goes wrong.
Some of the scripts reboot the computer and suspend the workflow. I have a scheduled task to restart the suspended workflow after the computer logs back in.
The problem is that when this happens the workflow resumes running in the background and the write-output messages are no longer visible on screen.
Here's my code to schedule the workflow restart:
# Set up a job trigger to go off 15-20 seconds after login
$delayTime = New-TimeSpan -Start 00:0:15 -End 00:0:20
$AtLogOn = New-JobTrigger -AtLogOn -RandomDelay $delayTime
# Set up the task action to start Powershell and run this code
$resumeScript = 'Get-Job -State Suspended | Resume-Job; pause'
$action = New-ScheduledTaskAction -Execute powershell -Argument $resumeScript
# Actually registering the scheduled task with the above inputs
Register-ScheduledTask -TaskName ResumeSetup -Trigger $AtLogOn -Action $action -RunLevel Highest
How can I have Powershell resume a workflow in an open powershell window so the write-output messages are visible?

Related

Trying to start firefox from a batch file (task scheduler) using Windows Powershell, but the window is not appearing

I am trying to run a command in windows powershell that will start a task schedule. Below is the command that I am using:
Start-ScheduledTask -TaskName "pkms task scheduler"
The powershell can run the task and the batch files from the scheduler but I do not know what is the problem why the Firefox window is not appearing even though the browser is running in the background.
Here is the code for the batch file:
#echo off cls start "" /d "C:\Kiosk Advertisement" firefox.exe.lnk exit
Hope that you can help me. Comment if you need more information
I did try to put "/max" beside the start command but the window is still not appearing.
If your goal is just to start Firefox, the simplest way would be to use the path to your firefox executable to create the scheduled task action, like so:
$StartFirefoxScheduledTaskAction =
New-ScheduledTaskAction `
-Execute 'C:\Program Files\Mozilla Firefox\firefox.exe'
Register-ScheduledTask `
-TaskName 'Start Firefox' `
-Action $StartFirefoxScheduledTaskAction
Note: you can pass multiple actions to the Register-ScheduledTask's -Action parameter.
Now, if you need something more sophisticated, please elaborate your question and tell us what you're trying to achieve with more details.

Register-Scheduledjob for mandatory profile users

I have a PowerShell script that I want to run in the background every few minutes. Creating a scheduled task for this script doesn’t work, because even when run with –windowstyle hidden, there is still a brief flash of the PowerShell box, which we cannot have. I have found that running this script as a PowerShell scheduled job works with no visual clues at all.
The scheduled jobs appear to store relevant information in the location %APPDATA%\Local\Microsoft\Windows\PowerShell. The problem I am facing is that we are using mandatory profiles for our users on Windows 10 PCs, so anything stored in the user’s profile disappears when they log out. This means that the scheduled job has to be recreated every time the user logs in, but the users do not have the permissions necessary to create the job.
I have created a PowerShell script that creates the necessary job, but it requires elevation to work.
My first thought was to create a scheduled task that runs at log on. This task would then launch the script to create the scheduled job. I tried this using GPO so the task would be created and run with the system account, but I am still not getting the results I am looking for.
When I successfully create the job as an admin and then export to XML, I see the reference to the %APPDATA% location. Is there a way to import the scheduled job from an xml file that has been edited to refer to a different store? Is there a way to register the job and have it use a different disk space instead of %APPDATA%?
Here is the script to create the job:
$start = (get-date)+(New-TimeSpan -Minutes 10)
$trigger = New-JobTrigger -at $start -once -RepetitionInterval (New-TimeSpan -Minutes 5) -RepeatIndefinitely
Register-ScheduledJob -Name "JobName" -Trigger $trigger -ScriptBlock { *JobScriptGoesHere* }

Prevent Powershell close on Shutdown

I have a Script to execute a code at shutdown but the code don't get executed because Windows closes the Powershell session.
Is there a way to prevent Powershell from closing if you press shutdown Windows?
To track the shutdown I use:
Register-ObjectEvent -InputObject $sysevent -EventName "SessionEnding" -Action { [Windows.Forms.MessageBox]::Show("Shutdown!", "", [Windows.Forms.MessageBoxButtons]::OK, [Windows.Forms.MessageBoxIcon]::Warning)}
Register-ObjectEvent -InputObject $sysevent -EventName "SessionEnded" -Action { [Windows.Forms.MessageBox]::Show("Shutdown!", "", [Windows.Forms.MessageBoxButtons]::OK, [Windows.Forms.MessageBoxIcon]::Warning)}
Edit:
I have a Script that runs in the background. This script is used to activate a product on a Server. If the user shutdown the pc, the script should deactivate the product on a server.
Situation now: Script run normal, product is activated on server. After on shutdown the script closes and do nothing
Situation expected: Script run normal, product is activated on server. After on shutdown the script runs last command and then shutdown the machine

Windows Task for restart if user not logged in

I'm trying to create scheduled task for Windows reboot, which is executed if any user is not logged in. If user is logged in locally or over RDP, the machine should not be restarted.
For unconditional restart, I have task in Task Scheduler with:
Action: "Start a program", Program/script: "powershell", Add arguments: "restart-computer -force"
For conditional restart I have powershell code:
$ErrorActionPreference = "Continue"
$userstatus = quser /server:'localhost'
if(!$userstatus){
Restart-Computer -Force
}
else{
exit
}
I can get the conditional restart working fine when I save the script as .ps1 file and add the filepath to the schedule as argument. I need the conditional restart with several desktops and I would like to avoid saving the .ps1 file locally for each machine. Is it possible to pass the entire script as argument?
Your logic's a bit off. If you plan on creating the scheduled task for each PC, it should look something like this:
$Users = quser.exe
If ($Users -match 'No\sUser') { Restart-Computer -Force }
From here, because of the syntax, you should encode it, then you could utilize schtasks.exe to create your task:
[Convert]::ToBase64String(
[Text.Encoding]::Unicode.GetBytes(
"If(#(quser.exe) -match 'no\suser'){Restart-Computer -Force}"
)
)
Output:
SQBmACAAKABAACgAcQB1AHMAZQByAC4AZQB4AGUAKQAgAC0AbQBhAHQAYwBoACAAJwBuAG8AXABzAHUAcwBlAHIAJwApAHsAUgBlAHMAdABhAHIAdAAtAEMAbwBtAHAAdQB0AGUAcgAgAC0ARgBvAHIAYwBlAH0A
schtasks.exe /Create /TN AutoRestart /SC DAILY /ST 20:00 /RU SYSTEM /TR "powershell.exe -EncodedCommand SQBmACAAKABAACgAcQB1AHMAZQByAC4AZQB4AGUAKQAgAC0AbQBhAHQAYwBoACAAJwBuAG8AXABzAHUAcwBlAHIAJwApAHsAUgBlAHMAdABhAHIAdAAtAEMAbwBtAHAAdQB0AGUAcgAgAC0ARgBvAHIAYwBlAH0A"

How to trigger one PS script from another after a set time, without blocking execution

Say I have a file A.ps1 that calls B.ps1:
& "B.ps1"
I want the contents of B.ps1 to run after N seconds, without blocking A.ps1. In this case, A.ps1 would finish immediately, and then the contents of B.ps1 would run after a set time.
How can this be achieved?
Context
We're leveraging Release Management to deploy builds with a powershell script. Sometimes RM outputs logging data that we need into a IR_ProcessAutoOutput file - but this only gets generated once RM completes. So I want to defer execution of the "GetLogs" script for ~20 seconds without blocking, allowing RM to complete and generate the IR_ProcessAutoOutput in the meantime.
Use Start-Process instead of the call operator.
Start-Process 'powershell.exe' -ArgumentList '-File', 'B.ps1'
If you don't want the process to run in a different window add the parameter -NoNewWindow.
You could also run the second script as a background job:
Start-Job -Scriptblock { & 'B.ps1' }
If you want B.ps1 to start after A.ps1 already terminated you'd need to create a scheduled task, though. Or add a delay at the beginning of B.ps1:
Start-Sleep -Seconds 20
...
As suggested by Ansgar, an alternative to Start-Process is scheduling a task instead.
Make sure the task gets deleted automatically after execution
# A.ps1 doing its thing, and then:
$DelayInSeconds = 5
$SchTaskProperties = #{
# Invoke powershell.exe -WindowStyle Hidden -File B.ps1
Action = New-ScheduledTaskAction -Id 0 -Execute powershell -Argument "-WindowStyle Hidden -File B.ps1" -WorkingDirectory 'C:\path\to\scripts'
# Let it trigger in 5 seconds
Trigger = New-ScheduledTaskTrigger -At $([datetime]::Now.AddSeconds($DelayInSeconds)) -Once
# Set task to be deleted after expiration, see below
Settings = New-ScheduledTaskSettingsSet -DeleteExpiredTaskAfter (New-TimeSpan -Seconds 0)
# Make up unique task name
TaskName = "MyTask $([guid]::NewGuid())"
}
# Give the Trigger an EndBoundary (2 minutes later) to make sure it expires and is deleted
$SchTaskProperties['Trigger'].EndBoundary = [datetime]::UtcNow.AddMinutes(2).ToString('s') + 'Z'
# Register the task
Register-ScheduledTask #SchTaskProperties |Out-Null
# Do whatever else A.ps1 needs to