locked
SCCM 2007 DCM Script Always Compliant ! RRS feed

  • Question

  • I have create a VBS script that detects if a Specific Printer Queue is installed on the machine, If the machine doesn't have the Printer it Echos "False", if Printer is connected it echos "True", i have set compliancy to detect is Equals False or True.

    Below is the VBS script used

    WScript.Echo IsPrinterMonoDetected()
    
    Function IsPrinterMonoDetected()
    Set objNetwork = CreateObject("Wscript.Network")
    
    strComputer = "."
    
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    
    Set colPrinters = objWMIService.ExecQuery _
        ("Select * From Win32_Printer Where Local = FALSE")
    
    For Each objPrinter in colPrinters
    
    	if objPrinter.name = "Mono"  then
    
    		IsPrinterMonoDetected = "True"
    
    	else
    
    		IsPrinterMonoDetected = "False"
    
    	end if
    
    Next
    End Function

    Below is the DCM Item With the above script inserted and the validation options.

    The DCM runs on the machine with the printer installed and it reports Compliant, if the machine doesn't have the printer it still reports compliant

    Am i missing anything? the script works on the machine when ran saying either "True" or "False" but DCM just says compliant?

    Any help please....



    • Edited by Danielw2000 Thursday, January 17, 2013 12:44 PM
    Thursday, January 17, 2013 12:27 PM

Answers

  • The compliance rules run against what is echoed by the script, not what the script returns.  If the script echoes a string "True", then you should compare it as a string literal to the word "True" for the compliance value.

    It is perfectly acceptable to echo "False" if not found, and for your validation rule to state "Equals True" should be the expected value.  It could just as easily echo "Mono" or "dog" or "cat", as long as your rule also expects that value as Compliant.

    Personally, I would have the script echo something like "MonoDetected" if it is found, and "MonoNotFound" or something like that if not found.

    Then your rule should have:

    Operator: Equals

    Value: "MonoDetected"

    However, the cause of your evaluation always being Compliant is something else.  If you have two rules as in your original example, and one says Equals "False" and the other Equals "True", one or the other should always be Non-compliant.  You are looping over the query result, I wonder if you are getting multiple results, and echoing both True and False?

    Why don't you try changing your script to make a more restrictive query, something like

    select * from Win32_Printer where Local=False and Name like '%Mono%'

    This way, you should only get one result back, and will for sure only echo once.  I'm not sure if this will solve your problem or not, but I'd say it is worth a try. 

    As probably a better alternative, skip the script altogether and instead use a WQLQuery setting, and define it like this:

    Display Name: Mono Detected

    Namespace: root\cimv2

    Class: Win32_Printer

    Property: Name

    WQL Query WHERE clause:

    Name like '%Mono%'

    On the Validation tab, you could just leave the "Report a non-compliance event when this instance count fails" checkbox selected, with the default of Greater than 0, and set your desired Severity.  You don't even need to add a value rule, but if you wanted to, you would have it say Equals Mono (or contains Mono).  Again this would not be necessary if you use the values I mention above.


    This posting is provided "AS IS", provides no warranties, and confers no rights. -- Kevin

    While I completely agree with what you've said. The OP's script wasn't echoing the string "true" it was echoing the vbscript operator True, which doesnt return a string value. For someone that doesnt fully understand the difference this is only going to create confusion.

    Though I do agree with the suggested approach that as the OP is querying WMI, a WQL query would be more appropriate for this DCM rule


    Kriss Milne | MCSE


    *Please click 'Vote As Helpful' or 'Mark as Answer' if a post has helped you or answered your question*

    • Marked as answer by Nicholas Li Tuesday, February 5, 2013 7:30 AM
    Friday, January 25, 2013 12:42 AM
  • The compliance rules run against what is echoed by the script, not what the script returns.  If the script echoes a string "True", then you should compare it as a string literal to the word "True" for the compliance value.

    It is perfectly acceptable to echo "False" if not found, and for your validation rule to state "Equals True" should be the expected value.  It could just as easily echo "Mono" or "dog" or "cat", as long as your rule also expects that value as Compliant.

    Personally, I would have the script echo something like "MonoDetected" if it is found, and "MonoNotFound" or something like that if not found.

    Then your rule should have:

    Operator: Equals

    Value: "MonoDetected"

    However, the cause of your evaluation always being Compliant is something else.  If you have two rules as in your original example, and one says Equals "False" and the other Equals "True", one or the other should always be Non-compliant.  You are looping over the query result, I wonder if you are getting multiple results, and echoing both True and False?

    Why don't you try changing your script to make a more restrictive query, something like

    select * from Win32_Printer where Local=False and Name like '%Mono%'

    This way, you should only get one result back, and will for sure only echo once.  I'm not sure if this will solve your problem or not, but I'd say it is worth a try. 

    As probably a better alternative, skip the script altogether and instead use a WQLQuery setting, and define it like this:

    Display Name: Mono Detected

    Namespace: root\cimv2

    Class: Win32_Printer

    Property: Name

    WQL Query WHERE clause:

    Name like '%Mono%'

    On the Validation tab, you could just leave the "Report a non-compliance event when this instance count fails" checkbox selected, with the default of Greater than 0, and set your desired Severity.  You don't even need to add a value rule, but if you wanted to, you would have it say Equals Mono (or contains Mono).  Again this would not be necessary if you use the values I mention above.


    This posting is provided "AS IS", provides no warranties, and confers no rights. -- Kevin

    • Marked as answer by Nicholas Li Tuesday, February 5, 2013 7:30 AM
    Thursday, January 24, 2013 8:18 PM
  • I believe the problem is not in the DCM configuration, but it's security context.  The security context of the SCCM Agent Host service can't read user defined printers in the Win32_Printer class.  The local system account context the agent host is running in doesn't have rights to view user data.  

    I tried this on a test system of mine and it seems to hold up.  I was able to run a vb script in my context and read/populate a custom WMI class with printer information.  But when I deleted the class and ported the same script into DCM and applied it to my system, it was unable to read printer information. 

    There is no way I am aware of out of this conundrum.   We are developing a script to be delivered through software delivery for our printers.   

    Sunday, February 17, 2013 8:04 PM

