As the old management saying goes “You can’t manage what you don’t measure”. A lot of scripting solutions I have been utilizing lately have been all about inventory. Having the right information at the right time can give you a true picture of your organization and the areas you might need to work on to simplify support, improve security, or a little bit of both.
The beauty of a domain-based infrastructure is the central management. For users, you can find out their information, change their password, and manage their group membership all from a console you can install on the endpoints. Setting up and utilizing local accounts can have their purposes such as for portable devices that may not contact the domain for a while. However, if the local account usage gets out of hand, you might be losing the benefit of the centralized management.
I created this script which utilizes WMI and assigned it as a shutdown script through Group Policy in order to list all of the local accounts on client computers. Since local accounts will not change that frequently, I have the script check to see if the “receipt” for that computer exists on the server already and if so, it can exit so the script doesn’t take up any more time running and I don’t get duplicate data.
The receipt that gets written out is a nicely formatted list of all local accounts and their properties. One particular property of interest checks to see if this local account is a member of the local Administrators group. I also have the script append the output to a .csv file for easy sorting and analysis. You will need a server share for the script to write to with the correct permissions for the computer accounts to be able to read and save their receipt and modify the .csv file.
You will also want to start the .csv file with some headers to make the data more meaningful. I went with:
Domain, User Name, Context, Disabled, Admin, Local Acct, Locked Out, Password Changeable, Password Expires, Password Requires.
On line 17 and 29, you will want to update the receipt and report paths to match where they should be stored on your server.
On Error Resume Next
Set objWMIService = GetObject("winmgmts:" _ & "{impersonationLevel=impersonate}!\.rootcimv2")
Set colItems = objWMIService.ExecQuery _ ("Select * from Win32_UserAccount Where LocalAccount = True")
Set objGroup = GetObject("WinNT://./Administrators")
intLoopCnt = 0 For Each objItem in colItems
intLoopCnt = intLoopCnt + 1 If intLoopCnt = 1 Then 'Write out all accounts to receipts strReceiptPath = "\ServershareLocalUserInfoReceipts" & objItem.Domain & ".txt"
'Exit if receipt for this computer already exists Set objFSO = CreateObject("Scripting.FileSystemObject") If objFSO.FileExists(strReceiptPath) Then Wscript.quit End If
Set objReceipt = objFSO.CreateTextFile(strReceiptPath) Set objReceipt = objFSO.OpenTextFile(strReceiptPath, 2)
'Append all accounts except Administrator and Guest to LocalUserReport.csv strReportPath = "\ServershareLocalUserInfoLocalUserReport.csv"
Set objReport = objFSO.OpenTextFile(strReportPath, 8) End If
objReceipt.WriteLine("Domain: " & objItem.Domain) objReceipt.WriteLine("Name: " & objItem.Name) objReceipt.WriteLine("Caption: " & objItem.Caption) objReceipt.WriteLine("Disabled: " & objItem.Disabled) strAdmin = "Reset" For Each objUser in objGroup.Members If objUser.Name = objItem.Name Then strAdmin = "Yes" End If Next If strAdmin = "Yes" Then objReceipt.WriteLine("Local Administrator: Yes") strAdmin = "Yes" Else objReceipt.WriteLine("Local Administrator: No") strAdmin = "No" End If
objReceipt.WriteLine("Local Account: " & objItem.LocalAccount) objReceipt.WriteLine("Lockout: " & objItem.Lockout) objReceipt.WriteLine("Password Changeable: " & objItem.PasswordChangeable) objReceipt.WriteLine("Password Expires: " & objItem.PasswordExpires) objReceipt.WriteLine("Password Required: " & objItem.PasswordRequired) objReceipt.WriteLine("")
If ((objItem.Name <> "Administrator") AND (objItem.Name <> "Guest")) Then strReport = objItem.Domain & "," & objItem.Name & "," & objItem.Caption & "," & objItem.Disabled & "," & strAdmin & "," & objItem.LocalAccount & "," & objItem.Lockout & "," & objItem.PasswordChangeable & "," & objItem.PasswordExpires & "," & objItem.PasswordRequired objReport.WriteLine(strReport) End If Next
objReceipt.Close objReport.Close
Wscript.quit
A note from experience, you will want to make a copy of your .csv file and only open the copy. If you were to open the .csv file that the script points to, the computers running the script will be unable to write to it while you have it open.
You might also notice that the conditional at Line 60 keeps the script from appending the Administrator and Guest accounts to the .csv report file. I chose to keep that information in the receipts but exclude it from the report so there was less noise since most of the computers would have the built-in Administrator and Guest accounts. You might expand the conditional to include some other wide-spread accounts or remove the conditional so you only have one place to look for all local user account information.
Now, I can analyze the file to see if there are any security concerns or accounts that should be Active Directory-based and not local accounts.