Hey, Scripting Guy! Part 2: How Can I Make Sure That a WMI Provider Exists Before Using It in a Script?

Hey, Scripting Guy! Part 2: How Can I Make Sure That a WMI Provider Exists Before Using It in a Script?

  • Comments 1
  • Likes

Bookmark and Share

(Editor's note: This is part 2 of a two-part article originally intended for TechNet Magazine. Part 1 was published yesterday.) 

 

To obtain information about the provider for a WMI class, you will need to open the class. Click the Open Class button, and type the name of the WMI class in the box that appears. We are looking for the provider name for the Win32_Product WMI class, and that is the name that you should type here. Click the OK button after you have typed and submitted the class name. The object editor for the Win32_Product WMI class now appears. This is seen in the following image. The first box of the object editor for Win32_Product lists the qualifiers. Provider is one of the qualifiers. WbemTest tells you the provider for Win32_Product is MSIProv.

Image of object editor for Win32_Product WMI class


You then assign the name of the WMI provider to the $providerName variable as seen here:

$providerName = "MSIProv"

The resulting object is stored in the $provider variable. This is seen here:

 $provider =  Get-WmiObject -Class __provider -filter "name = '$providerName'"

If the provider was not found, there will be no value in the $provider variable. You can therefore see if the $provider variable is null. If the $provider variable is not equal to null, the class ID of the provider is retrieved. The class ID of the WMI provider is stored in the clsID property. This is seen here:

 If($provider -ne $null)
   {
    $clsID = $provider.clsID

If the function was run with the verbose parameter, the $VerbosePreference variable is set to Continue. When the value of $VerbosePreference is equal to continue, the Write-Verbose cmdlet will display information on the console. On the other hand, if the value of the $VerbosePreference variable is equal to SilentlyContinue, the Write-Verbose cmdlet does not display anything. This makes it easy to implement tracing features in a function without needing to create extensive test conditions. When the function is called with the Verbose parameter, the class ID of the provider is displayed. This is seen here:

    Write-Verbose "$providerName WMI provider found. ClsID is $($clsID)"
   }

If the WMI provider is not found, the function returns false to the calling code. This is seen here:

 Else
   {

     Return $false
   }

The next thing the function does is check the registry to ensure the WMI provider has been properly registered with DCOM. Once again, the Write-Verbose cmdlet is used to provide feedback about the status of the provider check. This is seen here:

   Write-Verbose "Checking for proper registry registration ..."

To search the registry for the WMI provider registration, the Windows PowerShell registry provider is used. By default, there is no Windows PowerShell drive for the HKEY_CLASSES_ROOT registry hive. However, it is not a given that one would not have created such a drive in their Windows PowerShell profile. To avoid a potential error that might arise when creating a Windows PowerShell drive for the HKEY_CLASSES_ROOT hive, the Test-Path cmdlet is used to check to see if a HKCR: drive exists. If the HKCR: drive does exist, it will be used and the Write-Verbose cmdlet is used to display a status message that states the HKCR: drive was found and that the search is commencing for the class ID of the WMI provider. This is seen here:

   If(Test-Path -path HKCR:)
      {
        Write-Verbose "HKCR: drive found. Testing for $clsID"

To detect if the WMI provider is registered with DCOM, all that is necessary is to see if the class ID of the WMI provider is present in the CLSID section of HKEY_CLASSES_ROOT. The best way to check for the presence of the registry key is to use the Test-Path cmdlet. This is seen here:

        Test-path -path (Join-Path -path HKCR:\CLSID -childpath $clsID) 
      }

On the other hand, if there is no HKCR: drive on the computer, you can go ahead and create one. You could search for the existence of a drive that is rooted in HKEY_CLASSES_ROOT, and if you found it, you could then use the Windows PowerShell drive in your query. To find if there are any Windows PowerShell drives rooted in HKEY_CLASSES_ROOT, you could use the Get-PSDrive cmdlet as seen here:

Get-PSDrive | Where-Object { $_.root -match "classes" } |
Select-Object name

But to be honest, it is more trouble than it is worth. There is nothing wrong with having multiple Windows PowerShell drives mapped to the same resource. Therefore, if there is not an HKCR: drive, the Write-Verbose cmdlet is used to display a message that the drive does not exist and will be created. This is seen here:

   Else
     {
      Write-Verbose "HKCR: drive not found. Creating same."

To create a new Windows PowerShell drive, you use the New-PSDrive cmdlet to specify the name for the Windows PowerShell drive and the root location of the drive. Because this is going to be a registry drive, you will use the registry provider. When a Windows PowerShell drive is created, it displays feedback on the Windows PowerShell console. This feedback is seen here:

PS C:\AutoDoc> New-PSDrive -Name HKCR -PSProvider registry -Root Hkey_Classes_Ro
ot


Name       Provider      Root                                   CurrentLocation
----       --------      ----                                   ---------------
HKCR       Registry      Hkey_Classes_Root

The feedback from creating the registry drive can be distracting. To get rid of the feedback, you can pipe the results to the Out-Null cmdlet:

      New-PSDrive -Name HKCR -PSProvider registry -Root Hkey_Classes_Root | Out-Null

After the Windows PowerShell registry drive has been created, it is time to check for the existence of the WMI provider class ID. Before that is done, the Write-Verbose cmdlet is used to provide feedback about this step of the operation:

      Write-Verbose "Testing for $clsID"

The Test-Path cmdlet is used to check for the existence of the WMI provider class ID. To build the path to the registry key, the Join-Path cmdlet is used. The parent path is the HKCR: registry drive CLSID hive, and the child path is the WMI provider class ID that is stored in the $clsID variable. This is seen here:

      Test-path -path (Join-Path -path HKCR:\CLSID -childpath $clsID

After the Test-Path cmdlet has been used to check for the existence of the WMI provider class ID, the Write-Verbose cmdlet is used to display a message stating that the test is complete:

      Write-Verbose "Test complete."

It is a best practice to not make permanent modifications to the Windows PowerShell environment in a script. Therefore, you will want to remove the Windows PowerShell drive if it was created in the script. The Write-Verbose cmdlet is employed to provide a status update, and the Remove-PSDrive cmdlet is used to remove the HKCR: registry drive. To avoid cluttering the Windows PowerShell console, the result of removing the HKCR: registry drive is piped to the Out-Null cmdlet. This is seen here:

      Write-Verbose "Removing HKCR: drive."
      Remove-PSDrive -Name HKCR | Out-Null

     }

The last thing that needs to be done is to set the $VerbosePreference back to the value that was stored in the $oldVerbosePreference. This line of code is executed even if no change to the $VerbosePreference is made. This is seen here:

  $VerbosePreference = $oldVerbosePreference
} #end Get-WmiProvider function

The entry point to the script assigns a value to the $providerName variable:

$providerName = "msiprov"

The Get-WmiProvider function is called and it passes both the WMI provider name that is stored in the $providerName variable and the verbose switched parameter. The if statement is used because the Get-WmiProvider function returns a Boolean value (true or false):

 if(Get-WmiProvider -providerName $providerName  -verbose )

If the return from the Get-WmiProvider function is true, the WMI class supported by the WMI provider is queried by using the Get-WMiObject cmdlet. This is seen here:

  {

    Get-WmiObject -class win32_product


  }

If the WMI provider is not found, a message that states the WMI provider is not found is displayed on the console:

else
  {
   "$providerName provider not found"
  }

The entire Get-WmiProviderFunction.ps1 script is shown here:

Figure 3  Get-WmiProviderFunction.ps1

Function Get-WmiProvider([string]$providerName, [switch]$verbose)
{
 $oldVerbosePreference = $VerbosePreference
 if($verbose) { $VerbosePreference = "continue" }
 $provider =  Get-WmiObject -Class __provider -filter "name = '$providerName'"
 If($provider -ne $null)
   {
    $clsID = $provider.clsID
    Write-Verbose "$providerName WMI provider found. ClsID is $($clsID)"
   }
 Else
   {

     Return $false
   }
   Write-Verbose "Checking for proper registry registration ..."
   If(Test-Path -path HKCR:)
      {
        Write-Verbose "HKCR: drive found. Testing for $clsID"
        Test-path -path (Join-Path -path HKCR:\CLSID -childpath $clsID) 
      }

   Else
     {
      Write-Verbose "HKCR: drive not found. Creating same."
      New-PSDrive -Name HKCR -PSProvider registry -Root Hkey_Classes_Root | Out-Null

      Write-Verbose "Testing for $clsID"
      Test-path -path (Join-Path -path HKCR:\CLSID -childpath $clsID)
 
      Write-Verbose "Test complete."

      Write-Verbose "Removing HKCR: drive."
      Remove-PSDrive -Name HKCR | Out-Null

     }
  $VerbosePreference = $oldVerbosePreference
} #end Get-WmiProvider function

# *** Entry Point to Script ***
$providerName = "msiprov"
 if(Get-WmiProvider -providerName $providerName  -verbose )
  {

    Get-WmiObject -class win32_product

  }

else

  {

   "$providerName provider not found"

  }


We hope you will find these techniques useful and that you will incorporate them into your daily scripting needs. We invite you to join us on the Script Center for the daily Hey, Scripting Guy! Blog post
. If you would like to be among the first to be informed about everything that is happening on the Script Center, you can follow us on Twitter. We also make postings over on the Scripting Guys group on Facebook. If you get stuck some night while you are working on a script, you can post to the Official Scripting Guys Forum. We have an excellent group of moderators and other active members who are always willing to help other scripters. Of course, if you have questions, suggestions, or comments, you can always send us e-mail at scripter@microsoft.com.

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Very helpful post thanks!