Detecting Remote WMI Status

Started by keslaa, March 08, 2016, 11:51:30 AM

Previous topic - Next topic

keslaa

Hello,

I'm running into an issue while trying to read information out of WMI on remote computers. The code works for the most part unless we run into a computer with something broken in it. The code:


objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
objWMIService = objSWbemLocator.ConnectServer(ComputerName, "\root\cimv2\security\microsoftvolumeencryption", strUser, strPswd )
objSecurity = objWMIService.Security_
objSecurity.ImpersonationLevel = 3
objSecurity.AuthenticationLevel = 6
colItems = objWMIService.ExecQuery ("Select * from Win32_EncryptableVolume")
ForEach objInstance In colItems


It's the first three lines that can stop the script, although it's most often the second line. I've set up IntControl 73 to catch the errors, but since the value returned is zero, the next line fails as well. What I'm looking for is a simple test that I can run against the remote computer to ensure I can connect to its WMI without incident. Those machine names will be recorded and dealt with separately.

td

If you detect an error via IntControl 73 then don't execute the parts of the script that are dependent on the line causing the error.  There are multiple ways to accomplish this with IntControl 73.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

I thought others would have chipped in by now as this post invites a larger discussion. Can't remember the exact version but WB upped the capacity of the error handler to go beyond just a goto/gosub into a full error-handling udf.  I found this feature especially useful when working with objects (mainly ADO database stuff). For example, with SQL server when I encountered an error a custom udf could perform a rollback and either offer to try again or gracefully exit.

This particular post involves objects in perhaps multiple instances against multiple targets:  In the OP's case multiple computers. So Assume....

Do While... Enddo  or ForEach... Next  iterating through a list of computers

Create the WMI object, process the object, close the object, continue the loop or Next.

But at some point in the process an error occurs involving the object. At the beginning of the loop or foreach you have set IntControl 73 to redirect to a UDF. In the OP's case the objects have already been created so the UDF should...

1. close the object(s), make an error log notation and skip to the next computer?
2. quit the script (gracefully)?
3. [any suggestions welcome]

Eventually a rewrite of that section of code.

keslaa

Thank you for your replies. Using td's suggestion about IntControl 73, I have found a good way to handle the error and keep on compiling. I specified a goto for P2 instead of the gosub I was using, entered information into my log file and then sent back to the end of the loop to pick up the next name on the list.

td

One very simple but effective method is to wrap the WMI portion of your script in a UDF (not UDS) and just goto a return on error.  That way Winbatch will take care of the error clean up for you.  For examples:

Code (winbatch) Select
;; Returns 1 on success and 0 on error.
;; Could also have it return the WIL error
;; on error and 0 on success.
#DefineFunction DoMyStuff(_strSomething)
   IntControl(73,1, @True,0,0)
 
   ; Do some stuff here.
   
   return 1 ;  Oh happy day. It worked.
:WBERRORHANDLER
   return 0 ;  Wah! Error.
#EndFunction

bResult = DoMyStuff("Something")

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

Quote from: td on March 09, 2016, 10:20:58 AM
One very simple by effective method is to wrap the WMI portion of your script in a UDF (not UDS) and just goto a return on error.

Just out of curiosity, why do you say, explicitly, "not UDS"?

Wouldn't it all work just as well as a UDS?

(Modulo, of course, all the usual advantages and disadvantages of UDS vs. UDF, which don't seem particularly relevant to the instant case...)

stanl

Quote from: td on March 09, 2016, 10:20:58 AM
:WBERRORHANDLER
   return 0 ;  Wah! Error.
#EndFunction


and you do not have to reset the error-handler?

td

Quote from: snowsnowsnow on March 09, 2016, 10:41:56 AM
Quote from: td on March 09, 2016, 10:20:58 AM
One very simple by effective method is to wrap the WMI portion of your script in a UDF (not UDS) and just goto a return on error.

Just out of curiosity, why do you say, explicitly, "not UDS"?

Wouldn't it all work just as well as a UDS?

(Modulo, of course, all the usual advantages and disadvantages of UDS vs. UDF, which don't seem particularly relevant to the instant case...)

Using a UDF allows you to get 'no code' clean up of things like dangling object references.  A UDS does not provide that service.  Since the OP is using WMI COM Automation, this makes the script simpler and easier to maintain.  Note that both a UDF and UDS will cleanup the structure stack for you when using IntControl 73 but the mainline script will not.  This is important when suppressed errors can occur in structured ifs, or loop structures.       
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

Quote from: stanl on March 09, 2016, 11:23:17 AM
Quote from: td on March 09, 2016, 10:20:58 AM
:WBERRORHANDLER
   return 0 ;  Wah! Error.
#EndFunction


and you do not have to reset the error-handler?

The scope of the IntControl 73 set in the UDF is the UDF.  It means nothing outside the UDF.   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

keslaa

For the record, I had to rethink the way I was handling the IntControl 73. I moved the WMI scan portion of my script into a UDF. Everything works now. Thanks for all the suggestions!