All replies

  • For DCM, the script should return text (any text) for compliant and nothing at all for not compliant. Thus, get rid of "else IsPrinterMonoDetected = "False"".

    Jason | http://blog.configmgrftw.com

    Thursday, January 17, 2013 1:54 PM
  • For Each objPrinter in colPrinters
    if objPrinter.name = "Mono"  then
    IsPrinterMonoDetected = "True"
    end if
    Next

    Im affraid still the same Compliant. :-(

    I actually been watching this video over and over and still trying to figure out why its not working.

    http://technet.microsoft.com/en-us/video/dcm-authoring-script-settings

    Thursday, January 17, 2013 2:05 PM
  • My preference when writing DCM scripts is just to have a single block of code, its not necessary to embed in a function and echo the function:

    Set objNetwork = CreateObject("Wscript.Network")
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colPrinters = objWMIService.ExecQuery _
        ("Select * From Win32_Printer Where Local = FALSE")
    For Each objPrinter in colPrinters
    	if objPrinter.name = "Mono"  then
    		wscript.echo True
    Next

    Also, from a best practice scripting habit you should use option explicit and declare your variables.

    That's how your script should look anyway:

    The next is your validation rule...

    When you return True from vbscript, it doesnt actually return the string true, it returns a value of -1

    So your validation rule should be equals -1

    Your approach to your validation rules are incorrect, if the validation rule matches then it is compliant, if it does not match then it is non compliant. The severity setting is what determines the type of event raised if its non compliant.

    So you should:

    • Delete both of your validation rules
    • Create a new one called Mono Detected_True
    • Set the operator to Equals
    • Set the value to -1
    • Set the severity to Warning

    This will now raise a warning if true (-1) is not returned, and register as compliant if it is returned

    Happy Days :)


    Kriss Milne | MCSE


    *Please click 'Vote As Helpful' or 'Mark as Answer' if a post has helped you or answered your question*


    • Edited by Kriss Milne Friday, January 18, 2013 4:02 AM
    Friday, January 18, 2013 4:01 AM
  • Set objNetwork = CreateObject("Wscript.Network")
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colPrinters = objWMIService.ExecQuery _
        ("Select * From Win32_Printer Where Local = FALSE")
    For Each objPrinter in colPrinters
    	if objPrinter.name = "\\uiwapeps04\Mono"  then
    		wscript.echo True
    	end if
    Next

    Above is the code used and upon testing the script manually generates -1 when printer installed and nothing when not.

    Applied to DCM Item and Validation applied with;

    Name: Mono Detected_TRUE

    Operator: Equals

    Value: -1

    Severity: Warning

    Still reports compliant if printer is on or not!

    Friday, January 18, 2013 9:04 AM
  • Hi,

    I forgot to mention, you should also set the Data Type on the validation page to Integer :)

    I also recommend ticking the box "Report a Non-Compliance event when this instance count fails"

    Set the operator to 'Greater Than' and Value to '0' - This will catch any errors in processing of the validation. The Severity you can set to Warning or Error, I usually prefer Error for this event.

     

    NOTE: - also, in order to get an accurate evaluation after making changes, you should first initiate a Machine Policy Retrieval and Evaluation Cycle on the client, and after waiting a short period of time for the policy retrieval to complete, select the Baseline in the configurations tab and force an evaluation before viewing the report.


    Kriss Milne | MCSE


    *Please click 'Vote As Helpful' or 'Mark as Answer' if a post has helped you or answered your question*


    • Edited by Kriss Milne Tuesday, January 22, 2013 1:39 AM
    Tuesday, January 22, 2013 1:36 AM
  • The compliance rules run against what is echoed by the script, not what the script returns.  If the script echoes a string "True", then you should compare it as a string literal to the word "True" for the compliance value.

    It is perfectly acceptable to echo "False" if not found, and for your validation rule to state "Equals True" should be the expected value.  It could just as easily echo "Mono" or "dog" or "cat", as long as your rule also expects that value as Compliant.

    Personally, I would have the script echo something like "MonoDetected" if it is found, and "MonoNotFound" or something like that if not found.

    Then your rule should have:

    Operator: Equals

    Value: "MonoDetected"

    However, the cause of your evaluation always being Compliant is something else.  If you have two rules as in your original example, and one says Equals "False" and the other Equals "True", one or the other should always be Non-compliant.  You are looping over the query result, I wonder if you are getting multiple results, and echoing both True and False?

    Why don't you try changing your script to make a more restrictive query, something like

    select * from Win32_Printer where Local=False and Name like '%Mono%'

    This way, you should only get one result back, and will for sure only echo once.  I'm not sure if this will solve your problem or not, but I'd say it is worth a try. 

    As probably a better alternative, skip the script altogether and instead use a WQLQuery setting, and define it like this:

    Display Name: Mono Detected

    Namespace: root\cimv2

    Class: Win32_Printer

    Property: Name

    WQL Query WHERE clause:

    Name like '%Mono%'

    On the Validation tab, you could just leave the "Report a non-compliance event when this instance count fails" checkbox selected, with the default of Greater than 0, and set your desired Severity.  You don't even need to add a value rule, but if you wanted to, you would have it say Equals Mono (or contains Mono).  Again this would not be necessary if you use the values I mention above.


    This posting is provided "AS IS", provides no warranties, and confers no rights. -- Kevin

    • Marked as answer by Nicholas Li Tuesday, February 5, 2013 7:30 AM
    Thursday, January 24, 2013 8:18 PM
  • The compliance rules run against what is echoed by the script, not what the script returns.  If the script echoes a string "True", then you should compare it as a string literal to the word "True" for the compliance value.

    It is perfectly acceptable to echo "False" if not found, and for your validation rule to state "Equals True" should be the expected value.  It could just as easily echo "Mono" or "dog" or "cat", as long as your rule also expects that value as Compliant.

    Personally, I would have the script echo something like "MonoDetected" if it is found, and "MonoNotFound" or something like that if not found.

    Then your rule should have:

    Operator: Equals

    Value: "MonoDetected"

    However, the cause of your evaluation always being Compliant is something else.  If you have two rules as in your original example, and one says Equals "False" and the other Equals "True", one or the other should always be Non-compliant.  You are looping over the query result, I wonder if you are getting multiple results, and echoing both True and False?

    Why don't you try changing your script to make a more restrictive query, something like

    select * from Win32_Printer where Local=False and Name like '%Mono%'

    This way, you should only get one result back, and will for sure only echo once.  I'm not sure if this will solve your problem or not, but I'd say it is worth a try. 

    As probably a better alternative, skip the script altogether and instead use a WQLQuery setting, and define it like this:

    Display Name: Mono Detected

    Namespace: root\cimv2

    Class: Win32_Printer

    Property: Name

    WQL Query WHERE clause:

    Name like '%Mono%'

    On the Validation tab, you could just leave the "Report a non-compliance event when this instance count fails" checkbox selected, with the default of Greater than 0, and set your desired Severity.  You don't even need to add a value rule, but if you wanted to, you would have it say Equals Mono (or contains Mono).  Again this would not be necessary if you use the values I mention above.


    This posting is provided "AS IS", provides no warranties, and confers no rights. -- Kevin

    While I completely agree with what you've said. The OP's script wasn't echoing the string "true" it was echoing the vbscript operator True, which doesnt return a string value. For someone that doesnt fully understand the difference this is only going to create confusion.

    Though I do agree with the suggested approach that as the OP is querying WMI, a WQL query would be more appropriate for this DCM rule


    Kriss Milne | MCSE


    *Please click 'Vote As Helpful' or 'Mark as Answer' if a post has helped you or answered your question*

    • Marked as answer by Nicholas Li Tuesday, February 5, 2013 7:30 AM
    Friday, January 25, 2013 12:42 AM
  • I believe the problem is not in the DCM configuration, but it's security context.  The security context of the SCCM Agent Host service can't read user defined printers in the Win32_Printer class.  The local system account context the agent host is running in doesn't have rights to view user data.  

    I tried this on a test system of mine and it seems to hold up.  I was able to run a vb script in my context and read/populate a custom WMI class with printer information.  But when I deleted the class and ported the same script into DCM and applied it to my system, it was unable to read printer information. 

    There is no way I am aware of out of this conundrum.   We are developing a script to be delivered through software delivery for our printers.   

    Sunday, February 17, 2013 8:04 PM