Jobs
Jobs have the advantage of being able to run in the background and return the cursor to the shell. They allow you to run more than one command at a time without using multiple shells.
One thing to note is that jobs only exist in the current shell
PS C:\> (get-command -Noun job).name
Debug-Job
Get-Job
Receive-Job
Remove-Job
Resume-Job
Start-Job
Stop-Job
Suspend-Job
Starting a job is fairly easy just use Start-Job
PS C:\> Start-Job -ScriptBlock {dir c:\ -Recurse}
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob Running True localhost dir c:\ -Recurse
You can give your job a name which is a good idea if you are running multiple jobs
PS C:\> Start-Job -ScriptBlock {dir c:\ -Recurse} -Name longdirectoryJob
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
3 longdirector... BackgroundJob Running True localhost dir c:\ -Recurse
The command Get-Job can be used to check if the jobs are still running
PS C:\> get-job
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob Running True localhost dir c:\ -Recurse
3 longdirector... BackgroundJob Running True localhost dir c:\ -Recurse
The column HasMoreData tell you if there is any return value from the job
A job like this one that takes forever can be paused with Suspend-Job if the action allows it and resumed again with
Resume-Job or it can be stopped with Stop-Job
PS C:\> Stop-Job -Id 1
PS C:\> Get-Job
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob Stopped True localhost dir c:\ -Recurse
3 longdirector... BackgroundJob Running True localhost dir c:\ -Recurse
Stop-Job -Name longdirectoryJob
If you do a Receive-Job -Name Job1 you get all the data back but HasMoreData is set as false and leave memory
However if use Receive-Job -Id 3 -Keep you get all the data back only this time HasMoreData is True and is still kept in memory
PS C:\> Get-Job
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob Stopped False localhost dir c:\ -Recurse
3 longdirector... BackgroundJob Stopped True localhost dir c:\ -Recurse
To get rid of both of these jobs you can use: Get-Job | Remove-Job
Start-job is really for use on the local computer using local resources. To start jobs on remote computers use invoke-command
Invoke-Command -ScriptBlock {Get-EventLog -LogName Security -Newest 20 } -ComputerName localhost,w8p -AsJob -JobName eventlog
You can also use Get-WmiObject and commands that support as job
PS C:\> Get-WmiObject -Class win32_logicaldisk -ComputerName localhost,w10p -AsJob
Scheduled Jobs
PowerShell can do both scheduled jobs and scheduled tasks the main difference between the two is that Scheduled tasks appear in the task scheduler
PS C:\> gcm -Module PSScheduledJob
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Add-JobTrigger 1.1.0.0 PSScheduledJob
Cmdlet Disable-JobTrigger 1.1.0.0 PSScheduledJob
Cmdlet Disable-ScheduledJob 1.1.0.0 PSScheduledJob
Cmdlet Enable-JobTrigger 1.1.0.0 PSScheduledJob
Cmdlet Enable-ScheduledJob 1.1.0.0 PSScheduledJob
Cmdlet Get-JobTrigger 1.1.0.0 PSScheduledJob
Cmdlet Get-ScheduledJob 1.1.0.0 PSScheduledJob
Cmdlet Get-ScheduledJobOption 1.1.0.0 PSScheduledJob
Cmdlet New-JobTrigger 1.1.0.0 PSScheduledJob
Cmdlet New-ScheduledJobOption 1.1.0.0 PSScheduledJob
Cmdlet Register-ScheduledJob 1.1.0.0 PSScheduledJob
Cmdlet Remove-JobTrigger 1.1.0.0 PSScheduledJob
Cmdlet Set-JobTrigger 1.1.0.0 PSScheduledJob
Cmdlet Set-ScheduledJob 1.1.0.0 PSScheduledJob
Cmdlet Set-ScheduledJobOption 1.1.0.0 PSScheduledJob
Cmdlet Unregister-ScheduledJob 1.1.0.0 PSScheduledJob
The three main conponents of scheduling a job are:
New-JobTrigger
New-ScheduledJobOption
Register-ScheduledJob
First we will look at New-JobTrigger
NAME
New-JobTrigger
SYNOPSIS
Creates a job trigger for a scheduled job.
SYNTAX
New-JobTrigger [-Once] -At <DateTime> [-RandomDelay <TimeSpan>] [-RepeatIndefinitely] [-RepetitionDuration
<TimeSpan>] [-RepetitionInterval <TimeSpan>] [<CommonParameters>]
New-JobTrigger [-Daily] -At <DateTime> [-DaysInterval <Int32>] [-RandomDelay <TimeSpan>] [<CommonParameters>]
New-JobTrigger [-Weekly] -At <DateTime> -DaysOfWeek {Sunday | Monday | Tuesday | Wednesday | Thursday | Friday |
Saturday} [-RandomDelay <TimeSpan>] [-WeeksInterval <Int32>] [<CommonParameters>]
New-JobTrigger [-AtLogOn] [-RandomDelay <TimeSpan>] [-User <String>] [<CommonParameters>]
New-JobTrigger [-AtStartup] [-RandomDelay <TimeSpan>] [<CommonParameters>]
It all starts with the trigger and this one is set to run at logon
$trigger = New-JobTrigger -AtLogOn
The next thing needed is the scheduling option.
NAME
New-ScheduledJobOption
SYNOPSIS
Creates an object that contains advanced options for a scheduled job.
SYNTAX
New-ScheduledJobOption [-ContinueIfGoingOnBattery] [-DoNotAllowDemandStart] [-HideInTaskScheduler] [-IdleDuration
<TimeSpan>] [-IdleTimeout <TimeSpan>] [-MultipleInstancePolicy {None | IgnoreNew | Parallel | Queue |
StopExisting}] [-RequireNetwork] [-RestartOnIdleResume] [-RunElevated] [-StartIfIdle] [-StartIfOnBattery]
[-StopIfGoingOffIdle] [-WakeToRun] [<CommonParameters>]
So this is how we set an option
PS C:\> $option = New-ScheduledJobOption -RequireNetwork -WakeToRun
PS C:\> $option
StartIfOnBatteries : False
StopIfGoingOnBatteries : True
WakeToRun : True
StartIfNotIdle : True
StopIfGoingOffIdle : False
RestartOnIdleResume : False
IdleDuration : 00:10:00
IdleTimeout : 01:00:00
ShowInTaskScheduler : True
RunElevated : False
RunWithoutNetwork : False
DoNotAllowDemandStart : False
MultipleInstancePolicy : IgnoreNew
JobDefinition :
We have an option and a trigger now it is time to register our scheduled job.
NAME
Register-ScheduledJob
SYNOPSIS
Creates a scheduled job.
SYNTAX
Register-ScheduledJob [-Name] <String> [-FilePath] <String> [-ArgumentList <Object[]>] [-Authentication {Default |
Basic | Negotiate | NegotiateWithImplicitCredential | Credssp | Digest | Kerberos}] [-Confirm] [-Credential
<PSCredential>] [-InitializationScript <ScriptBlock>] [-MaxResultCount <Int32>] [-RunAs32] [-RunEvery <TimeSpan>]
[-RunNow] [-ScheduledJobOption <ScheduledJobOptions>] [-Trigger <ScheduledJobTrigger[]>] [-WhatIf]
[<CommonParameters>]
Register-ScheduledJob [-Name] <String> [-ScriptBlock] <ScriptBlock> [-ArgumentList <Object[]>] [-Authentication
{Default | Basic | Negotiate | NegotiateWithImplicitCredential | Credssp | Digest | Kerberos}] [-Confirm]
[-Credential <PSCredential>] [-InitializationScript <ScriptBlock>] [-MaxResultCount <Int32>] [-RunAs32] [-RunEvery
<TimeSpan>] [-RunNow] [-ScheduledJobOption <ScheduledJobOptions>] [-Trigger <ScheduledJobTrigger[]>] [-WhatIf]
[<CommonParameters>]
In this step we need to give it a name as well as a scriptblock.
So putting it all together the command would look like
Register-ScheduledJob -Name "get processes at logon" -ScriptBlock {ps} -MaxResultCount 2 -Trigger $trigger -ScheduledJobOption $option
If you were to log off and log back on again to trigger the job you could run get-job to view the status of this job and receive-job to get the output from the job.
