Detect non-standard local administrators with KACE SMA

In a  perfect (admin) world all our people work happily with user level privileges and nobody ever need admin rights nowhere at anytime. This may work well in Windows environments where all devices are managed through active directory and there are interesting tools out there to help you manage these challenges.

Today I want to share a small script that might help you find out where non-standard admin rights are set in your (Windows-)network.

The solution requires at least two and a third optional step:

1. a VBScript that is run periodically as a KACE SMA script
2. a custom inventory rule (CIR) to read the script results into your inventory
3. (optional) setup a report that gives you an overview of all non-standard machines

1. The Script

The script lists all members of the target machines’ local admin group. Since some accounts like the well-known “Administrator” should not necessarily be reported you may (and should) provide excludes for that list.
The script run results are saved to the file "c:\windows\localadmins.txt". If you don’t like that path feel free to adjust it, you can replace this inside the script.

So first you need to copy and paste the following script code into a text editor (I prefer Notepad++) of your choice and save it, for example as “LocalAdministrators.vbs”:


Set objWshNetwork = CreateObject("WScript.Network")
strComputer = objWshNetwork.ComputerName
dim filesys 
Set filesys = CreateObject("Scripting.FileSystemObject") 

'recreate output-file
If filesys.FileExists("c:\windows\localadmins.txt") Then 
	filesys.DeleteFile "c:\windows\localadmins.txt"
End If 
filesys.CreateTextFile("c:\windows\localadmins.txt"), True

' List of well know SID's is available here:
' Well-known security identifiers in Windows operating systems
' http://support.microsoft.com/?id=243330

strGroupSID = "S-1-5-32-544"  ' Well Known SID of the Administrators group


'For output of everything use this:
'excludes = Array()

'For excluding multiple entrys use this:
excludes = Array("Administrator","Domain-Admins")

'For excluding a single entry use this:
'excludes = Array("Administrator")

' Obtain the group name based on well know SID
strGroupName = GetGroupName(strComputer, strGroupSID)

' Connect to the group
Set objGroup = GetObject("WinNT://" & strComputer & "/" & strGroupName & ",group")
' Display all member names in the group
Set filetxt = filesys.OpenTextFile("c:\windows\localadmins.txt", 8, True)
For Each objMember in objGroup.Members
  output = True
  If UBound(excludes) <> -1 Then
	  For i = LBound(excludes) To UBound(excludes)
		If UCase(excludes(i)) = UCase(objMember.Name) Then output = False
  End If
  If output = True Then
	 WScript.Echo objMember.Name
  End If	 

Function GetGroupName(sComputer, sGroupSID)
  Dim oGroupAccounts, oGroupAccount
  Set oGroupAccounts = GetObject( _
       "winmgmts://" & sComputer & "/root/cimv2") _
       .ExecQuery("Select Name from Win32_Group" _
     & " WHERE Domain = '" & sComputer & "' AND SID = '" & sGroupSID & "'")
  If oGroupAccounts.Count = 0 Then
    ' need to use Domain = 'BUILTIN' at least for Win2k SP2
    Set oGroupAccounts = GetObject( _
         "winmgmts://" & sComputer & "/root/cimv2") _
         .ExecQuery("Select Name from Win32_Group" _
       & " WHERE Domain = 'BUILTIN' AND SID = '" & sGroupSID & "'")
  End If
  For Each oGroupAccount In oGroupAccounts
    GetGroupName = oGroupAccount.Name
End Function

Before importing the script into your KACE SMA now define your excludes.
Find this line in the Script:


See the documentation there: The excludes are defined as a comma separated list of strings of all the strings you want to drop from output. You’ll find other examples for a single exclusion or no exclusions as well.

Save the script again!

Now go to the Scripting section of your KACE SMA and create a new script. Be sure to:

  • Provide a nifty name for the script :)
  • Script type is “Online KScript”
  • DON’T FORGET TO TICK “ENABLE” AT YOUR SCRIPT AFTER TESTING! (don’t know how often I forgot that...)
  • Select a bunch of machines, labels or even all devices for deployment
  • Select at least one Windows OS as target “Operating Systems”
  • Run as “Local System”
  • Choose an appropriate schedule (I took every 24 hours)
  • Enable “Allow run without a logged-in user”
  • Preferably enable “Run on next connection if offline”
  • Upload your previously created script file (“LocalAdministrators.vbs”) as dependency

Inside the script you just need one single task with one single step in the “On Success”-section:

  • Step type is “Launch a program...”
  • “Directory” is:
  • “File” is:
  • Enable “Wait for completion”
  • Disable “Visible”
  • Parameters: (include the quotation marks!)
    //nologo "$(KACE_DEPENDENCY_DIR)\LocalAdministrators.vbs"

…so it should look like this in the end:


That’s all for the script. Now save everything and test run it on a couple of machines. You should see an appropriate output in the script run’s log file and, of course, in the output file of the script on the local machine ("c:\windows\localadmins.txt" if you did not change it).

2. The Custom Inventory Rule (CIR)

To attach the generated info to the machines inventory you need to create a custom inventory rule that allows the KACE SMA to upload the content to its database.
Here is how:

