Reuse PowerShell Code to Simplify Script Creation

ScriptingGuy1

Summary: The Microsoft Scripting Guys describe how to reuse Windows PowerShell code to simplify script writing and retrieve reliability information.

 

Hey, Scripting Guy! Question Hey, Scripting Guy! I really enjoy reading your stuff. It is generally both fun and informative. The thing I appreciate the most is that your writing does not read like standard product documentation. I am, however, not exactly clear how to use the Test-ReliabilityProvider function you developed yesterday. Can you explain that to me please?

— TE

 

Hey, Scripting Guy! Answer Hello TE,

Microsoft Scripting Guy Ed Wilson here. It has been raining all day down here in Charlotte, North Carolina, in the United States. With the cool temperatures outside (60 degrees Fahrenheit, 15.6 degrees Celsius), it has been an excellent day for drinking tea. Right now, I am sipping a cup of Darjeeling tea and munching on an Anzac biscuit while listening to Bon Jovi on my Zune HD. TE, I can certainly understand your misgivings about using the Test-ReliabilityProvider function, because in Windows PowerShell, functions can act like cmdlets. Things can become muddled.

I stored the Test-ReliabilityProvider function in a .ps1 Windows PowerShell script file, and added a line to the bottom of the file. The line is commented out to keep it from executing if you decide to dot-source the file (something I will talk about in a little bit). The Test-ReliabilityProvider.ps1 script is shown here.

Test-ReliabilityProvider.ps1

