#208686 - 2014-03-06 03:33 PM
How to get a for each statement nested within a for each statement
|
Robdutoit
Hey THIS is FUN
Registered: 2012-03-27
Posts: 363
Loc: London, England
|
I am not getting this one right. I have tried different variations, but still no joy!
My Function is as follows:
Function GetW7AVinfo(optional $machine)
dim $oSWbem,$colItems,$av[4],$colItem
if not $machine $machine = "." endif
$Product= "AntiVirusProduct"
$Product= "AntiSpywareProduct"
$Product= "FirewallProduct"
$oSWbem = GetObject("winmgmts:\\" + $machine + "\root\SecurityCenter2")
If @Error exit @error EndIf
For each $SelectStatement in $Product
$colItems = $oSWbem.ExecQuery("Select * From " + $SelectStatement)
If @Error exit @error EndIf
For Each $colItem In $colItems
$av[0] = $colItem.productState
$av[1] = $colItem.displayName
$av[2] = $colItem.instanceGuid
$av[3] = $colItem.pathToSignedProductExe
$av[4] = $colItem.pathToSignedReportingExe
Next
? $av[1]
? $av[2]
? $av[3]
? $av[4]
? $av[0]
if $av[0] = 0 ? $Product + "not installed"
else
endif
EndFunction
If I replace $SelectStament with either AntiVirusProduct, AntiSpywareProduct and get rid of the for each $selectstatement, then code works perfectly. But I don't want to have three Functions GetW7AVinfo and Function GetW7ASinfo and Function GetW7FWinfo. In other words this works $colItems = $oSWbem.ExecQuery("Select * From AntiVirusProduct"), but I want the script to loop and replace AntiVirusProduct with AntiSpywareProduct and then FirewallProduct if that makes sense
I know that it can be done, but I cannot work out how to call AntivirusProduct, run the rest of the UDF and then return back to the top and call Antispyware Product. What the script is doing is not calling anything as its obviously not using the For each $SelectStatement in $Product.
lastly, what would be the best option to alert the administrator to a problem. My intention is to complete the coding for the script and run it as a scheduled task on each computer once every fortnight. If there is problem, the script will write to a file on the server giving out name of computer and what is not installed or up to date. But not sure whether there is a better way.
|
Top
|
|
|
|
#208690 - 2014-03-06 03:55 PM
Re: How to get a for each statement nested within a for each statement
[Re: Robdutoit]
|
Robdutoit
Hey THIS is FUN
Registered: 2012-03-27
Posts: 363
Loc: London, England
|
How bizarre. It worked this time. Maybe I had something different in the script when I was trying an hour ago. its working now so ignore that.
I don't know if the problem with the Code highlighting should be default issue is causing my current issues with kixtart, but I am getting double posts and it hangs when posting anything. I have to click try again or type in http://www.kixtart.org to get back to the website. May be unrelated to the code highlighting change, but I thought that I would mention it.
|
Top
|
|
|
|
#208694 - 2014-03-06 05:41 PM
Re: How to get a for each statement nested within a for each statement
[Re: Glenn Barnas]
|
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
|
Just a comment from the perspective of an instructor...Function GetW7AVinfo(optional $machine)
dim $oSWbem,$colItems,$av[4],$colItem
if not $machine $machine = "." endif
$Product= "AntiVirusProduct"
$Product= "AntiSpywareProduct"
$Product= "FirewallProduct"
$oSWbem = GetObject("winmgmts:\\" + $machine + "\root\SecurityCenter2")
If @Error exit @error EndIf
For each $SelectStatement in $Product contains errors as Lonk pointed out, but also is not as clear as it could be..
You have multiple products in an array, so declare (DIM!) the array of products (plural!)and define the arrayDim $aProducts, $Product ; array of products, enumerator var
$aProducts = 'prod 1', 'prod 2', 'prod 3' Now you have an array that clearly indicates its content - a list of products, and a variable used to step through (enumerate) that list with a meaningful name - $Product.For Each $Product in $Products The code is the same, but the clarity is improved.
Your loop For Each $ColItem in $colItems is also unclear. The "col" in front of the "real" variable name Items ($colItems) implies that it is a collection of items from an object reference. $colItem isn't a collection, so the "col" prefix is misleading. A better form would be For Each $Item in $colItems Again, you follow a singular/plural format for the enumeration, but don't imply that the enumerated object is a collection.
Simple syntax changes that make your code more readable and understandable, both to others and to your "future" self.
Glenn
_________________________
Actually I am a Rocket Scientist!
|
Top
|
|
|
|
#208695 - 2014-03-06 05:54 PM
Re: How to get a for each statement nested within a for each statement
[Re: Glenn Barnas]
|
Robdutoit
Hey THIS is FUN
Registered: 2012-03-27
Posts: 363
Loc: London, England
|
I think we need to close Korg down and hire Glenn. He comes up with all the answers! I never noticed that there was a delete option when editing the post. I just didn't see a delete option where one sees the reply, quote, quick reply etc. Thanks Glenn, I will remember that.
Does anyone know how I work out where in this script the loop function starts. I have tried to reset the variable to be blank after each loop but cannot get it to work. The reason being is that the script is returning the details of the anti virus, then the details of the anti spyware, but when it is supposed to return the details of the firewall it should be returning blanks for the firewall, but instead its returning the information received in the last loop from the anti spyware!
I have tried to put in an exit function so that the coding exits if say a third party firewall is not installed, but this does not work and I think its because its still finding a class called firewallproduct in WMI even if nothing is installed and using it. The working script that I have at the moment is:
Function GetW7AVinfo(optional $machine)
dim $oSWbem,$colItems,$av[4],$colItem
if not $machine $machine = "." endif
$Product = "AntiVirusProduct", "AntiSpywareProduct", "FirewallProduct"
$oSWbem = GetObject("winmgmts:\\" + $machine + "\root\SecurityCenter2")
If @Error exit @error EndIf
For each $SelectStatement in $Product
$colItems = $oSWbem.ExecQuery("Select * From " + $SelectStatement)
If @Error exit @error EndIf
For Each $colItem In $colItems
$av[0] = $colItem.productState
$av[1] = $colItem.displayName
$av[2] = $colItem.instanceGuid
$av[3] = $colItem.pathToSignedProductExe
$av[4] = $colItem.pathToSignedReportingExe
Next
? $av[1]
? $av[2]
? $av[3]
? $av[4]
? $av[0]
; Select $iProductState = Hex($colItem.productState, 8)
; Case ($iProductState, 5, 2) = "00" or "01"
; $aReturn[5] = "Disabled"
; Case "10", "11"
; $aReturn[5] = "Enabled"
; EndSelect
if $av[0] = 0 ? "Something not installed"
else
endif
EndFunction
Exit
What I am trying to get it to do go through each loop and ultimately it will send to a file anything that is not installed/updated/enabled etc. I will get to the file bit later, but I cannot work out where to dim the variable so that $ColItems is set to zero after loop. I think part of the problem is that you cannot dim an array - $product which is why its probably not working. But reading the documentation the variable is retained only within the if else endif statement therefore I assumed that the variable would only be remembered for one loop within the For each statement! Or does remembering the value of the variables only get eliminated within if else endif statements and not in for net and while .. do until statements?
|
Top
|
|
|
|
#208697 - 2014-03-06 06:27 PM
Re: How to get a for each statement nested within a for each statement
[Re: Robdutoit]
|
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
|
You probably want something more like this:Function GetW7AVinfo(optional $_Machine)
Dim $_oSWbem ; COM Object pointer for query
Dim $_colItems, $_Item ; collection of items, enumerator var
Dim $_Product ; Product type to retrieve
Dim $_Av[4] ; 5-element array to return
; Define localhost if Machine Name not provided
If Not $_Machine $_Machine = '.' EndIf
; Define product to find
$_Product = 'AntiVirusProduct'
$_oSWbem = GetObject('winmgmts:\\' + $_Machine + '\root\SecurityCenter2')
If @ERROR Exit @ERROR EndIf
; Get collection of items for product type
$_colItems = $_oSWbem.ExecQuery('Select * From ' + $_Product)
If @ERROR Exit @ERROR EndIf
; process the collection and assign the desired object values
For Each $Item In $colItems
$_Av[0] = $Item.productState
$_Av[1] = $Item.displayName
$_Av[2] = $Item.instanceGuid
$_Av[3] = $Item.pathToSignedProductExe
$_Av[4] = $Item.pathToSignedReportingExe
Next
; DEBUGGING
$_Product @CRLF ; show current product type
Join($_Av, @CRLF) @CRLF ; show array, 1 element per line
; Select $iProductState = Hex($colItem.productState, 8)
; Case ($iProductState, 5, 2) = '00' or '01'
; $aReturn[5] = 'Disabled'
; Case '10', '11'
; $aReturn[5] = 'Enabled'
; EndSelect
; Prepare to return the data
$GetW7AVinfo = $_Av
; Validate results of query and return exit status accordingly
If $_Av[0] = 0
; ? 'Something not installed' ; BAD! Do not generate output from UDFs
Exit 2 ; not found, optionally use "87" for invalid value
EndIf
Exit 0 ; success!
EndFunction You probably want to move the commented code that deals with element 5 of the AV array to your core code, and use the correct index value, as "5" is beyond the 5th element of the array (Dim $_Av[4]).
Also - the two lines after the ; DEBUGGING comment should be removed after testing.
Glenn
_________________________
Actually I am a Rocket Scientist!
|
Top
|
|
|
|
Moderator: Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart
|
0 registered
and 515 anonymous users online.
|
|
|