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.