This post may seem a little backward to some, given the newer alternatives such as Powershell or even vbscript, but the past couple of weeks have seen me playing a with script that has turned out to be pretty useful and I figured I would share.
The origins of this story then, I have a small customer who runs SBS 2003 premium in the office. Occasionally they would give me a call and complain that they couldn’t access the internet and that the server was offline. They would then look at the console and it would be alive and they would be able to login without issue. I would get them to have a look at the services and they would report that the firewall service was not running. They would then start it manually, then it would run like a champ and they would be happy.
The logs weren’t showing any major errors and the fact that once the service was started it all ran fine, we went with the easy option of creating a script that would check to see if the service was running, and if it wasn’t then to start it up.
Like any scripting solution, this could have been done a number of ways. The simplest being to create a script that starts the service irrespective of its current state and then schedule to run at regular intervals. To do this, you would open notepad, then type in the following
net start fwsrv
save that as a file named fw.cmd then schedule it using the AT.EXE command to run once at 11pm day by using this command
at 23:00 /every:M,T,W,Th,F "c:fw.cmd"
As a solution, this works, but it could be described as being a little base in its approach. It works well for a single service, but if the service is already running, then there is not much point in trying to start it again. So what if we could check the status of the service, and then if it is running, we’ll leave it be, but if its not, then we can start it? The first thing we need to do then is check the state of the current service, and as we’re trying to script this, opening the services console is not an option, we need something that will work from a command prompt and give us an output. This is where SC.EXE helps (that link is for the Windows Server 2008 version of the tool, so if you are using an earlier OS, be aware that the tool has evolved so check the help for the OS you are on).
To query the status of the firewall service, you run the command
sc query fwsrv
The problem with the output of this command is that the data we’re interested in, is on the 3rd line down, so we need a way to isolate that line so we can process it. For this we can use the FINDSTR.EXE command. In this instance, we need to find something unique on the line so we can query for it. In this example I used STATE. So the next command we need is
findstr /i "state"
The /i switch is used to ignore the case of the word we are looking for. I could have searched for “STATE” and not used the /i switch, it is just a habit that I have gotten into.
The next step then is to make a decision based on the state of the service. To do this, I use the FOR.EXE command. If you have a look at the link, it can be a little daunting and it may not be immediately obvious as to how it is useful in this situation as the primary examples look at stepping through a file, so I’ll save time and show you the command and its output.
for /f "tokens=3" %i in ('sc query FWSRV ^|findstr "STATE"') do echo %i
The entry as displayed executes a command (‘sc query FWSRV ^|findstr "STATE"’) then looks for the third object in the output /f "tokens=3" and then assigns it as a variable named %i. In the example I have then used the ECHO command to see the value.
It is worth noting a couple of points regarding the format of the SC command within the brackets (‘sc query FWSRV ^|findstr "STATE"’).
- The entire string needs to be placed within single quotes. If you don’t you’ll receive an error stating that “The system cannot find the file sc.”
- The caret ^ is required before the pipe | or you will receive an error stating that “| was unexpected at this time.”
This now gives us a way of getting the numerical value of the current state of the service. Having a value for the service means that we can then use an IF statement to make a decision on whether or not to start the service. From the output of the SC query above, we can see that a value of 4 means that the service is running (here is a link to a list of the seven possible values). What we need though is a way to pass the numerical value of the service state to the IF command, and for this, we can use an environment variable. The command then now looks like this
for /f "tokens=3" %i in ('sc query FWSRV ^|findstr "STATE"') do set FW=%i
Putting all the pieces together then we end up with a script that looks like this.
:Query
for /f "tokens=3" %%i in ('sc query FWSRV ^|findstr "STATE"') do set FW=%%i
if (%FW%) EQU (4) goto :END else goto :start
:start
net start fwsrv
goto :query
:end
As you can see, there are couple of formatting tweaks that are required to use the commands within a batch file.
- I added a couple of labels (:Query :start :end) to the script to support the use of the GOTO command. The logic behind this is to provide a means to confirm that the service has started successfully and then to provide a means to jump out of the script.
- The use of the double percantage (%%) is required when using a % within a script.
With the script complete, the next step then is set it up as a schedule task. I could use the AT command I showed you above, but in this instance I decided I would kick off the script once every two hours, so for this I used the scheduled tasks command line tool SCHTASKS.EXE. The reason for using SCHTASKS.exe is that it offers more flexibility than AT.exe.
schtasks /create /SC HOURLY /MO 2 /TN CHECKFW /TR c:scriptsfwqry.cmd /ST 12:00
In this example, I saved the script as a file named c:scriptsfwqry.cmd and scheduled it to run once every 2 hours.
And that is it. A script which will check once every two hours to see if a single service is running, and if its not, send a start command to the service.
But what if there is more than one service? This provides a great example of how you can take an existing script and with a little work, rework it for a new task.
For this scenario, I had a virtual machine setup that was running Office Communications Server 2007 R2 for a lab environment. The vm in question was running as a standard edition server, and as such, had about 10 individual services that needed to be running in order for the server to operate correctly. In this instance, all the services have a prefix of RTC so this time the SC command is a little different
sc query state= inactive |findstr /i "RTC"
The command this time looks for all services that have a state of inactive (ie not running) and then we parse the output looking for the names of the services that start with RTC (e.g. RTCSRV).
When this is then rolled into the script, it looks like this
:Query
for /f "tokens=2" %%i in ('sc query state^= inactive ^|findstr /i "RTC"') do set SVC=%%i
Echo %FW%
if (%SVC%) == () goto :END else goto :start
:start
net start %FW%
SET FW=
goto query
:end
Like before, we need to modify the formatting to get it to work within a batch file
- percent symbols (%%) need to be doubled
- equal (=) and pipe (|) symbols need a caret (^) as a prefix so they are handled correctly.
The next step then is to check that a value has been set for the SVC environment variable. If it is empty, then we know there are no stopped services with a prefix of RTC and we end the script, if it has a value we then send a start command to the service, reset the environment variable, and then re-run the query to look for stopped services with RTC as a prefix.
So there you have it, a couple of basic scripts that can be used to manage scripts within your environment.