Running programs on remote computers is a common administrative task, and there are a number of techniques available to accomplish it. (See the article
"Common Ways to Run Programs on Remote Computers" for a list of some commonly used techniques and their advantages and disadvantages
.) I've come to
rely on the Windows Task Scheduler service because it's a native part of Windows OSs and hence always available under normal circumstances.
In 2005, I wrote a VBScript script, JTRun.vbs, that used the Task Scheduler service to immediately run programs on Windows XP and Windows 2000 (Win2K)
remote computers. As I described in the web-exclusive article "Command-Line Task Scheduler," I used the
Microsoft utility Jt.exe instead of the Schtasks command (which was introduced in XP) as the command-line interface for the Task Scheduler service for
two reasons. First, Jt.exe worked on both XP and Win2K, whereas Schtasks didn't exist on Win2K. Second, Jt.exe had a "run now" feature that Schtasks
lacked. (Jt.exe lets you run programs "now," meaning in the next minute.)
Now that I use Windows PowerShell as my primary command-line shell, I decided to replace JTRun.vbs with a PowerShell script for several reasons:
-
JTRun.vbs requires an administrative password in clear text on the script's command line. PowerShell can use PSCredential objects, which
securely store passwords.
-
JTRun.vbs works with only one computer at a time. PowerShell pipelining makes working with multiple computers relatively easy.
-
JTRun.vbs produces output that isn't designed for parsing. In PowerShell, you can output custom objects with whatever properties are needed.
-
Jt.exe's "run now" feature can be problematic if the local and remote computers' times aren't in sync, or if the local and remote computers are
in different time zones.
After I decided to replace JTRun.vbs with a PowerShell script, my first thought was to use the TaskService scripting object (which was introduced in
Windows Vista and Windows Server 2008) or the Schtasks command instead of Jt.exe. However, I was annoyed to discover that, at least from Windows 7, you
can't connect to remote XP systems using either the TaskService or Schtasks method. As Figure 1 shows, both methods return an Access is denied
error. (The PowerShell window in Figure 1 is running under the Administrator account on the local system, and the same domain account is a member of
Administrators on the remote XP system as well.) However, I found that Jt.exe works just fine on Windows 7, so I decided to stick with it.

Figure 1: Errors encountered when trying to use the TaskService and Schtasks methods to connect to a remote XP system
Although the new PowerShell script, Start-Program.ps1, still uses Jt.exe to create the scheduled task, it doesn't have the old VBScript script's other
problems. Before I show you how to use the new PowerShell script, however, I need to describe the Jt.exe program and how Start-Program.ps1 uses it to
become a general-purpose "run a program on any computer" tool.
Understanding Jt.exe
As I mentioned previously, Jt.exe provides a command-line interface to the Task Scheduler service. You can download this utility fromftp://ftp.microsoft.com/ResKit/win2000/jt.zip. After you extract the Jt.exe file, you need to put it in a directory in your Path. You only need Jt.exe
in the Path on the computer on which you run Start-Program.ps1.
Although the Jt.exe command is powerful and flexible, its syntax is rather complex and not very user-friendly. For that reason, I designed
Start-Program.ps1 to create and run a Jt.exe command that contains the parameters shown in Table 1.
Jt.exe generates output strings that are informative. For example, Figure 2 shows some sample output strings, one of which contains an error message.
However, the output strings make parsing difficult, especially if you need to execute a Jt.exe command for more than one computer. Start-Program.ps1
parses the output strings and manages Jt.exe errors for you, reporting errors when appropriate.

Figure 2: Sample output strings from Jt.exe
Using Start-Program.ps1 to run Jt.exe offers other several advantages as well. First, you don't need to type passwords in clear text on the command
line. Second, Start-Program.ps1 hides the complexities of the Jt.exe command-line parameters shown in Table 1. Third, Start-Program.ps1 can run a
program on multiple computers. Finally, it outputs objects that can be filtered, sorted, and so on.
Using Start-Program.ps1
You can download Start-Program.ps1 by clicking the 141270.zip hotlink at the top of this page. After you
extract the script, you should put it in the same Path as Jt.exe. (Start-Program.ps1 and Jt.exe can be in the same or different directories in the
Path.) The script's command-line syntax is as follows:
Start-Program [-ComputerName] <String[]>
-StartTime <DateTime>
-Program <String>
[-Parameters <String>]
[-WorkingDirectory <String>]
[-KeepTask]
[-TaskCredential <PSCredential>]
[-Verbose]
The -ComputerName parameter specifies the computers on which to run the program. You can omit the -ComputerName parameter name if you put the computer
names first on the command line. You can specify a period (.) or the string localhost to refer to the current computer. This parameter also
supports pipeline input (i.e., if you pipe input to the script, the script assumes the piped input is a list of computer names).
The -StartTime parameter is a DateTime object that specifies when the program should run. You can specify a date, a time, or both. If you specify only
a date, the time will be midnight. If you specify only a time, the date will be the current day. Because the parameter is a DateTime object, you can
specify the date and time in any valid format. Note that for remote computers, this parameter refers to the date and time on the remote computer, not
the computer on which you run the script.