Function Test-ReliabilityProvider
{ 
 
<#
  
.Synopsis
   
This function checks for the presence of the WMI Reliability provider
  
.Description
   
This function checks for the presence of the WMI Reliability provider
  
.Example
   
Test-ReliabilityProvider
   
Returns true if reliability exists and is enabled on local computer. 
  
.Example
   
Test-ReliabilityProvider -computer berlin
   
Tests for presence of reliability provider on remote computer named berlin.
   
Returns true if exists and is enabled, false otherwise 
  
.Parameter Computer
   
Name of remote computer to test
  
.Inputs
   
[string]
  
.Outputs
   
[boolean]
  
.Notes
   
NAME:  Test-ReliabilityProvider
   
AUTHOR: ed wilson, msft
   
LASTEDIT: 09/27/2010 13:59:47
   
KEYWORDS: Operating System, Registry, Scripting Techniques, WMI
   
HSG: HSG-10-06-10
  
.Link
    
Http://www.ScriptingGuys.com
 
#Requires -Version 2.0
 
#>
 
[cmdletBinding()]
 
Param ([string]$computer = “.”)
 
$provider =  Get-WmiObject -Class __provider -filter `
“name = ‘ReliabilityMetricsProvider'”
-computername $computer
 
If($provider -ne $null)
  
{
   
Write-Verbose “Reliability Provider found”
   
$hklm = 2147483650
   
$key = “SOFTWARE\Policies\Microsoft\Windows\Reliability Analysis\WMI”
   
$value = “WmiEnable”
   
$wmi = [wmiclass]“\\$computer\root\default:stdRegProv”
   
if( ($wmi.GetDWORDValue($hklm,$key,$value)).uValue -eq 1) 
    
{
     
Write-Verbose “Reliability Provider enabled via Group Policy” 
     
Return $true 
     
}
   
Else 
    
{
      
Write-verbose “Reliability Provider not enabled via Group Policy”
      
Return $false 
     
}
  
}
 
Else 
 
{
  
Write-verbose “Reliability Provider does not exist” 
   
Return $false 
  
}
}  # end function Test-ReliabilityProvider
 
 
# *** Entry Point to script ***

#Test-ReliabilityProvider -computer “.” -verbose

If you simply want to see if the WMI Reliability provider is installed and enabled on your computer, uncomment the last line in the script. The line to uncomment is shown here:

Test-ReliabilityProvider -computer “.” -verbose

When you run the script with the verbose parameter as seen above, the script will return information similar to that shown here:

PS C:\Users\ed.NWTRADERS> C:\data\ScriptingGuys\2010\HSG_10_4_10\Test-ReliabilityProvider.ps1
VERBOSE: Reliability Provider found
VERBOSE: Reliability Provider enabled via Group Policy
True
___________________________________________________________________________________
PS C:\Users\ed.NWTRADERS> C:\data\ScriptingGuys\2010\HSG_10_4_10\Test-ReliabilityProvider.ps1
VERBOSE: Reliability Provider does not exist
False

If the function is called without the –verbose switch, the Test-ReliabilityProvider function returns either true or false.

There are two ways to call the Test-ReliabilityProvider function (actually, there are at least three ways if you include adding it to a module). The first way is to have the function and the calling code in the same file. This is shown in Get-SortedReliabilityRecords_TestProvider_embeded.ps1.

Get-SortedReliabilityRecords_TestProvider_embeded.ps1

Function Test-ReliabilityProvider
{ 
 
<#
  
.Synopsis
   
This function checks for the presence of the WMI Reliability provider
  
.Description
   
This function checks for the presence of the WMI Reliability provider
  
.Example
   
Test-ReliabilityProvider
   
Returns true if reliability exists and is enabled on local computer. 
  
.Example
   
Test-ReliabilityProvider -computer berlin
   
Tests for presence of reliability provider on remote computer named berlin.
   
Returns true if exists and is enabled, false otherwise 
  
.Parameter Computer
   
Name of remote computer to test
  
.Inputs
   
[string]
  
.Outputs
   
[boolean]
  
.Notes
   
NAME:  Test-ReliabilityProvider
   
AUTHOR: ed wilson, msft
   
LASTEDIT: 09/27/2010 13:59:47
   
KEYWORDS: Operating System, Registry, Scripting Techniques, WMI
   
HSG: HSG-10-06-10
  
.Link
    
Http://www.ScriptingGuys.com
 
#Requires -Version 2.0
 
#>
 
[cmdletBinding()]
 
Param ([string]$computer = “.”)
 
$provider =  Get-WmiObject -Class __provider -filter `
“name = ‘ReliabilityMetricsProvider'”
-computername $computer
 
If($provider -ne $null)
  
{
   
Write-Verbose “Reliability Provider found”
   
$hklm = 2147483650
   
$key = “SOFTWARE\Policies\Microsoft\Windows\Reliability Analysis\WMI”
   
$value = “WmiEnable”
   
$wmi = [wmiclass]“\\$computer\root\default:stdRegProv”
   
if( ($wmi.GetDWORDValue($hklm,$key,$value)).uValue -eq 1) 
    
{
     
Write-Verbose “Reliability Provider enabled via Group Policy” 
     
Return $true 
     
}
   
Else 
    
{
      
Write-verbose “Reliability Provider not enabled via Group Policy”
      
Return $false 
     
}
  
}
 
Else 
 
{
  
Write-verbose “Reliability Provider does not exist” 
   
Return $false 
  
}
}  # end function Test-ReliabilityProvider

Function Get-SortedReliabilityRecords
{
 
Param ([string]$computer = “.”)
 
Get-WmiObject -Class win32_reliabilityRecords -ComputerName $computer |
 
Group-Object -Property sourcename, eventidentifier -NoElement |
 
Sort-Object -Descending count |
 
Format-Table -AutoSize -Property count, 
 
@{Label = “Source, EventID”;Expression = {$_.name} }
} #end function Get-SortedReliabilityRecords

# *** Entry Point to Script ***

$computer = “.”
if(Test-ReliabilityProvider -computer $computer)
  
{ Get-SortedReliabilityRecords -computer $computer }
else 
 
{ write-host -ForegroundColor red `
    “WMI Reliability Provider either does not exist
    or is not enabled via Group Policy”
}

The function I am interested in running is the Get-SortedReliabilityRecords function that will display an output such as that shown in the following image.

Image of output from Get-SortedReliabilityRecords function

To ensure that the script does not fail abnormally, the Test-ReliabilityProvider function is called. If the Test-ReliabilityProvider function returns $true, the Get-SortedReliabilityRecords function is called. If it does not return true, a message is displayed on the Windows PowerShell console. This portion of the code is shown here:

# *** Entry Point to Script ***

$computer = “.”
if(Test-ReliabilityProvider -computer $computer)
  
{ Get-SortedReliabilityRecords -computer $computer }
else 
 
{ write-host -ForegroundColor red `
    “WMI Reliability Provider either does not exist
    or is not enabled via Group Policy”
}