Go to your “Inventory” and inside the “Software” section, hit the “Choose Action” button and then click “New”.

Now fill the “Name” field. You can enter anything meaningful you like, e.g. “Local Administrators”.
In “Supported Operating Systems” you have to select at least the Windows OS you chose at the KScript before!
I suggest you pick all Windows Client OS in both cases. Don’t worry, neither the script nor the custom inventory rule will eat up performance or memory on your systems.

Most important: fill the text box “Custom Inventory Rule:” with this one:

ShellCommandTextReturn(cmd /c type C:\Windows\localadmins.txt)

All other fields are not necessary to fill for making this custom inventory rule work. Just save it now and you’re done.

After setting up this custom inventory rule you should see output like this in a machines inventory under “Software” in the “Custom Inventory Fields” section:



3. Optional: the Report

You can define a report that will show you all non-standard systems with more local admins than you expect. This probably won’t work if you did not define any exclusions in the script above anyway.

To create that report go to the “Reporting” section of your SMA, hit “Choose action:” and click on “New (Wizard)”.


Enter a useful name in the “Title” field and assign a fitting category.

I suggest to disable “Show Line Numbers” unless explicitly needed.

Leave “Device” selected as “Topic:” and click the “Next”-button.

In the “Fields to Display”-dialogue I just selected a few fields beside the special information we want so see, in my case that’s “System Name” and “Last Inventory” of the “Device Identity Information”-group.

Now scroll down to the “Custom Fields”-group and expand it. Select your custom inventory field you created in step 2 and continue by clicking the “Next”-button again.

Give the columns the order you desire, I started with “System Name” (that’s nice because KACE SMA will provide a link to that machines’ inventory!)
Continue with “Next” again.

Order the results as you want and proceed with “Next”.

Now in the “Filters” section, hit “Specify rules to filter the records”, remove the unnecessary “Agent connection time” field with the trash bin icon and add your custom inventory again by clicking the + icon.
Define the operator as “is NOT NULL”, now it should look like this:




Finish and test drive your new report!
If everything went right and your machines ran the script and at least one inventory cycle (already mentioned in step 2) you should now get some results - unless you don’t have any non-standard admins floating around!

One last hint: you can use the “Report Schedules” of KACE SMA to periodically investigate your network. For example, let KACE SMA email you the results of your new report as Excel sheet attached once a week.

Now happy admin-hunting :) and leave a comment if you have any questions or suggestions about this!


  • thanks for updating my blog from 2014 and using PS instead of a batch file to run.
    https://www.itninja.com/blog/view/create-a-cir-to-get-a-clean-list-of-your-local-admins-and-then-filter-out-the-it-approved-admins-also-presented-at-dell-world-user-forum-2014-lessions-from-the-field - SMal.tmcc 3 years ago
    • Thanks again for that post in 2014!
      The reason to take this slightly different approach was caused by a scenario in which the local administrators group had different localized names in a (global company) network.
      I'm currently trying to add a way to exclude objects by optionally using the (well-known) SIDs instead of static strings for the same reason.
      But no luck until now... - chrpetri 3 years ago
  • I appreciate it, things have changed a lot in the 5 years and you never think (or have time) to rewrite. With v10 powershell runs much better and a lot of techs understand PS better then batch scripting.

    One thing I would do different is not use c:\windows for the file placement, you really do not want to create random files in the system directories.
    You should use %ALLUSERSAPPDATA%\Quest\KACE\user for file placement. The rights are set correctly on this path when the client installs to do this. Putting files here makes it easier to recognize that they were created for Kace usage and not by malware gathering info. - SMal.tmcc 3 years ago
  • I'm still surprise you guys are still suggesting to run VBS scripts, It's dead: https://www.howtogeek.com/437372/what-is-vbscript-and-why-did-microsoft-just-kill-it/#targetText=On%20August%2013%2C%202019%2C%20Microsoft,will%20be%20disabled%20by%20default.

    I solve the same problems with Powershell - czerp 3 years ago
  • It's not like they are taking the exe to run scripts out of windows. You work with what coding you know. I come from DOS 1.0 days so I still solve a lot of my problems with batch code.
    So why don't you post a powershell solution blog for this if you solve the problems that way. Be glad to read it and rate it. - SMal.tmcc 3 years ago
  • I usually use powershell oneliners directly in the Custom inventory rule (no need of exporting to a file then read):

    ShellCommandTextReturn(Powershell.exe "$Computer = $env:computername; $LocalGroupName = "Administrators"; $group = [ADSI]"WinNT://$Computer/$LocalGroupName"; $members = @($group.Invoke("Members")); $members | foreach {$_[0].GetType().InvokeMember("ADSPath", 'GetProperty', $null, $_, $null)}") - czerp 3 years ago
This post is locked
This website uses cookies. By continuing to use this site and/or clicking the "Accept" button you are providing consent Quest Software and its affiliates do NOT sell the Personal Data you provide to us either when you register on our websites or when you do business with us. For more information about our Privacy Policy and our data protection efforts, please visit GDPR-HQ