Service or Schedule Task
I run a lot of scripts as scheduled tasks on servers for system administration for checking disk space or running processes, but in some instances it’s not as efficient as I would like. I want some scripts to run constantly, or run under the computers system account, and using task scheduler does not warn you if the scheduled task failed to run. One scenario that I run into a lot is using an account that changes passwords every so often, then I forget to change it on a server and the task goes unnoticed. Sometimes, the tasks would simply quit running, but, if it were a service, then you have some interesting options available to you. Some, similar to running it as a scheduled task, but others like the “Recovery” tab in a services properties where you can set the service to restart itself, if it had stopped, or run a program, like another script to let you know that the service has stopped and you’d better do something about it! Plus, it has three chances to do all these recovery options if the service does stop.
I know you can use “Schtasks” and scripts to manage Scheduled Tasks, and I’ve tried them, but it is somewhat limited. With “Schtasks” you have to use Wscript.Shell or Exec to run the executable and then capture its output and display it, which works, but can be somewhat difficult to get results the way you want it. The script for managing scheduled tasks only works if the task was created using Win32_ScheduledJob class or the At.exe utility. Now I’m not saying move all your scheduled tasks to services, I’m just trying to point out the benefits of running certain scripts as a service. You need the right tools for the job. I use both, Scheduled tasks and services to run my scripts to complement each other.
As an example, we needed to move files that were saved into a local folder moved to a network share automatically. Figure 7 show the script I used to run as the service. It is a pretty simple script that uses the “scripting.filesystemobject” to move any file that exists in the C:\TempImages folder and moves them to the network share. Now this example is very plain, meaning that is has very little error handling involved and no reporting. If a file with the same name existed in the destination then the script would not be able to move the file. If you wanted to make this example more robust you could add code to deal with these situations as well as a reporting feature like recording the errors or file moves that the script did perform. Then you could see the progress of the script running as the service and see just what the script has done or is doing.
Taking several snippets of scripts I found from various scripting web sites I put together and made an HTA that can make the job of installing a script as a service easy in case I needed it again. Thinking that script would be used by other analyst in the company I wanted to make as straight forward as possible, have some error checking, and have the script able to get the files required to make the service run, like Srvany.exe. I chose to make it an HTA because I like the windows look and feel to them. I think it makes using the scripts a bit easier because all the information you need to input is right in front of you, so you’re not waiting for Input Boxes or any other dialog boxes that lead you step by step thru the script. With an HTA if you fill out a text box wrong, you can just go back to it, providing you did not click the execute button! Also with HTA’s you can place helpful text where you want it, and it’s all basic HTML stuff that you can find plenty of help on the web if you need it.
The script when run (see Figure 1) has text boxes that ask the user what computer to install the service on, what the service is to be called and the location of the script is that is to be run as the service, and the optional alternate credentials. One thing that is very important to keep in mind is that the script you intend to use as the service must run totally unattended, otherwise the script may run, but, let’s say you left a Wscript.echo statement in the script somewhere. If the script were to run with the Wscript.exe engine then it would prompt you when it got to that specific line and wait for you to click the OK button before it continued. But you would not necessarily see the prompt if the service was running under a different account than the one you were currently log in on. Just be aware of the Msgbox, Wscript.Shell popup and Wscript.echo statements. If you would like to leave the echo statement in the script for testing later on down the road you can place “Wscript.interactive = False” at the beginning of the script to disable all prompts instead of going thru the script and remarking them. You could avoid this by running the script in Cscript.exe but you run the risk of having a command window pop up if certain service parameters are set.
Getting the required files
When the “Install Service” button is clicked, the script calls the “getfile”sub routine (shown in Figure 2) which searches for the Srvany.exe and the script file in the Admin$\system32 folder on the target computer. If the files are not found, it uses the Microsoft.XMLHTTP object or the scripting.filesystemobject to download or copy the file and place it in the Admin$\system32 folder as seen in the code in figure 2. Because it uses the Microsoft.XMLHTTP object it can download files from FTP site vs. just a network share. I won’t go into much detail with the Microsoft.XMLHTTP or the adodb.stream objects here because they can be an article all to them self’s. But I’ll give a brief description of how I am using them. The HttpRequest object (Microsoft.XMLHTTP) can be used in a script to send an HTTP request to a URL, receive the response, and have that response parsed by the Microsoft XML Document Object Model. In this case I direct the HTTP request to a file on an FTP site then take the response from the request an pass it to the “adodb.stream” which in turn writes it to a binary file on the client. You may have seen the “adodb” (ADO) reference before if you write scripts to access data sources like Access or SQL. The ADO Stream Object is used to read, write, and manage a stream of binary data or text. The company I work for has an FTP site that all the analysts have access to, so I placed a copy of the Srvany.exe file there for the script to retrieve when run.
If the script does not find the Srvany.exe there will be another text box that appears on the main interface asking for a location of the Srvany.exe file so that it can copy it to the source destination, the script uses the “instr()” function by simply searching for “ftp” in the string entered in the text box to determine whether not to use the Microsoft.XMLHTTP object or just use scripting.filesystemobject to copy the file (as seen in callout A in Figure 2).
There is also a continue button on the page to have the script continue after a location for the file is entered. The text box and button is added to the document body of the HTA with a SPAN tag “<span id=DataArea></span>”, then it populates the SPAN with this line in the script “DataArea.innerhtml = <input name=’Srvanyfile’ size=’20’>” for the text box.
You’ll notice a “Browse” button next to the text box where you enter the name and path of the script, this lets you browse for the file just like most windows programs do. This uses the “UserAccounts.CommonDialog” object as shown in callout A in Figure 3 and although using this object limits the use of this script to only Windows XP operation systems, if you enter a network share path or a local path then it will not use this object and the script will work on Windows 2000 professional and server. For more information on the “UserAccounts.CommonDialog” take a look at one of the MS scripting guys scripts here http://www.microsoft.com/technet/scriptcenter/resources/qanda/jan05/hey0128.mspx.
The script opens a new IE window to display progress as the standard methods like Msgbox, and Wscript.shell popup pause a script during execution, and Wscript.echo does not work in an HTA because it is an intrinsic object to the Wscript.exe and Cscript.exe engines, and HTA’s use Mshta.exe for execution. Using another IE window for the message leaves the script able to continue to execute and report progress the entire time the script is running. If I tried to display the messages in the HTA document body itself the script would seem to “Hang” while it was busy running and you would not see any progress, but you would see all the messages when the script was complete, unless an error occurred to halt execution early.
The script uses WMI to connect to the target computer to get and set information required for the service to function correctly. You can specify alternate credentials for the remote connections if needed, as you need administrative privileges on the remote computer to create the service and make registry edits. If you are already an administrator on the remote computer then you can leave these text boxes blank. First the script needs to find the %systemroot% folder on the target by using the “Win32_OperatingSystem” and gets the “SystemDirectory” property. With this the script can copy files needed to the correct location and write the correct location to the registry to let the service know where to find the files. If the script cannot copy the files it will attempt to map a network drive (Z: to Admin$\system32) using the alternate credentials provided and try to copy the files, and the script will exit if the files cannot be copied.
Creating the service
The script then connects to the “Win32_BaseService” (shown in Callout A in Figure 5) to create the service and set some service properties. The “Win32_BaseService” accepts several parameters and this script sets several of those. Look here for the complete list of options using the “Win32_BaseService” create method http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/create_method_in_class_win32_baseservice.asp . I set first parameter “name” which is the name of the service and in my case is the variable “Service”. The script retrieved this value from the text box Servicename.Value. This is also used as the second parameter of the service “display name”. The third parameter is the “path” parameter which is a fully-qualified path to the executable file that implements the service. The third parameter is the “Own Process’ which means the script will run in its own process. I set this as a constant so I can look at the code and remember what that parameter is instead of the value of “16” for which it stands for. The forth parameter is NORMAL_ERROR_CONTROL which sets the error control of the service if it fails to start when the computer is restarted. Again I’ve set this as a constant so I can tell what the setting is instead of the number “2”. The fifth parameter I have set is the services startup type which I’ve set to Automatic so that it starts up when the computer is restarted. The last parameter I made is the “NOT_INTERACTIVE” which is also a constant, so that the service does not interact with the desktop. For more information on how to create a user-Defined Service using Srvany.exe see this link http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q137/8/90.asp&NoWebContent=1
Service Registry Settings
Without some registry edits the service is not yet ready to start. So the script connects to the “winmgmts: \root\default:StdRegProv” to make the necessary changes (see callout A in Figure 6). The registry keys for services are located “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\your service name”. The script needs to add a “Parameters” key to the service just installed and it also needs to create a string key named “Application” with a value of the path to Wscript.exe which is the script execution engine, and the path to the script that Srvyany.exe runs as the service (See callout B in Figure 6). Callout C in figure 6 shows the description of the service being set in the registry. This is a nice addition to let you anyone else who looks at the services applet in the control panel to let then know what the service is.With Srvany.exe and these created registry keys you can run applications or other types of scripts like Perl or Jscript.
After the registry changes are created on the target computer the service is ready to be started, so the script connects to the “Win32_Service” to start the service!
Every time the script makes a connection to the target computer there is some error control that happens, as seen in Figure 4. If there is an error the script stops execution and reports the error by calling the sub routine and passing two arguments to it to display in the progress window. If the script execution is past the point when the service has already been created on the target then the script will prompt you to ask if you want to remove the service off the target computer as it will not function without manual editing of the remote registry for service parameters.
The script has a built in help document with a help link on the interface that can be seen in Figure 1. Instead of opening an internet address like a normal link, this link has an “onclick” event associated that runs a sub routine called “Helpdoc” that opens an IE window and writes to the body of the window explaining the script and how to use it.
Another thing to remember when making a script a service is if you make changes to the script you will have to restart the service for the changes to become effective.
If you ever want to remove the service, the script center here http://www.microsoft.com/technet/scriptcenter/default.mspx has a script to remove the service locally or remotely. If you browse thru the script center you’ll find a lot of helpful scripts that you can change to fit you needs like I’ve done here. I didn’t invent the wheel, I just put some playing cards in the spokes!