Hey, Scripting Guy! I have a mixture of operating systems at work. We have Windows XP on the desktop, a few Windows Vista machines, Windows 7 on a few computers so far, Windows 2003 in the server room, and Windows 2008 and a couple of Windows 2008 R2 computers that are running Hyper-V on Windows Core edition. I know we are not unique in this regard, but given all this diversity, do you have any tricks that can be done to ensure that my scripts will not bomb out?
— JH
Hello JH,
Microsoft Scripting Guy Ed Wilson here. The other night I watched the movie, A Christmas Story, which is about a little boy who wants a BB gun for Christmas. One of the funniest scenes in the movie happens when the boy gets his tongue stuck to the flagpole in the schoolyard. I never got my tongue stuck to a flagpole when I was a little scripting guy (I grew up in Florida in the United States and it was never an option). Luckily, I had seen the movie when I moved to Ohio, and my co-workers tried to get me to stick my tongue on the flagpole at work. The trick to keeping your tongue attached to your mouth lies in knowing about the properties of frozen flagpoles.
Note: Portions of today’s Hey, Scripting Guy! post are excerpted from the Microsoft Press book, Windows PowerShell 2.0 Best Practices by Ed Wilson, which is now available for pre-order.
JH, the trick to ensure that your scripts do not bomb out is to know about the various operating systems. The easiest way to see if a script will work on a particular version of the operating system is to run it and see what happens. I have a Windows Server 2008 R2 Core Edition at home configured to run Hyper-V and a variety of different operating systems. When I determine a script will not work on a particular version of the operating system, I add a check for the operating system and exit the script gracefully.
Given the differences between the various versions of the Windows operating system, it is a best practice to check the version of the operating system before executing the script if you know that there could be version compatibility issues. There are, of course, several different methods of doing this. You can use the .NET Framework class System.Environment to check the operating system version. This is seen here:
PS C:> ([system.environment]::osversion).version.tostring()
6.1.7600.0
It is true that you can use Windows PowerShell remoting to get information from this class remotely, as seen here:
PS C:> Invoke-Command -ComputerName hyperv -Script { ([system.environment]::osversion).version.tostring() }
6.1.7600.0
PS C:>
But you can also achieve similar results using the WMI class Win32_OperatingSystem. The advantage of this approach is that WMI automatically remotes, and the syntax is a bit easier to use.
The GetVersion.ps1 script accepts a single command-line parameter, $computer, which is set by default to the localhost computer. The entry point to the script passes the value of the $computer variable and a reference type variable $osv to the Get-OSVersion function. Inside the Get-OSVersion function, the first thing that is done is to use the Get-WMIObject cmdlet to query the Win32_OperatingSystem WMI class from the computer that is targeted by the $computer variable. The resulting management object is stored in the $os variable.
The Switch statement is used to evaluate the Version property of the Win32_OperatingSystem class. If the value of the Version property is equal to 5.1.2600, the value property of the $osv reference type variable is set equal to xp. This type of logic is repeated for the value 5.1.3790, which was the build number for Windows Server 2003.
A problem arises if the version number is 6.0.6001 because both Windows Server 2008 and Windows Vista have the same build number. This is the same problem if the version number is 6.1.7600 because both Windows Server 2008 R2 and Windows 7 have the same build number. This is why the script stores the entire Win32_OperatingSystem management object in the $os variable instead of retrieving only the version attribute. The ProductType property can be used to distinguish between a workstation and a server. The possible values for the ProductType property are seen in Table 1.
Table 1 Win32_OperatingSystem ProductType Values and Associated Meanings
Value |
Meaning |
1 |
Work Station |
2 |
Domain Controller |
3 |
Server |
After the version of the operating system has been detected, a single word or number representing the operating system is assigned to the value property of the reference variable. In the GetVersion.ps1 script, this value is displayed on the console. The complete GetVersion.ps1 script is seen here.
GetVersion.ps1
Param($computer = “localhost”)
Function Get-OSVersion($computer,[ref]$osv)
{
$os = Get-WmiObject -class Win32_OperatingSystem `
-computerName $computer
Switch ($os.Version)
{
“5.1.2600” { $osv.value = “xp” }
“5.1.3790” { $osv.value = “2003” }
“6.0.6001”
{
If($os.ProductType -eq 1)
{
$osv.value = “Vista”
} #end if
Else
{
$osv.value = “2008”
} #end else
} #end 6001
“6.1.7600”
{
If($os.ProductType -eq 1)
{
$osv.value = “Win7”
} #end if
Else
{
$osv.value = “2008R2”
} #end else
} #end 7600
DEFAULT { “Version not listed” }
} #end switch
} #end Get-OSVersion
# *** entry point to script ***
$osv = $null
Get-OSVersion -computer $computer -osv ([ref]$osv)
$osv
The GetVersion.ps1 script returns a single word to indicate the version of the operating system. You can use this from the command line to quickly check the operating system version, as seen here:
PS C:bp> .GetVersion.ps1
Vista
PS C:bp> .GetVersion.ps1 -c berlin
2008
PS C:bp> .GetVersion.ps1 -c lisbon
xp
The GetVersion.ps1 script was written as a function to permit easy inclusion in other scripts. This allows you to perform the operating system version check, and then decide if you wish to continue processing the script. An example of this approach is seen in the GetVersionGetVolume.ps1 script that uses the Win32_Volume WMI class we examined in yesterday’s Hey, Scripting Guy! post.
GetVersionGetVolume.ps1
Param($drive = “C:”, $computer = “localhost”)
Function Get-OSVersion($computer,[ref]$osv)
{
$os = Get-WmiObject -class Win32_OperatingSystem `
-computerName $computer
Switch ($os.Version)
{
“5.1.2600” { $osv.value = “xp” }
“5.1.3790” { $osv.value = “2003” }
“6.0.6001”
{
If($os.ProductType -eq 1)
{
$osv.value = “Vista”
} #end if
Else
{
$osv.value = “2008”
} #end else
} #end 6001
“6.1.7600”
{
If($os.ProductType -eq 1)
{
$osv.value = “Win7”
} #end if
Else
{
$osv.value = “2008R2”
} #end else
} #end 7600
DEFAULT { “Version not listed” }
} #end switch
} #end Get-OSVersion
Function Get-Volume($drive, $computer)
{
$drive += “\”
Get-WmiObject -Class Win32_Volume -computerName $computer `
-filter “Name = ‘$drive'”
} #end Get-Volume
# *** entry point to script ***
$osv = $null
Get-OSVersion -computer $computer -osv ([ref]$osv)
if($osv -eq “xp”) { “Script does not run on XP” ; exit }
Get-Volume -Drive $drive -Computer $computer
When the GetVersionGetVolume.ps1 script is run against my remote Windows XP computer (named WinXP), the script displays a message that states the script will not run on a Windows XP computer. This is seen here:
JH, that is all there is to using WMI to check the operating system version. WMI Week will continue tomorrow.
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail 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