How to Exit a For Each Loop within a Function?

infrb picture infrb · Dec 17, 2013 · Viewed 7.3k times · Source

I've got the following Function that is designed to recursively read all WMI namespaces on a machine depending on the namespace that's been passed (by default the script calls for ReadWMI("root"). If a WMI namespace contains the name sms or ccm, I want to test writing to that namespace to validate writing works. If Writing to WMI fails in that function, I want to exit the For Loop and completely exit the function.

What I'm noticing is that when I exit the for or exit the function (using either Exit For or Exit Function) I go back to Next instead of exiting the function completely. This causes a number of issues where other namespaces can successfully be written to.

Function ReadWMI(strNameSpace)

Dim oWMI, colNameSpaces, objNameSpace, sFullNamespace

'ReadWMI = "True"

WMI_ReadRepository = "Healthy"

On Error Resume Next

'Verify all namespaces

Set oWMI = GetObject("winmgmts:\\" & sComputer & "\" & strNameSpace)

If Err.Number <> 0 Then

    ReadWMI = "False"

    WMI_ReadRepository = "Unhealthy"

    oLog.WriteLine Now()& " - " &  "ReadWMI(): Failed to bind to WMI namespace " & strNamespace & ". Stopping WMI Verification"
    oLog.WriteLine Now()& " - " &  "ReadWMI(): Error Code: " & Err.Number
    'oLog.WriteLine Now()& " - " &  "ReadWMI(): Error Description: " & Err.Description
    Err.Clear

    Exit Function

Else

    oLog.WriteLine Now()& " - " &  "ReadWMI(): Successfully connected to WMI namespace " & strNamespace 

End If  

Set colNameSpaces = oWMI.InstancesOf("__NAMESPACE")

For Each objNameSpace In colNameSpaces

    sFullNamespace = LCase(strNamespace & "\" & objNamespace.Name)



    If InStr(sFullNamespace,"ccm") Or InStr(sFullNamespace,"sms") > 0 Then

        oLog.WriteLine Now()& " - " &  "ReadWMI(): Writing to " & sFullNamespace & " WMI Namespace if WMIWriteRepository set to TRUE"

        If WMIWriteRepository = True Then

            If WriteWMI(sFullNamespace) = "False" Then

                oLog.WriteLine Now()& " - " &  "ReadWMI(): Failed to write to namespace " & sFullNamespace

                WMI_ReadRepository = "Unhealthy"

                'ReadWMI = "False"

                Exit Function

            End If

        Else

            oLog.WriteLine Now()& " - " &  "ReadWMI(): WMIWriteRepository set to False or OS is a Server. Will not write to repository."    

        End If


    End If


    'Call VerifyWMI again to run through the next namespace     

    Call ReadWMI(sFullNamespace)

Next



'ReadWMI = "True"

'WMI_ReadRepository = "Healthy"

Set oWMI = Nothing

On Error Goto 0

End Function

Answer

AutomatedChaos picture AutomatedChaos · Dec 17, 2013

If something goes wrong and you want to jump out of the recursive function call, make the return value False (uncomment the 'ReadWMI = "False" in your script).

Your last statement before the next must test if the reading of the WMI was correct, so instead of

Call ReadWMI(sFullNamespace)

use

If ReadWMI(sFullNamespace) = "False" Then
    Exit For
End If

Protip: Stop using "string booleans", they are slow and errors are luring around the corner to bite you in the back ("True" <> "true" <> "Treu" <> "True "). Just use True and False. Whenever you want to output a boolean to a string, it is automatically converted to the correct string value:

MsgBox True & " / " & False 
' Output: "True / False"