Hey, Scripting Guy! Question

I have a problem. The pointy-headed boss (PHB) loves to play with his laptop. The problem is he does not know anything. He routinely hoses his computer, and then expects me to drop everything and come fix it. I am not making this up; we had an Exchange server crash one time, he knew we were trying to get the thing back up, and he comes into the server room whining about his laptop, expecting me to come look at it. And this is in the middle of an outage! Sorry, I digress. Where was I? Oh, yeah. His latest toy to play with is the services control tool. He thinks he knows better than Microsoft what needs to be running to make Windows Vista work. Now before you say it, I cannot take administrator rights away from him. The PHB insists on being a domain administrator. Is there a way I can easily reconfigure the services after he has screwed up everything?

- SV

SpacerHey, Scripting Guy! Answer

Hi SV,

Don’t you just love it when the PHB makes extra work for you? Consider it a learning experience, an opportunity to grow and to mature in your profession (cough, cough). Interestingly enough, I may have just the thing you are looking for. It is a script that I wrote for myself several years ago, and I used it when I used to fly every week. When I am using my laptop on an airplane, there are a number of services that I really do not need running. If I can easily stop a bunch of services I am not using, I can free up memory and often increase my battery life as well. The trick is to have a file that documents what your desired configuration is, and go through the services to ensure that your computer meets that configuration. In my case, what I did was have a list of services that I wanted to stop, read that file, and then use the Stop-Service cmdlet to perform the configuration change. Here is an example:

Get-Content -Path C:\fso\runningServices.txt | Stop-Service

That’s it. One line of code. It does not even have to be put in a script, if you do not want to do so. The text file is not anything special—it can be simply a list of service names:

Image of the text file of service names

 

If I want to start the services in the text file, I use the same text file and the same syntax. However, instead of using the Stop-Service cmdlet, I use the Start-Service cmdlet. This is seen here:

Get-Content -Path C:\fso\runningServices.txt | Start-Service

To verify that I have not missed any of the services and that none of the services hung on start, I use the Get-Service cmdlet instead of Start-Service or Stop-Service cmdlet:

Get-Content -Path C:\fso\runningServices.txt | Get-Service

Here is an image of the output from the Get-Service command as seen in Windows PowerShell:

Image of the output from the Get-Service command

 

What does this all have to do with the PHB? Perhaps nothing, but then again, perhaps everything. All you need to do is to get a baseline snapshot of the services you want to have running, store them in a text file, and then use the above three commands to manage the PHB. The hard part, it would seem, is creating a text file that lists all the services you want to have running on the computer and then cleaning up that text file. This script will create the text file for you:

Get-Service |
Where-Object {$_.status -eq 'running'} | 
Format-Table name -HideTableHeaders | 
Out-File –FilePath C:\fso\runningServices.txt

This script could be a command that was typed on a single line. In fact, most of the time this is how I use it. The script begins by using Get-Service to obtain a listing of services. It then pipes the result to the Where-Object where the status of each service is checked. If the service is running, the service is passed to Format-Table where the name of the service is chosen and the table headers are hidden. From there, it is passed to Out-File, which creates the text file.

If we were to use the text file directly, it would not work. This is because of blank lines and spaces that keep Get-Service from working. The errors are shown in this image:

Image of the errors returned because of blank lines and spaces in the text file

 

In the past, I used to open the text file in Notepad and manually clean up the file. This is fine, but begins to get old after a while. The answer, of course, is to write a script. The resulting script is seen here:

$serviceFile = "C:\fso\runningServices.txt"
$tempFile = [io.path]::getTempFIleName()
$content = Get-Content -path $serviceFile
$content | 
Foreach-object `
{
  if($_ -notmatch "^$")
    {
      $_.trim() >> $tempFile
    } #end if
} #end foreach

Remove-item $serviceFile
Copy-Item $tempFile $serviceFile

The script begins by assigning the path to the service file to the $serviceFile variable. The runningServices.txt file is the file we created earlier that contains white space and blank lines in it:

$serviceFile = "C:\fso\runningServices.txt"

Now for some cool stuff. The io.path .NET Framework class has the GetTempFileName static method. This will create a temporary file in the temporary directory. This is a great thing to use when you have a task that requires temporary storage. In Windows PowerShell, when you need to use a static method from a .NET Framework class, you put the class in square brackets and use a double-dotted notation. We store the temporary file name and path in the $tempFile variable (for a VBScript example of this technique, see the text files repository):

$tempFile = [io.path]::getTempFileName()

To read the content of a text file, you use the Get-Content cmdlet. We give it the path to the text file we wish to read, and store the results in the $content variable. This is shown here:

$content = Get-Content -path $serviceFile

Now we want to groom our data. We can't have a bunch of hairy strings hanging out in our nice clean text file. The first thing we do is take the content of the text file we stored in the $content variable and pipeline it to the Foreach-Object cmdlet. This will allow us to work with each line in the text file and is similar to using readline in VBScript. There are a couple examples of doing this with VBScript in the text files repository as well. After we have each object, we use a regular expression pattern match that basically says the beginning of the line (^) followed by the end of the line ($)...but hold our horses, we don’t want it to match, so we use notmatch. This gives a line with stuff in it and will remove blank lines. Now we use the trim method from the string class to get rid of blank spaces and the like from the beginning and the end of the line. We send this line to the temporary file by using the redirect and append operator, >>:

$content | 
Foreach-object `
{
  if($_ -notmatch "^$")
    {
      $_.trim() >> $tempFile
    } #end if
} #end foreach

 

The rest of the script deletes the original file by using Remove-Item, and copies the temporary file to the original file location. This is shown here:

 
Remove-Item $serviceFile
Copy-Item $tempFile $serviceFile

 

Well, SV, this should help you to remove at least one dollop of annoyance delivered daily by your pointy-headed boss. Script you tomorrow.

Ed Wilson and Craig Liebendorfer, Scripting Guys