Expert Solution for 2011 Scripting Games Advanced Event 1:Use PowerShell to Find Process Module Versions

Avatar

Summary: Guest blogger, Trevor Sullivan, solves 2011 Scripting Games advanced Event 1 and finds process module versions.
Microsoft Scripting Guy, Ed Wilson, here. Today we start two weeks of expert commentators’ solutions for the 2011 Scripting Games. To provide the solution for Advanced Event 1, we have Trevor Sullivan.

Hello, my name is Trevor Sullivan. I have been working on a Windows PowerShell module recently that makes working with Windows Management Instrumentation (WMI) permanent event registrations much easier! The name of this module is PowerEvents—appropriately named to combine Windows PowerShell and WMI eventing. You can download this module free from http://powerevents.codeplex.com, and there is ample documentation in the form of a PDF document, YouTube videos, and the CodePlex.com wiki.

The Advanced Windows PowerShell Event 1 for the 2011 Microsoft Scripting Games, requires that one retrieve file information from a potentially large number of remote systems. Thankfully, this is quite simple to do by using a combination of Windows PowerShell and WMI.
Most of my scripts, whether PowerShell or VBScript, use Windows Management Instrumentation (WMI) to retrieve information about computers or perform actions against them. WMI is particularly useful, because it inherently includes support for accessing information from remote computers, both workstations and servers. Additionally, authentication is handled by using pass-through credentials, which makes writing and executing scripts against it very easy in an Active Directory domain environment. In my script for this challenge, I use the Win32_ProcessExecutable WMI class, in the rootcimv2 WMI namespace, to discover which executable files (libraries, drivers, etc.) have been loaded by a process. This WMI class provides a reference to the CIM_DataFile instance for the executable file in question, which provides detailed file information such as the version, size, path, and so on.
Taking this concept, I wrapped the code inside an advanced function called Get-ExecutableInfo. This reusable function accepts any process name, executable name, and remote computer name from which to retrieve the information.
The other piece to this challenge was to have a list of computers against which to run the code. The Active Directory database is the perfect place to get this information because it theoretically contains a list of all computers on an enterprise network, and it provides for centralized authentication. Windows PowerShell also has type accelerators to make working with Active Directory simple. In this script, I use the [adsisearcher] type accelerator, along with a simple LDAP filter: “(objectClass=computer)”. When the results are retrieved from this query, I iterate over each search result, and call the Get-ExecutableInfo function using the computer’s name, “notepad.exe”, and “winspool.drv” as my parameters for the remote computer, process name, and executable name to get, respectively.
This script demonstrates how easy Windows PowerShell makes working with WMI and Active Directory. WMI is useful for many administrative tasks, including retrieval of file information. Active Directory is the perfect place to get a centralized list of computers in your network environment. I hope that this has been educational for you, and I look forward to writing again.
The complete script is shown here:

function Get-ExecutableInfo {

      [CmdletBinding()]

      param(

            [Parameter(Position=0)]

            [System.String]

            $ComputerName,

            [Parameter(Position=1)]

            [System.String]

            $ProcessName,

            [Parameter(Position=2, Mandatory = $true)]

            [System.String]

            $ExecutableName

      )

 

      process {

            # If computer is not accessible, do not proceed.

            if (-not (Test-Connection $ComputerName -Count 1)) {

                  break

            }

           

            # Find notepad process (just need any one instance)

            $Process = $null;

            $Process = @(Get-WmiObject -ComputerName $ComputerName -Class Win32_Process -Filter “Name = ‘$ProcessName'”)[0];

            #Write-Host $Process.ProcessID

            #Write-Host $ExecutableName

           

            # Get

            if ($Process)

            {

                  # Retrieve list of all executable files that Notepad has loaded

                  $ExecutableList = Get-WmiObject -ComputerName $ComputerName -Query “ASSOCIATORS OF {$($Process.__PATH)} WHERE ResultClass = CIM_DataFile”

                  # Get the first instance of the executable file we are looking for

                  $Executable = @($ExecutableList | ? { $_.Name -like “*$ExecutableName*” })[0]

                  $Output = “`”$($Executable.__SERVER)`”,`”$($Executable.FileName)`”,`”$($Executable.FileSize)`”,`”$($Executable.Name)`”,`”$($Executable.Version)`””

                  Write-Output -InputObject $Output

            }

            else

            {

                  break;

            }

      }

}

 

# Retrieves a list of all computers from Active Directory

function Get-Computers()

{

      ([adsisearcher]”(objectClass=computer)”).FindAll()

}

 

Clear-Host

# This is only an example!

$ComputerList = Get-Computers

foreach ($Computer in $ComputerList)

{

      Get-ExecutableInfo $Computer.properties.dnshostname notepad.exe ‘winspool.drv’

}

Thank you, Trevor, for providing this solution for the Advanced Event 1.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Avatar

Follow    

0 comments

    Leave a comment