MAKEMSI quickly and reliably creates MSI files in a non-programmatic way
\Tips and TricksToolsJT.EXE

 JT.EXE

This is a free tool from Microsoft which is believe available in both NT and WIN2000 resource kits. Windows XP has yet another tool which comes with the operating system called "SCHTASKS.EXE" (Microsoft never seem to get anything right...)!

This tool is used to set up job/task schedules in the Windows NT, 2000 and XP scheduling GUI (from the command line). WinNT seems to generate weird "permission denied" errors on longer command lines (about 500 chars?) so it is advisable to use the "@ file" mechanism to shorten it.

The "Schedule" command requires this tool (or "SCHTASKS.EXE") to be available at install time (you can install it along with your package if required). You can download it from microsoft's site (ftp://ftp.microsoft.com/reskit/win2000/jt.zip).

There is no documentation so you may wish to see the macro sample, also note that you can get help by typing "JT.EXE /?" or "JT.EXE /? LJ" etc. An easy way to get a list of task attributes is "JT.EXE /pj" (some of these don't work - probably JT.EXE bug).

The following is an example of the command I used when trying to work out the required syntax to set a trigger up the way I wanted it:

ms_jt /CTJ Type = WEEKLY TypeArguments=1,.M.W.F. /ptj

Note that in a lot of ways this tool is "brain dead" so you will have trouble at times getting it to work (for example I have not figured out how a double quoted parameter can contain double quotes, I suspect it can't). It would be too useful if it could dump a schedule in the same format it takes it which is why Microsoft decided not to include the feature...

 Debugging Creation Problems

Check the NAKEMSI (or Windows Installer) log for the full "JT.EXE" command, you should be able to run this command if you have left the install error message displayed (haven't rolled back yet).

The log or the commands console output will display some possibly useful but generally cryptic information (the "JT.EXE" output).

You always seem to get a message "[ERROR] Expected job property name but found token 'Interactive'", it does appear to work though...

It will say "Created trigger x" before it has done so (that is it should be "creating trigger"). It probably failed because of inconsistent values in the trigger. Try creating a very simple trigger following the failing one to be sure.

My "favourite" way of stuffing things up is to supply a smaller value for "MinutesDuration" than I supply for "MinutesInterval"... The "/SJ" switch seems to fail (or at least it says so and returns a non-zero return code) if the job already exists, I always delete any existing job first.

Using appropriate command line options you can load and existing job and display its values. This is a good way of working out what some of the values will be however, from memory it is not always correct (different keywords!).

 JT.EXE /?

Microsoft (R) Task Scheduler Command Line Utility
This executable compiled as a retail build for the Windows NT Resource Kit.

usage: JT {[options]|[@commandfile]}

options:

@ <file>           - parse file
/? [cmd]           - display help on [cmd], e.g. /? abj
!<cmd>             - don't stop if command returns error
/CTJ [<props>]     - create trigger in task
/DTJ [<id>]        - delete trigger <id> (default 0) from task
/EJ [<n> [T|F]]    - edit task page <n>, persist changes T/f
/ENC <id1> <id2>   - enumerator clone <id1> from <id2> (see SCE command)
/ENN <id> <n>      - enumerate next <n> items (see SCE command)
/ENR <id>          - enumerator reset (see SCE command)
/ENS <id> <n>      - enumerator skip forward by <n> (see SCE command)
/GC                - get credential account name
/GM                - get target machine
/ISJQ <file>       - test <file> to see if it is a task
/PJ                - print all properties of task
/PRJ [<n>]         - print next <n> or today's remaining run times of task
/PSJ [<id>]        - print trigger strings of <id> or all in task
/PTJ [<id>]        - print trigger props of <id> or all in task
/SC <acct> <pwd>   - set task credentials
/SCE <id>          - scheduler create enumerator in slot <id>=0..9
/SE [<n>] [P]      - scheduler enum tasks <n> at a time, [P]rint
/SJ <props>        - set task's properties
/SM [<machine>]    - set machine (NULL = local machine if omitted)
/STJ [id] props    - set properties of task trigger <id> or 0
/SVJ [<file>]      - save task to <file>

For detailed help use: JT /? <command-name>, e.g. JT /? LJ.

 CMD="JT.EXE /? /CTJ"

Command:

/CTJ [<props>] - create trigger in task

Purpose:

Create a new trigger.

Arguments:

[<props>] - Optional list of trigger properties.

Remarks:

The property list has the form <propname> = <value>...

The trigger properties and form of their values:

StartDate = <date>
EndDate = <date>
StartTime = <time>
MinutesDuration = n
MinutesInterval = n
HasEndDate = {1|0}
KillAtDuration = {1|0}
Disabled = {1|0}
Type = {Once|Daily|Weekly|MonthlyDate|MonthlyDOW|OnIdle|AtStartup|AtLogon}
TypeArguments = <type-args-list>

<date>           - { m/d/y | TODAY }
<time>           - { h:m | NOW }
<type-args-list> - see below

Note that NOW is actually 60 seconds in the future so it can be used to
create triggers that will fire soon.

The following table lists the forms of the <type-args-list> property
value for each of the trigger types:

Trigger       Argument List        Argument meanings
Type          Format
-----------   ------------         ----------------------------
DAILY         n                    DaysInterval
WEEKLY        n, <DOW>             WeeksInterval, DaysOfTheWeek
MONTHLYDATE   <DOM>, <months>      DaysOfTheMonth, Months
MONTHLYDOW    n, <DOW>, <months>   Week, DaysOfTheWeek, Months
ONCE                               (no args)
ONIDLE                             (no args)
ATSTARTUP                          (no args)
ATLOGON                            (no args)

<DOW> is a string with one letter per weekday.  To specify the task
is to run on every day, use the string UMTWRFA.  To specify no days
use a period.

<DOM> is a comma-separated list of day numbers and ranges.  Some examples:
1-31
10
20,21,22
1,3,5,7-10
2-8,20,12

<months> is a string containing three letter abbreviations for months.
For all months, use: JanFebMarAprMayJunJulAugSepOctNovDec (case and order
are not significant).

The trigger type must be specified before the type arguments, otherwise
properties may appear in any order.  Case, whitespace, and leading zeros
are not significant.

Examples:

/ctj
- creates a trigger with default values

/ctj StartTime=13:40 StartDate=3/4/1996 type=weekly typearguments = 1,mwf

 CMD="JT.EXE /? /DTJ"

Command:

/DTJ [<id>] - delete trigger <id> (default 0) from task

Purpose:

Delete a single trigger from task.

Arguments:

[<id>] - 0-based index of trigger to delete.  If omitted, trigger 0
will be deleted.

Examples:

/dtj 3

 CMD="JT.EXE /? /GC"

Command:

/GC - get credentials (account name only)

Purpose:

Print the credential account name

Examples:

/gc
- print the credential account name.

 CMD="JT.EXE /? /GM"

Command:

/GM - get target machine

Purpose:

Print the name of the currently targeted machine

Remarks:

This should appear as \\machine-name.
Note also that the target machine is not persisted across multiple runs of JT.

Examples:

/gm
- print the name of the current target of Scheduler commands.

 CMD="JT.EXE /? /LJ"

Command:

Purpose:

Arguments:

Remarks:

JT acts like notepad.exe, in that when it starts it creates a blank task
object, and all commands operate on that object.  You can fill that blank
object by loading a file from disk, or by putting data into it using the

Every Save command (/SVJ) is actually a Save As.

Just before JT exits, it checks to see if the task object is dirty.  If a
name has been associated with it by a Load or Save command, it will be
saved automatically.

The task object is *not* automatically saved before being loaded if it is
dirty.

Examples:

properties.

 CMD="JT.EXE /? /PJ"

Command:

/PJ - print all properties of task

Purpose:

Print properties and triggers of task.

Remarks:

To print only a single trigger, use PTJ.  To print only a
trigger string, use PSJ.

Examples:

/pj

 CMD="JT.EXE /? /PRJ"

Command:

/PRJ [<n>] - print next <n> or today's run times of task

Purpose:

Print next run times of task.

Arguments:

<n> - number of run times to print.  If omitted, print run times from
now till the end of today

Examples:

/prj
- print remaining run times for today

/prq 4
- print next 4 run times

 CMD="JT.EXE /? /PSJ"

Command:

/PSJ [<id>] - print trigger strings of <id> or all in task

Purpose:

Print one or all trigger strings of task.

Arguments:

[<id>] - 0-based index of trigger to print string for.  If omitted,
print all trigger strings.

Examples:

/psj
- print all trigger strings

/psq 4
- print string for trigger 4

 CMD="JT.EXE /? /PTJ"

Command:

/PTJ [<id>] - print trigger props of <id> or all in task

Purpose:

Print the properties of one or all triggers of task.

Arguments:

[<id>] - 0-based index of trigger to print.  If omitted,
print all triggers.

Examples:

/ptj
- print properties of all triggers

 CMD="JT.EXE /? /RJ"

Command:

Purpose:

Examples:

- load mytask.job into the in-memory task object, then run it.

 CMD="JT.EXE /? /SAC"

Command:

Purpose:

object.

If the in-memory object is dirty, it will be saved first.

Arguments:

Examples:

/sac foo.job

/sac bar
in-memory task object.

 CMD="JT.EXE /? /SAJ"

Command:

Purpose:

Arguments:

<file> - filename to save.

Remarks:

This command acts as a Save As operation.  Any changes made to the in-
memory object after this command is executed will automatically be saved
to <file> before JT exits.

The scheduler will return an error if tasks\<file> exists.

Examples:

/saj foo.job
- save the in-memory task object in <tasks folder>\foo.job.

 CMD="JT.EXE /? /SC"

Command:

/SC <new acct> <new pswd> - create/set credentials.

Purpose:

Specify new or change existing task credentials.

Arguments:

<new acct>  - new account name. Mandatory.
<new pswd>  - new password. Specify the string "" for a blank

Remarks:
The password may also specified as NULL if the account name is set.
NULL as a password indicates that the task should be run ONLY if
the specified user is logged on at the time the task is set to
execute.  Users may create tasks of this type only for themselves.
Administrators may create them for any user.

Examples:

- Specify new credentials.

 CMD="JT.EXE /? /SD"

Command:

Purpose:

Arguments:

<file> - filename of task object to delete.

Examples:

/sd foo.job
- delete <tasks folder>\foo.job.

 CMD="JT.EXE /? /SE"

Command:

/SE [<n>] [P] - scheduler enum tasks <n> at a time, [P]rint

Purpose:

the properties of each.

Arguments:

[<n>] - optional value to use for celt in IEnumWorkItems::Next.
[P]   - optional flag to make JT dump properties of enumerated objects.

Remarks:

If the [P] flag is not specified, only the names of the enumerated
objects are displayed.

Examples:

/se
- print the names of all objects in the tasks folder, one per line.

/se p
- print all properties of all objects in the tasks folder

/se 2
- print the names of all objects in the tasks folder, one per line.
use 2 for the celt argument to IEnumWorkItems::Next.

 CMD="JT.EXE /? /SJ"

Command:

/SJ <props> - set task's properties

Purpose:

Change one or more properties on the in-memory task object.

Arguments:

<props> - list of task properties.

Remarks:

The property list has the form <propname> = <value>...

The task properties and the form of their values:

ApplicationName        = <path>
Parameters             = <string>
WorkingDirectory       = <path>
Comment                = <string>
Creator                = <string>
Priority               = { Idle | Normal | High | Realtime }
MaxRunTime             = <int> (in milliseconds)
Idle                   = <int> <int> (wait & deadline, in minutes)
Interactive            = { 1 | 0 }
DontStartIfOnBatteries = { 1 | 0 }
KillIfGoingOnBatteries = { 1 | 0 }
RunOnlyIfLoggedOn      = { 1 | 0 }
SystemRequired         = { 1 | 0 }
DeleteWhenDone         = { 1 | 0 }
Suspend                = { 1 | 0 }
HaltOnError            = { 1 | 0 }
StartOnlyIfIdle        = { 1 | 0 }
KillOnIdleEnd          = { 1 | 0 }
RestartOnIdleResume    = { 1 | 0 }
Hidden                 = { 1 | 0 }

<string> - must be surrounded by double quotes if it contains spaces
<date>   - { m/d/y | TODAY }
<int>    - any integer

Case is not significant (i.e., IDLE and Idle are both legal).

Examples:

/sj command = notepad.exe Priority=idle DeleteWhenDone=1

 CMD="JT.EXE /? /SM"

Command:

/SM [<machine>] - set machine (NULL = local machine if omitted)

Purpose:

Retarget future ITaskScheduler methods at a remote or the local machine.

Arguments:

[<machine>] - machine to target, in the form \\machine-name.

Remarks:

If argument is omitted, command targets local machine.  The argument
may also explicitly target the local machine.  Note that the
machine choice is not persisted across invocations of JT.

Examples:

/sm
- target the local machine.

!sm bogus /gm
- attempt to target a non-existent machine, then print currently
targeted machine (to verify that it hasn't changed).

 CMD="JT.EXE /? /SNJ"

Command:

Purpose:

Arguments:

Remarks:

CAUTION: the in-memory task object is NOT SAVED before being
replaced.  This allows you to test the behavior of the task
object when it is released while dirty.

Examples:

/ctj /snj foo.job
and load it into the in-memory task object without first saving the
existing in-memory object.

 CMD="JT.EXE /? /STJ"

Command:

/STJ [id] <props> - set properties of trigger [id] on task

Purpose:

Change one or more properties of a trigger in the in-memory task
object.

Arguments:

[id]    - trigger number.  If omitted, trigger 0 is modified.
<props> - list of trigger properties.

Remarks:

The property list has the form <propname> = <value>...

The trigger properties and form of their values:

StartDate = <date>
EndDate = <date>
StartTime = <time>
MinutesDuration = n
MinutesInterval = n
HasEndDate = {1|0}
KillAtDuration = {1|0}
Disabled = {1|0}
Type = {Once|Daily|Weekly|MonthlyDate|MonthlyDOW|OnIdle|AtStartup|AtLogon}
TypeArguments = <type-args-list>

<date>           - { m/d/y | TODAY }
<time>           - { h:m | NOW }
<type-args-list> - see below

Note that NOW is actually 60 seconds in the future so it can be used to
create triggers that will fire soon.

The following table lists the forms of the <type-args-list> property
value for each of the trigger types:

Trigger       Argument List        Argument meanings
Type          Format
-----------   ------------         ----------------------------
DAILY         n                    DaysInterval
WEEKLY        n, <DOW>             WeeksInterval, DaysOfTheWeek
MONTHLYDATE   <DOM>, <months>      DaysOfTheMonth, Months
MONTHLYDOW    n, <DOW>, <months>   Week, DaysOfTheWeek, Months
ONCE                               (no args)
ONIDLE                             (no args)
ATSTARTUP                          (no args)
ATLOGON                            (no args)

<DOW> is a string with one letter per weekday.  To specify the task
is to run on every day, use the string UMTWRFA.  To specify no days
use a period.

<DOM> is a comma-separated list of day numbers and ranges.  Some examples:
1-31
10
20,21,22
1,3,5,7-10
2-8,20,12

<months> is a string containing three letter abbreviations for months.
For all months, use: JanFebMarAprMayJunJulAugSepOctNovDec (case and order
are not significant).

The trigger type must be specified before the type arguments, otherwise
properties may appear in any order.  Case, whitespace, and leading zeros
are not significant.

Examples:
/stj enddate=today
- set the end date of trigger 0 on the in-memory task object to today's
date.

 CMD="JT.EXE /? /SVJ"

Command:

/SVJ [<file>] - save task to <file>

Purpose:

Arguments:

<file> - file to save.  If omitted, saves to last file loaded or saved.

Remarks:

Any task object which has an associated filename (because it's
been used with the LJ, SAJ, SNJ, SAC commands) will
automatically be saved, if it has been modified, just before JT exits.

Therefore these save commands are most useful for doing a save as.

Examples:

/sac a.job /svj b.job
it to b.job in the current directory.