July 21, 2005

XYNTService open source admin tool for Windows

Author: Christian Gross

Running a background process on the Windows platform requires running a Windows Service. To run a Windows Service, you must have an application that is Windows Service aware. A Bash script is not Windows Service aware and neither are many console applications. Converting those applications into a Windows Service is not feasible. Without any additional applications, it's complicated to run a console application as a service. Microsoft distributes with its Resource Toolkit an application that converts a console program into a Windows Service. Unfortunately, the Resource Toolkit is not available free. A solution that is free, however, is the XYNTService open source application, which allows an administrator to define a console program and its options to execute. The XYNTService application is a Windows Service that reads a configuration file to know which applications to run.

This article is excerpted from the newly published book "Open Source For Windows Administrators."

You can download the application XYNTService from the Code Project Web site. (Code Project requires a user registration to download the sources and application.) The downloaded and expanded archive contains a small executable called XYNTService.exe. Copy this executable to a directory that will serve as your XYNTService application directory and execute the command XYNTService.exe -i to install the service. The command XYNTService.exe –u removes the service.

When installing the XYNTService application as a Windows service, be sure to run the service in the context of a specific user. Some console applications might need to read user environment variables or files and the local system account does not have those attributes.

On starting XYNTService, the application searches the initial execution directory for the file XYNTService.ini. An example configuration file is as follows:

[Settings]
ServiceName = XYNTService
ProcCount = 2
CheckProcess = 30
[Process0]
CommandLine = c:\bin\unison.exe -socket 8118
WorkingDir = c:\
PauseStart = 1000
PauseEnd = 1000
UserInterface = No
Restart = Yes
[Process1]
CommandLine = C:\j2sdk1.4.1_05\bin\java.exe -ms1m -cp . scache
WorkingDir = c:\bin\scache
PauseStart = 1000
PauseEnd = 1000
UserInterface = No
Restart = Yes

In the example configuration file there are two main section types: Settings and the other sections (Process0 and Process1). The Settings sections contain all the main global definitions related to the XYNTService application. The other sections define the individual processes that will be started when the XYNTService starts. The individual keys of the Settings section are defined as follows:

ServiceName: Sets the service name of the XYNTService. Modifying this value allows an administrator to install multiple XYNTService instances.

ProcCount: Specifies the number of processes that will be started. The main reason this key exists is for the XYNTService application. It uses the value as a maximum value when iterating all the ProcessX sections. In the example configuration, the value is 2, which means that Process0 and Process1 sections must exist.

CheckProcess: This value specifies how often XYNTService should check to see if the processes started are still alive. If the value is 0, then no checking is done; otherwise, the process is restarted. When this value is active, if the started process has died, it will be restarted if the Restart property of the ProcessX section allows it. Be careful with this property because an incorrectly configured process could be constantly dying and restarting, potentially causing the computer to become inoperable.

For each process, there is a Process[n] section, which from the example
configuration file means Process0 and Process1. Each Process section has the following key definitions:

CommandLine: Defines the command line that is executed to start the process. Use full paths.

WorkingDir: Defines the working directory of the process that is started.

PauseStart: Specifies the number of milliseconds to wait before the process is considered initialized. Internally within XYNTService, all that occurs is a sleep for
the length of time specified by the value.

PauseEnd: Specifies the number of milliseconds to wait before a process is forcibly terminated. When the XYNTService shuts down, it sends a quit message to the process and the value of PauseEnd causes XYNTService to wait. After the waiting period is done, the process is forcibly shut down.

UserInterface: Specifies whether the XYNTService can interact with the desktop, which only works with the Local System account. Note that there is no My Documents directory when using the Local System account, which could be problematic with some console applications that expect one.

Restart: Specifies whether the process should be restarted if the process dies.

Restarting the processes

You may run into problems when running scripts in the context of XYNTService. For example, imagine a script that runs another process and waits for the process to end. When XYNTService shuts down, it sends a WM_QUIT message. The Cygwin
Bash shell does not trap the WM_QUIT message, so the shell will be killed in a hard fashion. When the XYNTService restarts, old processes will already exist. The problem of not trapping the WM_QUIT message is not isolated to the Bash shell; Windows batch processes have the same problem.

The solution is to modify the script to kill off any of the old processes before starting new ones. The following script shows how to find old processes and then kill
them using PSTools:

#!/bin/bash
pslist | grep $procIdentifier | awk '{print $2}' > /tmp/pids.txt
exec 3<&0
exec < /tmp/pids.txt
while read line
do
  pskill $line
done
exec <&3
exec 3<&-
rm /tmp/pids.txt

The script makes a listing of all running processes using the command pslist. It searches that result set using grep for the process ID as identified by the variable $procIdentifier. The grep results are then fed into awk to retrieve the process IDs, which are saved in the file pids.txt, which is then loaded and iterated. Each iteration contains the process ID of a found process that needs to be killed using the command pskill. Finally, the file pids.txt is deleted.

The script code is a sure way to kill off the old processes. You can also use kill to send a specific signal. Note that the key PauseStart should include the time taken to kill off already existing processes.

Restarting services and XYNTService

The executable XYNTService is not just a Windows Service executable, but also a control application that can locally start and stop services and restart specific XYNTService services. To restart the second ProcessX section shown in the example configuration file, use the command:

XYNTService.exe -b 2

You can stop a service named Apache with the command:

XYNTService -k Apache

and you can run a service named Apache with the command:

XYNTService -r Apache

Click Here!