WinBatch® Technical Support Forum

All Things WinBatch => WinBatch => Topic started by: keslaa on March 08, 2016, 11:51:30 AM

Title: Detecting Remote WMI Status
Post by: keslaa on March 08, 2016, 11:51:30 AM
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.
Title: Re: Detecting Remote WMI Status
Post by: td on March 08, 2016, 01:10:25 PM
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.
Title: Re: Detecting Remote WMI Status
Post by: stanl on March 09, 2016, 04:08:56 AM
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.
Title: Re: Detecting Remote WMI Status
Post by: keslaa on March 09, 2016, 08:28:13 AM
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.
Title: Re: Detecting Remote WMI Status
Post by: td on March 09, 2016, 10:20:58 AM
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")

Title: Re: Detecting Remote WMI Status
Post by: 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...)
Title: Re: Detecting Remote WMI Status
Post by: 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?
Title: Re: Detecting Remote WMI Status
Post by: td on March 09, 2016, 11:32:57 AM
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.       
Title: Re: Detecting Remote WMI Status
Post by: td on March 09, 2016, 11:38:35 AM
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.   
Title: Re: Detecting Remote WMI Status
Post by: keslaa on March 15, 2016, 05:36:13 AM
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!