The advantage of this approach is that the script is completely self-contained. There are no external dependencies that need to be tracked. The disadvantage is that the script is more than 80 lines long. For some scripters, this becomes an issue; for others, the advantage of portability overrides the three seconds it took to copy and paste the function from the Test-ReliabilityProvider.ps1 script into the Get-SortedReliabilityRecords_TestProvider_embeded.ps1 script.

By dot-sourcing the Test-ReliabilityProvider function from the Test-ReliabilityProvider.ps1 script, the function is made available in the Get-SortedReliabilityRecords_TestProvider_DotSource.ps1 script without the need to copy 80 lines of code into the new script. The only requirement to be able to dot-source the function from the script is access to the Windows PowerShell script file. In this example, the source file is stored in folder c:\fso, as shown in the following image.

Image of source file stored in folder c:\fso

The code required to dot-source the script is a period, a space, and the path to the file. This is shown here:

. C:\fso\Test-ReliabilityProvider.ps1

The remainder of the entry point to the script is exactly the same as with the embedded function. The complete Get-SortedReliabilityRecords_TestProvider_DotSource.ps1 script is shown here.

Get-SortedReliabilityRecords_TestProvider_DotSource.ps1

Function Get-SortedReliabilityRecords
{
 
Param ([string]$computer = “.”)
 
Get-WmiObject -Class win32_reliabilityRecords -ComputerName $computer |
 
Group-Object -Property sourcename, eventidentifier -NoElement |
 
Sort-Object -Descending count |
 
Format-Table -AutoSize -Property count, 
 
@{Label = “Source, EventID”;Expression = {$_.name} }
} #end function Get-SortedReliabilityRecords

# *** Entry Point to Script ***

. C:\fso\Test-ReliabilityProvider.ps1

$computer = “.”
if(Test-ReliabilityProvider -computer $computer)
  
{ Get-SortedReliabilityRecords -computer $computer }
else 
 
{ write-host -ForegroundColor red `
    “WMI Reliability Provider either does not exist
    or is not enabled via Group Policy”
}

Of course, if you can dot-source one function, you can dot-source two functions. When dot-sourcing functions in a script, you may wish to check to see if the file actually exists prior to attempting to call the code. To do this, use the Test-Path cmdlet. If the file exists, you go ahead and include the function in your script by dot-sourcing it. If the file does not exist, the script should exit gracefully while displaying a useful message. This approach is illustrated in the DotSourceReliabilityProviderAndSortRecords.ps1 script shown here.

DotSourceReliabilityProviderAndSortRecords.ps1

$TestReliabilityProvider = “C:\fso\Test-ReliabilityProvider.ps1”
$SortedReliabilityRecord = “C:\fso\Get-SortedReliabilityRecords_Function.ps1”
If(test-path -path $TestReliabilityProvider)
 
{ . $TestReliabilityProvider}
Else { “$TestReliabilityProvider not found” ; exit }

If(Test-Path -Path $SortedReliabilityRecord)
 
{ . $SortedReliabilityRecord }
else {“$SortedReliabilityRecord not found” ; exit }

$computer = “.”
if(Test-ReliabilityProvider -computer $computer)
  
{ Get-SortedReliabilityRecords -computer $computer }
else 
 
{ write-host -ForegroundColor red `
    “WMI Reliability Provider either does not exist
    or is not enabled via Group Policy”
}

It would actually be simpler to place the two functions inside a module and install the module than to do all the path testing and exiting. For more information about creating and installing modules, see the Hey, Scripting Guy! Getting Started with Modules series of posts.

 

TE, that is all there is to using Windows PowerShell and the WMI reliability classes. Join us tomorrow as we conclude Reliability Week when we talk about parsing reliability output.

We invite you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

0 comments

Discussion is closed.

Feedback usabilla icon