We had a Risk and Health Assessment Program (RAP) for SQL Server running in our environment in the last few days and one of the issues in the final report was:
My PowerShell "wheels" started to roll and I suggested our team have a script to check for such inconsistences. So, here's how we can perform a quick check against a two node cluster (or any other pair of computers) using PowerShell and find if the installed hotfixes are not identical.
First we use the Get-HotFix cmdlet to retrieve the list of hot-fix installed on each cluster node and then we use the Compare-Object cmdlet to compare the collections based on the HotFixID property. No result means the two nodes have the same set of hot-fixes installed and no action needs to be performed.
PS > $node1 = Get-HotFix -ComputerName ClusterNode1
PS > $node2 = Get-HotFix -ComputerName ClusterNode2
PS > Compare-Object -ReferenceObject $node1 -DifferenceObject $node2 -Property HotFixID
The output shows just one hotfix. We can see that the SideIndicator value ('=>') shows that the KB967752 hotfix is installed on ClusterNode2 (DifferenceObject) and that it is missing from ClusterNode1.
In the last few days I was working with Artur Zurawicz (this guy rocks!), Microsoft OpsMgr PFE, on our OpsMgr server. We had a discussion regarding PowerShell and while we were working with the shell I executed the Get-PSSnapin cmdlet and was very intrigued by the output:
For quite some time I have been searching for PowerShell cmdlets for HP blades and couldn't find one , and there it was, right here under my nose! I knew we had the HP BladeSystem Management pack installed but never knew it uses PowerShell scripts to monitor the health of blade enclosures. I searched the web for the snap-in name and found this document (PDF).
Feeling lucky, as if I have just found Ali Baba's secret treasure, I quickly executed another command to list the cmdlets of the HewlettPackard.Servers.BladeSystem.HPBladeSystemEnclosureCmdLets snap-in:
How do I install the cmdlets on my machine? I don't want to connect to my OpsMgr server to use the cmdlets. I decided to install the HP BladeSystem Management Pack on my admin machine (Windows 7 x64) and see how it goes. I grabbed the installation files from our server and ran the setup file. After installing the package locally I was able to use the cmdlets. Here's a detailed step by step procedure to install the package on Windows 7.
The HP BladeSystem Management Pack kit can be downloaded from the HP Web site (15.7 MB, needs registration). Download the file and extract it. The folder contains the following files:
Note: The HP BladeSystem Management Pack used in this post is version 1.4 (2010). At work we use a "newer" version (1.6 October 2009), I'm not sure why the "new" version is older than the current one that HP provides, I also couldn't find a download link either. Anyway, the procedure described below is the same for both versions.
Run the setup file (as administrator, I used the HPBladeSystemMP01_40(x64).exe version)
The installer detected that the local machine is not an OpsMgr server and removed the Managament Pack from the installation. Additional components include documentation, the enclosure monitor service and the enclosure monitor manager. The Monitor Service runs on the system to monitor HP BladeSystem c-Class enclosures. The Monitor Service also requires the SNMP Trap service as the monitoring service (HPBladeSystemEnclosureMonitorService) depends on it.
At this stage all selected components are installed and we need to register the enclosures we want to monitor. Click 'Finish' to launch the HP BladeSystem monitor manager.
Click the 'localhost monitor service' node and then click the 'Add' button
Click 'Next' to add BladeSystem enclosures that you want to manage. Only blade systems from the enclosures you add will be available. Fill in the Name/IP and the credentials of the enclosure and then click 'Apply'.
If you have more than one enclosure to add, click 'Add Another'. This will save the credentials you used previously and you'll only need to fill in the new enclosure Name/IP.
When done, click 'Next' for all other screens and then click 'Finish'. It can take some time for the configuration to update and show on screen. If this takes to long, click the 'Refresh' button.
You can view the enclosure's details by clicking on the respective node. You can now close the 'HP BladeSystem Enclosure Monitor Manager' interface and proceed to the fun part with PowerShell. Before we do that restart the HPBladeSystemEnclosureMonitorService service to ensure all configurations are in place.
PS > Restart-Service HPBladeSystemEnclosureMonitorService
If you need to make configuration changes, open the 'HP BladeSystem Enclosure Monitor Manager' as an administrator, otherwise you'll get an error ('Error connecting to localhost.Requested registry access is not allowed'). The Enclosure Monitor Manager can be launched from the command line (bypasses the Connect dialog):
PS > & 'D:\Program Files\HP BladeSystem Management Pack for Operations Manager 2007\Tools\HPBladeSystemEnclosureMonitorManager.exe' localhost
Open PowerShell, load the HP BladeSystem snap-in and execute the Get-Blade cmdlet, the following example grabs the first blade object:
Take some time to explore all other cmdlets. Hopefully HP will take it one step further and release a separate PowerShell package aimed towards admins. There's a lot to improve in the current snap-in. Most of the cmdlets use the Get verb (which are great to produce reports about your blades and enclosures) but some do not conform to the verb naming rules and uses unapproved verbs, such as: Acquire,Apply and Release (more information about verb naming can be found HERE and HERE). We can also use the Get-Verb function to retrieve the list of approved verbs.
That said, it's a start, HP made the move towards PowerShell and that's a good thing. Thumbs up!
Lastly, here is a great a tip I got from Artur. The HP HewlettPackard management pack is a sealed pack and therefore we cannot export it using the OpsMgr console directly. However, we can do that using the OpsMgr PowerShell cmdlets. The example below reveals the scripts used by the management pack. At run time these scripts are saved to the OpsMgr agent folder cache and executed from there. The following example shows the code used in one of the scripts.
The commands in the example was executed on the OpsMgr server which has the 1.6 management pack so the structure of the xml file may vary.
PS > Get-ManagementPack -Name HewlettPackard.Servers.BladeSystem | Export-ManagementPack -Path C:\
PS > [xml]$xml = Get-Content C:\HewlettPackard.Servers.BladeSystem.xml
$xml.ManagementPack.TypeDefinitions.ModuleTypes.DataSourceModuleType.ModuleImplementation.Composite.MemberModules.DataSource.Files.File | Format-List *
In PowerShell, when you enclose a string that contains variables (preceded by a dollar sign) in double quotation marks, the variables are replaced with the variable's value. For example:
PS > $i = 5
PS > "The value of $i is $i."
The value of 5 is 5.
When the string is enclosed a string in single-quotation marks, the string is passed as is, no substitution is performed.
PS > 'The value of $i is $i.'
The value of $i is $i
What if we want to expand single quoted strings? PowerShell maintains a predefined set of variables called Automatic Variables. Each time you launch PowerShell these variables are created. One of the variables is $ExecutionContext. $ExecutionContext is added by the PowerShell engine and it provides access to the command, provider, host, event manager, and session-state information for the current instance of the Windows PowerShell runtime.
One of the $ExecutionContext members is InvokeCommand. It provides access to the command methods that can be used to expand strings, invoke scripts, and create new script blocks. $ExecutionContext.InvokeCommand has a method called ExpandString(). This method expands a specified string but in addition to double quoted strings, it can also be used to expand strings enclosed in single quotes.
PS > $a,$b,$c = 1,2,3
PS > $string = 'a=$a b=$b c=$c'
PS > $ExecutionContext.InvokeCommand.ExpandString($string)
a=1 b=2 c=3
With regard to Environment variables, they can be accessed through the Env: drive or be referenced as $env:VARIABLENAME. PowerShell expands the latter when it's embedded in a double quoted string.
PS > "The windows directory path is: $env:WINDIR"
The windows directory path is: C:\Windows
But if you have a string that contains an environment variable in the form of an MS-DOS variable (quoted with the percent sign character '%') then ExpandString returns the value as is, no substitution occur.
PS > $ExecutionContext.InvokeCommand.ExpandString("%USERNAME%\%USERDOMAIN%")
To expand it we need to use the the [System.Environment]::ExpandEnvironmentVariables static method:
PS > [System.Environment]::ExpandEnvironmentVariables("%USERNAME%\%USERDOMAIN%")
Warning: String expansion can be also performed using the Invoke-Expression cmdlet BUT before you decide to use it you need to make sure that the code you invoke does not contain malicious expressions.
So, instead of running the above commands manually I put together the Expand-String function. With Expand-String you can expand both types of string/variables. The function defines two parameters, Value and EnvironmentVariable. Value is the string to expand and if the value is a DOS environment variable then you need to specify the EnvironmentVariable switch parameter. You can specify the values on the command line or pipe them to the function.
## Usage ##
# expand single quote strings
PS > $ps = Get-Process -Id $PID
PS > Expand-String -Value 'Process name: $($ps.name)'
Process name: powershell
# expand DOS Environment Variables
PS > Expand-String -Value "%USERNAME%\%USERDOMAIN%" -EnvironmentVariable
# piping values
PS > '%USERNAME%\%USERDOMAIN%'| Expand-String -EnvironmentVariable
PS > 'Process name: $($p.name)' | Expand-String
Process name: powershell