Table of Contents |
---|
Scope
- JobScheduler offers Agents support PowerShell as a language for implementation of jobs, see
Jira server SOS JIRA columns key,summary,type,created,updated,due,assignee,reporter,priority,status,resolution serverId 6dc67751-9d67-34cd-985b-194a8cdc9602 key JS-1595 - The introduction of PowerShell as a language for JobScheduler has not only with API jobs to do, but can also be used a language for shell jobs.
- There are some differences between Shell and PowerShell Jobs that will be supported as they are (see PowerShell as a Shell).
- support for PowerShell fills the gap between Shell jobs and API jobs:.
- PowerShell jobs can use any Windows commands or PowerShell cmdlets and functions.
- PowerShell jobs can use the objects and methods of the JobScheduler API for PowerShell.
- Some minor differences exist between classic Shell jobs and PowerShell jobs, see Compatibility between PowerShell and ShellThe decision to include PowerShell as a language for JobScheduler (among others) is in the same line with the development of Microsoft programming languages.
- PowerShell jobs are executed with Agents, not with a Master
Feature Availability
Display feature availability | ||
---|---|---|
|
Examples
Example: PowerShell as a Shell
Example 1: A simple PowerShell job with some scripting similar to basic shell jobs might look like this:
Code Block |
---|
<?xml version="1.0" encoding="ISO-8859-1"?>
<job process_class="my_Agent">
<script language="powershell">
echo "job is starting"
# pauses the job for 10 seconds
sleep 10
# show the files in a directory
$files = dir *
echo $files
echo "job is finishing"
</script>
<run_time />
</job>
|
Example 2: A basic PowerShell job including the call to a function might look like this:
Code Block |
---|
<?xml version="1.0" encoding="ISO-8859-1"?>
<job process_class="my_Agent">
<script language="powershell">
# PowerShell function used for the main job
function get_files($directory){
echo "entering function get_files"
return get-childitem $directory
}
echo "job is starting"
sleep 10
# the same structure as in the example 1 but using a PowerShell function
$files = get_files "my_directory"
echo $files
echo "job is finishing"
</script>
<run_time />
</job> |
Example: PowerShell API Jobs
A basic API Job might look like this:
- JobScheduler Master.
Background
- From the early days of JobScheduler the distinction between Shell jobs and API jobs was introduced:
- Shell jobs include whatever can be executed from the command line of the respective shell (Unix or Windows)
- API jobs are coded in a programming/scripting language. JobScheduler exposes its API to supported languages.
- With PowerShell jobs such differences are leveled in a way that PowerShell jobs can include
- commands such as
- any calls to Windows commands and programs
- any PowerShell cmdlets
- any calls to .NET classes
- callback functions such as
spooler_init(), spooler_open(), spooler_process(), spooler_close(), spooler_exit() as known from API jobs:
- without a callback function being specified script code is automatically executed within the scope of a
spooler_process()
callback function.
- without a callback function being specified script code is automatically executed within the scope of a
- commands such as
- At the time of writing performance penalties are obseved for PowerShell jobs due to loading the .NET Framework for the PowerShell run-tme:
- the delay for PowerShell jobs starting compared to Shell job is about 1-2s. The effective delay depends on the users system performance.
- this delay corresponds more or less to the time required to execute
PowerShell.exe
from the command line.
Feature Availability
Display feature availability | ||
---|---|---|
|
Examples
For use of the following examples create a process class configuration that points to an Agent running on the same or on a different server. The configuration for a process class my_Agent.process_class.xml
could look like this:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
<process_class max_processes="10" remote_scheduler="http://localhost:4445"/> |
Example: PowerShell Job
Example: A simple PowerShell job with some scripting similar to shell jobs might look like this:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
<job process_class="my_Agent">
<script language="powershell">
<![CDATA[
echo "job is starting"
# pause the job for 10 seconds
Start-Sleep -Seconds 10
# list files in a directory
$files = dir *
echo $files
# execute some Windows command script
/tmp/some_batch_script.cmd
echo "job is finishing"
]]>
</script>
<run_time />
</job>
|
Example: A basic PowerShell job including the call to a function might look like this:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
<job process_class="my_Agent">
<script language="powershell">
<![CDATA[
# PowerShell function used in main job
function Get-Files( $directory )
{
echo "entering function get_files"
return Get-ChildItem $directory
}
echo "job is starting"
Start-Sleep -Seconds 10
$files = Get-Files "c:\tmp\my_directory"
echo $files
echo "job is finishing" | ||||||
Code Block | ||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
<job process_class="/tests/Agent" stop_on_error="no">
<script language="powershell">
<![CDATA[
function spooler_process(){
# set variables to store the information about job and task
$jobName = $spooler_job.name()
$jobTitle = $spooler_job.title()
$taskID = $spooler_task.id()
# show the information about job and task
echo "job $jobName with title $jobTitle is starting"
echo "task ID is $taskID"
echo "job is finishing"
# for standalone jobs set to false / for order jobs set to true
return $false
}
]]>
</script>
<run_time />
</job> |
...
Example:
...
PowerShell API Job
A basic API job might look like this:
Code Block | ||||||
---|---|---|---|---|---|---|
|
This PowerShell job contains a job with a pre-processing Monitor script (API job) that is executed before the job script (the shell job) is executed:
<?xml version="1.0" encoding="ISO-8859-1"?> <job process_class="my_Agent"/tests/Agent" stop_on_error="no"> <script language="powershell"> echo "job is starting" sleep 10 echo "job is finishing" </script> <monitor name="process_powershell" ordering="0"> <script language="powershell"> <![CDATA[ function spooler_process_before() { # check for a "go" file that is required to start the job $rc = (Test-Path -Path "/tmp/go.txt" -PathType Leaf) echo ".. looking up go file: $rc" return $rc } <![CDATA[ function spooler_process() { # set variables to store the information about job and task $jobName = $spooler_job.name() $jobTitle = $spooler_job.title() $taskId = $spooler_task.id() # display the information about job and task echo "job $jobName with title $jobTitle is starting" echo "task ID is $taskId" echo "job is finishing" # for standalone jobs set return code to false / for order jobs set to true in case of successful execution return $false } ]]> </script> </monitor> <run_time /> </job> |
Explanations
...
Example: Combine both PowerShell Job and Monitor
This PowerShell sample job implements a pre-processing Monitor script that is executed before
...
Example: PowerShell Job with different outputs
The following job shows how to set different outputs for PowerShell such as:
the job script is executed:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<?xml version="1.0 |
...
linenumbers | true |
---|
...
" encoding="ISO-8859-1"?> |
...
<job process_class="my_Agent |
...
"> <script |
...
language="powershell"> |
...
<![CDATA[ |
...
echo "job is starting" Start-Sleep -Seconds 10 echo "job is finishing" |
...
]]>
</script>
<monitor name="process_powershell" ordering="0">
<script language="powershell">
<![CDATA[
function spooler_process_before()
{
# check for a "go" file that is required to start the job
$rc = ( Test-Path -Path "/tmp/go.txt" -PathType Leaf )
echo ".. looking up go file: $rc"
return $rc
}
]]>
</script>
</monitor>
<run_time />
</job> |
Explanations
- The monitor script is executed before a task is started for this job.
- Its purpose is to decide if the task should be started or not. This decision is taken from the existence of the file
/tmp/go.txt
. - The return code reflects the decision to start or not to start a task for the job.
Example: PowerShell Job with different output channels
The following sample job explains how to use output channels for PowerShell such as:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
<job process_class="my_Agent" stop_on_error="no">
<settings >
<log_level ><![CDATA[debug1]]></log_level>
</settings>
<script language="powershell">
<![CDATA[
# Use Write-Host, Write-Output or Echo cmdlets to write to the JobScheduler log
Write-Host "job: this is some output"
Write-Output "job: this is some output"
echo "job: this is some output"
# Standard PowerShell verbose setting is used for log output, consider script scope when modifying this variable
$script:VerbosePreference = "Continue"
# In addition the current log level of the job has to be set, i.e. log level "debug1" or higher logs verbose output
Write-Verbose "job: this is some verbose output"
# Standard PowerShell debug setting is used for log output, consider script scope when modifying this variable
$script:DebugPreference = "Continue"
# In addition the current log level of the job has to be set, i.e. log level "debug3" or higher logs debug messages
Write-Debug "job: this is some debug output"
# creates a warning for the job
Write-Warning "job: this is a warning"
# can be used to throw an error
Write-Error "job: this is an error"
]]>
</script>
<run_time />
</job> |
Explanations
- Using PowerShell standard output
- Use of the
Write-Host
,Write-Output
andEcho
cmdlets is applicable.
- Use of the
- Using PowerShell verbose output
- The standard PowerShell verbosity setting is considered for log output if the job is configured for a log level
debug1
or higher. - Use
$script:VerbosePreference = "Continue"
- Subsequently use the
Write-Verbose
cmdlet.
- The standard PowerShell verbosity setting is considered for log output if the job is configured for a log level
- Using PowerShell debug messages
- The PowerShell debug setting is considered for log output in jobs if the job is configured for a log level
debug3
or higher. - Use
$script:DebugPreference = "Continue"
- Subsequently use the
Write-Debug
cmdlet.
- The PowerShell debug setting is considered for log output in jobs if the job is configured for a log level
- Using PowerShell Warnings
- Warnings are created by use of the
Write-Warning
cmdlet. Such warnings cause corresponding warnings in the JobScheduler Master that are visible from the log and that might trigger a notification by e-mail.
- Warnings are created by use of the
- Using PowerShell Error Messages
- Use of the
Write-Error
cmdlet will raise a job error that is visible from the log and that triggers subsequent actions as e.g. notification by e-mail, stopping the job, suspending an order etc.
- Use of the
JobScheduler PowerShell CLI for Jobs
Info |
---|
|
The JobScheduler PowerShell CLI module is available for PowerShell jobs. A basic job using the PowerShell CLI might look like this:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
<job process_class="my_Agent">
<script language="powershell">
<![CDATA[
Import-Module JobScheduler
# display summary information
Show-Status
# retrieve the number of available job chains
( Get-JobChain ).count
# get the number of current tasks
( Get-Task ).count
]]>
</script>
<run_time />
</job> |
Explanations
- The PowerShell CLI is activated by the
Import-Module JobScheduler
command. - For a complete list of cmdlets available from the PowerShell CLI see PowerShell CLI 1.1 - Cmdlets
Additional examples are available from the PowerShell CLI 1.1 - Use Cases article.
Parameter Handling
Reading Order parameters or Job parameters
PowerShell jobs offer additional methods for reading parameters:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
# Example PowerShell solution 1: environment variable for task/order parameter
$env:SCHEDULER_PARAM_NAME1
# Example PowerShell solution 2: shorthand notation for task/order parameter
$spooler_params.get( "name1" )
$spooler_params.value( "name1" )
# Example PowerShell solution 3 - read all task/order parameters as Variable_set
$variableSet = $spooler_params.getAll()
# Example PowerShell solution 4 - read all task/order parameters as object
$parameters = $spooler_params.items
$parameters.name1
# Example PowerShell solution 5: access task parameter
$spooler_task.params().value( "name1" )
# Example PowerShell solution 6: access order parameter
$spooler_task.order().params().value( "name1" ) |
Explanations
- Parameter passing by environment variables is only available for PowerShell jobs that do not implement any of the API functions
spooler_init(), spooler_exit(), spooler_process()
etc.- Solution 1
$env:SCHEDULER_PARAM_NAME1
returns the respective parameter
- Solution 1
- A new object
$spooler_params
has been introduced- The objects includes parameters from both job and order. For parameters with the same name an order parameter beats a job parameter.
- The object includes the following methods:
- Solution 2
$spooler_params.get( "name1" )
reads a parameter value$spooler_params.value( "name1" )
is an alias for$spooler_params.get()
- Solution 3
$spooler_params.getAll()
returns a Variable_set with all job and order parameters.
- Solution 4
$parameters = $spooler_params.items
returns a PSObject that allows to access individual parameters as PowerShell properties$parameters.name1
returns the parameter"name1"
as property
- Solution 2
- The usual API methods for parameters access are available:
- Solution 5
$spooler_task.params().value( "name1" )
reads a job parameter
- Solution 6
$spooler_task.order().params().value( "name1" )
reads an order parameter
- Solution 5
Returning a parameter and its value to an Order or Job
Additionals methods are available for returning parameter values:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
# Example PowerShell solution 1: set task/order parameter
$spooler_params.set( "name1", "value2" )
# Example PowerShell solution 2: setting a task parameter
$spooler_task.params().set_value( "name1", "value2" )
# Example PowerShell solution 3: setting an order parameter
$spooler_task.order().params().set_value( "name1", "value2" ) |
Explanations
- Parameters are return
- Solution 1
$spooler_params.set( "name1", "value2" )
- sets a job parameter if the current job is configured as a standalone job
- sets an order parameter if the current job is configured for a job chain.
- Solution 2
$spooler_task.params().set_value( "name1", "value2" )
sets a parameter for a job (for instance parametername1
with the initial valuevalue1
) and modifies the value tovalue2
- Solution 3
$spooler_task.order().params().set_value( "name1", "value2" )
sets a parameter for an order (for instance parametername1
with the initial valuevalue1
) and modifies the value tovalue2
- Solution 1
Anchor | ||||
---|---|---|---|---|
|
PowerShell jobs can be considered as a migration path for shell jobs. This suggests that any shell job can possibly be converted (with a few changes) to a PowerShell job.
Please consider compatibility issues as explained below.
Reading Order parameters or Job parameters
Reading parameters works slightly different for PowerShell jobs than for shell jobs, using $env:VARIABLE
for PowerShell instead of %VARIABLE%
as for shell:
Code Block |
---|
# Example Shell: environment variable for task/order parameter
myscript.cmd %SCHEDULER_PARAM_NAME1%
# Example PowerShell solution 1: environment variable for task/order parameter
myscript.cmd $env:SCHEDULER_PARAM_NAME1
# Example PowerShell solution 2: shorthand notation for task/order parameter
myscript.cmd $spooler_params.get( "name1" )
myscript.cmd $spooler_params.value( "name1" ) |
Returning a parameter and its value to an Order
Setting a parameter for an order (for instance parameter name1
with the initial value value1
) and modifying the value to value2
and returning the parameter to the order so that the next job chain node uses the new value. For PowerShell this works using the API method available from $spooler_task.order()
:
Code Block |
---|
# Example Shell:
echo name1 = value2 >> %SCHEDULER_RETURN_VALUES%
# Example PowerShell solution 1:
$spooler_task.order().params().set_value( "name1", "value2" )
# Example PowerShell solution 2: shorthand notation for task/order parameter
$spooler_params.set( "name1", "value2" ) |
Execution Policies
By default PowerShell ships with the execution policy Restricted
that does not allow to run scripts from files.
Should jobs be able to run external PowerShell script files then the execution policy has to be modified. This can be performed
- at machine level, e.g. if an administrator executes
Set-ExecutionPolicy RemoteSigned
- at user level if the the user executes
Set-ExecutionPolicy bypass -scope CurrentUser
- at process level if the the user executes
Set-ExecutionPolicy bypass -scope
process
Should execution policies not be explicitly ruled for a scheduling environment then we recommend to add Set-ExecutionPolicy bypass -scope
process
to the profile on a Windows platform.
Profile Handling
Display feature availability | ||
---|---|---|
|
Profile Locations
JobScheduler handles PowerShell profiles in a similar way to the PowerShell host.
- The $PROFILE variable returns a collection of locations that a profile is looked up for. By default PowerShell would use four variables as stated below that are mapped by JobScheduler to two possible profile locations.
- If a profile is found in a number of locations then all profiles are processed in the sequence as stated below.
Profile locations (<agent_data>
points to the data directory that is configured for an Agent, usually by use of the SCHEDULER_DATA environment variable with the Agent instance script):
- $PROFILE.AllUsersAllHosts, $PROFILE.AllUsersCurrentHost
<agent_data>\config\powershell\JobScheduler.PowerShell_profile.ps1
- $PROFILE.CurrentUserAllHosts, $PROFILE.CurrentUserCurrentHost
- Agent/Job runs as system account: the same profile as stated above is processed
<agent_data>\config\powershell\JobScheduler.PowerShell_profile.ps1
- Agent/Job runs as user account: the profile is looked up in the
Users
sub-directory for the current user (indicated by<user_name>
).<agent_data>\config\Users\<user_name>\powershell\JobScheduler.PowerShell_profile.ps1
- Agent/Job runs as system account: the same profile as stated above is processed
For details check
Jira | ||||||||
---|---|---|---|---|---|---|---|---|
|
Use of Profiles
Profiles can be used
- to specify alias names for cmdlets,
- to specify global variables, e.g. paths, that can be used by all jobs,
- to import PowerShell modules, e.g. to specify
Import-Module JobScheduler
for use of the PowerShell CLI - to specify the behavior in case of errors by use of the
$ErrorActionPreference variable
- A value
$ErrorActionPreference = "Continue"
(Default) allows a PowerShell script to continue after an error occurred. It is up to the script developer to check for errors, e.g. by use of exceptions. - A value
$ErrorActionPreference = "Stop"
is the recommended setting as it immediately stops execution of the script after an error occurred.
- A value
Error Handling
PowerShell jobs offer a number of options to detect run-time errors.
Error handling by JobScheduler
Checking the exit code of PowerShell script
- PowerShell scripts can use the
exit()
function to stop execution and to signal the execution result by specifyingexit(0)
for successful executionexit(1)
or any non-zero numeric value
- JobScheduler will report the value of the exit() function as the job execution result.
Checking the last exit code of a Windows program or script
- If a native Windows program or script (.bat, .cmd) causes an error then this will assign the exit code to the
$LastExitCode
global variable.- If a number of programs/scripts are executed from a PowerShell job then the result of the last program/script will decide about the exit code stored with
$LastExitCode
. - This behavior does not apply to cmdlets causing errors.
- The behavior to stop script execution in case of an error by use of the
$ErrorActionPreference
does not apply to errors caused by programs/scripts but to PowerShell commands and cmdlets only.
- If a number of programs/scripts are executed from a PowerShell job then the result of the last program/script will decide about the exit code stored with
- JobScheduler checks this variable and will set the job exit code accordingly. For exit codes != 0 an error is raised.
- This behavior is superior compared to shell jobs as errors from any line in the job script are detected. For shell scripts only the last line of a job script determines the execution result (Unix:
$?
, Windows:%ERRORLEVEL%
).
Checking error output
- Native Windows programs or scripts and cmdlets can cause errors that create some error output (stderr).
- PowerShell jobs can be configured to handle any output found in stderr to indicate an error. Not all output to stderr may indicate an error as a number of Windows native programs is reported to write to stderr instead of stdout. Therefore users can choose from the following configuration:
<job stderr_log_level="error"/>
- Indicates that any output found in stderr will result in a job error.
<job stderr_log_level="info"/>
- Indicates that output to stderr is logged but will not result in a job error (default).
- Users should consider that output checking is performed after the job has completed. It can therefore not be used to stop execution of a script in case of error, however, we recommend to use output checking that would set the execution result of jobs in case of errors that are not handled by the script.
- For details check
andJira server SOS JIRA columns key,summary,type,created,updated,due,assignee,reporter,priority,status,resolution serverId 6dc67751-9d67-34cd-985b-194a8cdc9602 key JS-1329 Jira server SOS JIRA columns key,summary,type,created,updated,due,assignee,reporter,priority,status,resolution serverId 6dc67751-9d67-34cd-985b-194a8cdc9602 key JS-1393
Error handling by job scripts
Checking cmdlet errors
- By default PowerShell most cmdlets write errors to the stderr output channel that is captured by JobScheduler.
- This does not include that a processing error is raised as in this situation the next line of the PowerShell job script would be executed.
- Users can force PowerShell to throw an exeception in case of cmdlet errors
- by setting the global variable
$ErrorActionPreference = "Stop"
. This would stop processing immediately and prevent subsequent lines of the PowerShell job script from being executed. The value of this variable will be considered in case of cmdlet errors and in case of syntax errors, e.g. when using wrong parameterization for cmdlets. JobScheduler will detect this type of error. It is recommended to set this variable in the PowerShell Profile, see chapter Profile Handling. - by setting the
-ErrorAction stop
parameter provided that the cmdlet supports common parameters. The-ErrorAction
parameter is not considered for syntax errors when using cmdlets, e.g. in case of wrong parameterization.
- by setting the global variable
Suppressing Exit Codes
- Users who wish to suppress exit codes of failed executions of native Windows programs or scripts can use
$script:LastExitCode = $null
- This will disable the above mentioned check of the last exit code.
Catching errors
- Users can use
try/catch
blocks to implement individual error handlingThis simple example prevents errors from being raised for non-accessible network shares:
Code Block language powershell try { $found = Test-Path \\some_share\some_directory\some_file -PathType Leaf } catch { $found = $false }
- From the above example an exception is raised and handled that does not result in a job error. In addition no output to stderr is created that would be detected by the above mentioned error output checking.
Explanations
- Setting PowerShell verbosity for a job
- The standard PowerShell verbosity setting is considered for log output
- Use
$VerbosePreference = "Continue"
followed by theWrite-Verbose
cmdlet.
- Setting PowerShell debug messages for a job
- The Standard PowerShell debug setting is considered for log output in jobs (through
$DebugPreference = "Continue"
) - In addition, the current log level of the job has to be set, e.g. log level
debug1
will log debug messages - With the JobScheduler log level being switched to
info
no debug output is written to the log file - With the JobScheduler log level being switched to
debug1
,debug2
, ...,debug9
then debug output is added to the log. - The example shows how to set this at lines 16-17
- The Standard PowerShell debug setting is considered for log output in jobs (through
- Setting Warning Messages can be done as in line 19
- Setting Error Messages can be done as in line 22
- This throws an error and ends effectively the job with an error
Write-Host
does not work for PowerShell jobs as such jobs are not running in a PowerShell host console, but in a PowerShell run-time process.
Extras: PowerShell CLI for Powershell Jobs
The integration of the PowerShell CLI into PowerShell jobs is available as well. A basic job using the PowerShell CLI might look like this:
Code Block |
---|
<job process_class="my_Agent">
<script language="powershell">
<![CDATA[
Import-Module JobScheduler
show-status
]]>
</script>
<run_time /> |
Info |
---|
|
...
As mentioned before, PowerShell Jobs should be seen as a migration path for shell jobs. That means, every shell job should possibly be converted (with a few changes) to a PowerShell job.
Please consider compatibility issues as explained below.
Calling Order parameters or Job parameters
Calling parameters works differently for PowerShell jobs than for shell jobs, using $env:
for PowerShell instead of %
as for shell:
Code Block |
---|
# Example Shell:
myscript.cmd %SCHEDULER_PARAM_NAME1%
# Example PowerShell:
myscript.cmd $env:SCHEDULER_PARAM_NAME1 |
Returning a parameter and its value to an Order
Setting a parameter in an order (for instance parameter name1
with the initial value value1
) and modifying the value to value2
and returning the parameter to the order so that the next job chain node uses the new value. For PowerShell this works using the API methods for $spooler_task.order()
:
Code Block |
---|
# Example Shell:
echo name1 = value2 >> %SCHEDULER_RETURN_VALUES%
# Example PowerShell:
$spooler_task.order().params().set_value("name1","value2") |
...
References
Reference Documentation
- For further information about how to write API Jobs in PowerShell please check http://www.sos-berlin.com/doc/en/scheduler.doc/api/api-powershell.xmlcheck the Reference Documentation. You will find the available objects and methods as well as some useful examples for your API jobs
Change Management References
Jira | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|