Expert Solution for 2011 Scripting Games Beginner Event 1: Use PowerShell to Determine if a Process Is a Private Build

Avatar

Summary: Microsoft Windows PowerShell MVP, Thomas Lee, solves 2011 Scripting Games beginner event 1 by finding private build processes.
Microsoft Scripting Guy, Ed Wilson, here. Our expert commentator for Beginner Event 1 is Dr. Thomas Lee. Here is Thomas’ scripting autobiography from The Official Scripting Guys Forum! where he is a moderator:

I’ve been scripting pretty much forever. I used to be pretty hot at JCL on the IBM 360 in the late 1960s, and I did a ton of shell scripting in the 70s on ICL VME. I learned batch scripting with DOS 2.0. I never really grokked VBS (and never got infected with *ix). But I truly “got” Monad when I first saw it in September 2003 and never looked back. I’m proficient in Windows PowerShell 1.0 and 2.0, and specialize in the .NET and WMI aspects. My one interesting fact is that I was the first person to blog about Monad. Check out my Under the Stairs blog and my PowerShell Scripts blog.

Worked solution

Like so many Windows PowerShell scripting problems, this challenge breaks down into two parts: first knowing how and where to look to see if some file or process is a private build; then secondly, writing the script in such a way as to be generic, produce the CSV file that is required, etc. This event also throws up the fact that there are often two ways to do things in Windows PowerShell, if not more.
In my case, I really did not know where to look to see if a file was a private build. From the event scenario, I was tempted to look at the processes; but instead, I started by issuing a very simple query to my main search engine: “Microsoft Private Build.” Interestingly, the first reference was to the System.Diagnostics.Fileversioninfo class—in particular, the Privatebuild property. And when I looked further down the page, it even had a sample that actually checked to see whether Notepad was a private build! Armed with this information, it looked like the script would be fairly easy to write. Basically, I had to run something like the following command on each computer, and then look at whether the IsPrivateBuild property was True (indicating that the file is a private build) or False.

[System.Diagnostics.FileVersionInfo]::GetVersionInfo($file)

But then I re-read the event scenario. The scenario asks for computers that are running the file you are interested in. And that means that in the example, Notepad had to be running. In other words, this might have something to do with the processes on the system after all.
As I thought more about the real life problem (The Scripting Games are all about real life problems, right?), it became clear —a server that has a private build file could result in an application compatibility issue when another conflicting application was deployed. It seemed to me that my boss wanted to find whether a server could run this private build as opposed to whether the private build was running!
Of course in real life, as a beginner scripter, I would have a boss to ask for more guidance (after all, he gave me the task to do, right?). But since this solution is for the Scripting Games, I am my boss! So I approved my approach and moved on. Of course, this means that you might come up with an entirely different answer (and still be “right”). Maybe next time, my boss could write the scenario better!
In developing the solution I first decided to write the script as a function that took a parameter ($file) that would represent the file you are looking for. To facilitate handling multiple computers, I added a second parameter, computer, to contain an array of computers you wanted to search for this file on. I also included a couple of calls to the function to check out that it worked.
The body of the script iterates through all the computers and checks to see if the file existed. To do the checking, I decided to use the great remoting feature in Windows PowerShell 2.0 to send a script (query.ps1) to each computer to query if the file existed. I built the query and then copied it to a local file. I also included in this script a call to hostname to get the host’s actual name (as opposed to some other name, such as a CName or a netbios name, where the hostname is different). I return two items from the function: whether the file is a private build and the actual host’s name.
It turns out that this was a little tricky, and I resorted to a little string manipulation to get the query perfect. There are bound to be more elegant solutions to that problem. Here’s my script:

 

<#

.SYNOPSIS

    This script queries remote machines to find out if

    a private build of a file resides there.

.DESCRIPTION

    This script is a worked solution for the Scripting Games.

.NOTES

    File Name  : Get-PrivateBuildInfo.ps1

    Author     : Thomas Lee – tfl@psp.co.uk

    Requires   : PowerShell Version 2.0

.EXAMPLE

    Get-PrivateBuildInfo -file “C:windowsnotepad.exe” -computer “cookham8”

    Process, computer, PrivateBuild

    C:windowsnotepad.exe, Cookham8, False

.EXAMPLE

    get-privatebuildinfo  -file “C:windowsnotepad.exe” -computer “cookham8″,”cookham1”

    Process, computer, PrivateBuild

    C:windowsnotepad.exe, Cookham8, False

    C:windowsnotepad.exe, Cookham1, False

#>

Function Get-PrivateBuildInfo {

Param(

   [string]$file,

   [string[]] $computer

)

# Start of function

# Write header output

“Process, computer, PrivateBuild”

# Specify query and store away

$qs  = “`$filver `= [System.Diagnostics.FileVersionInfo]::GetVersionInfo(`”{0}`”)`n” -f $file

$qs += “hostname;”

$qs += “`$filver”

$qs | Out-File .query.ps1

# Run query on each system

$computer | foreach {

  $result = invoke-command -file .query.ps1 -computername $_

  #output info

  $h   = $result[0]

  $ipb = $result[1].isprivatebuild

  “{0}, {1}, {2}” -f $file, $h, $ipb 

}

}

get-privatebuildinfo  -file “C:windowsnotepad.exe” -computer “cookham8”

get-privatebuildinfo  -file “C:windowsnotepad.exe” -computer

Avatar

Follow    

0 comments

    Leave a comment