Managing Desktop Administration using WSH and ADSI

By ServerWatch Staff (Send Email)
Posted Jun 24, 2002


by Marcin Policht


In his latest article, Marcin Policht presents a useful scripting approach to dealing with local user and group accounts in Windows NT 4.0. The script will renaming the local Administrator account, reset the password, list the membership of a specified local group, and add any number of global groups into the specified local group.


Delegation of Active Directory administration in Windows 2000 can be handled efficiently by granting different level of permissions on Active Directory objects. Similarly, by using restricted groups settings of group policies, you can ensure that privileged groups will contain only specific accounts (the procedure for configuring restricted groups is outlined in the Microsoft Knowledge Base article Q320065). You can also use group policies to alter the names of built-in accounts -- Administrator and Guest -- which is a common practice of security-concious administrators.

Even though this functionality exists in Active Directory domains, it requires that all servers and workstations have Windows 2000 (or later) operating system installed. In the meantime, there are still many environments running Windows NT 4.0. In such cases, dealing with local user and group accounts tends to be difficult and time consuming. For example, you might have a number of computers on which, over time, membership of the local Administrators group has been modified or the built-in Administrator account renamed and its password changed. Monitoring and reversing such changes, especially with a large number of computers, would not be something that you would want to perform manually.

Fortunately, scripting can once again help in automating such processes. The script that follows helps you accomplish the following:

  • Renaming the local Administrator account,
  • Resetting the password for this account to an arbitrarily chosen string,
  • Listing the membership of a local group you specified (this would typically be used for local Administrators or Power Users groups, but any other group name will work as well),
  • Adding any number of global groups into the specified local group (again, most often targeted at Administrators or Power Users, although can be used with any other local group)

The script runs against any number of computers, with the computer names listed (one name per line) in a separate text file called PCList.txt (although the file name can be easily changed by modifying value of the strPCFile variable).

Since a local Administrator account might have been previously renamed, the script does not rely on account names to locate it. Instead, its logic is based on the fact that the SID for Administrator's account is always equal to S-1-5--500. The last 3 decimal digits translate into 000001F4(hex), which in the little endian notation becomes F4010000. The SID is extracted by using functions available in ADsSecurity.dll. Prior to running the script, you will have to download this file from the Microsoft Web Site (it is part of ADSI 2.5 and Platform Software Development Kits) to your local machine and register it using regsvr32.exe. Registering can be done by copying ADsSEcurity.dll to %SystemRoot%\system32 folder and running the following from the Command Prompt:
regsvr32 ADsSecurity.dll

You should receive the confirmation of a successful registration in the form of a message box.

The script logs all of the activities in the file SetLocalAdmins.LOG (the file name can be easily changed by modifying the value of the strLogFile variable). Here is the content of a sample log file:


Started logging at 6/20/2002 8:00:00 PM

******************** Started processing PCTEST001 ********************

*** Enumerating accounts in Administrators group ***

Member of Administrators group: Administrator
SID of the account (if ending with F4010000 then it's local Administrator):
01050000000000051500000043170A327973DD0675B97554F4010000
*** Administrator Account Found ***
*** Administrator password reset ***
*** Administrator account renamed ***
Member of Administrators group: Marcin.Policht
Member of Administrators group: S-1-5-21-1993962763-413027322-1607980848-519
Member of Administrators group: Domain Admins
Member of Administrators group: Enterprise Admins

*** Adding global groups to Administrators group ***

*** Adding MyDomain\Desktop Admins to Administrators group ***
*** MyDomain\Desktop Admins added successfully to Administrators group ***
*** Adding MyDomain\Domain Admins to Administrators group ***
*** MyDomain\Domain Admins added successfully to Administrators group ***

******************** Finished processing PCTEST001 ********************

******************** Finished processing ********************

And below is the content of the script. Change the values of the variables strLocalGroup, strNewAdminName, strPassword, strPCFile, strLogFile, and strGlobalAdminGroups to match your requirements, save the modified contents as ManageLocal.vbs (or whatever other name you deem appropriate) and execute it by running:
cscript //nologo ManageLocal.vbs


Option Explicit
On Error Resume Next

'********************************************************************************************************
'*** SID for the Administrator's account is equal to S-1-5--500
'*** 500(decimal) translates into 000001F4(hex), which in the little endian notation becomes F4010000
'*** This value is stored in the HEX_500_LE constant
Const HEX_500_LE 		= "F4010000"
Const ADS_SID_WINNT_PATH	= 5
Const ADS_SID_HEXSTRING		= 1
Const NO_OVERWRITE 		= TRUE	'used by CreateTextFile of the FileSystemObject
Const FOR_READING		= 1	'used by Scripting.FileSystemObject methods
Const SEP			= 20	'used as separator in output listing

Dim strLocalGroup 		'name of local group whose membership is to be modified
				'		(e.g. "Administrators")
Dim objLocalGroup		'object representing local group whose membership is to be modified
Dim strNewAdminName		'new name to be assigned to local Administrator account
				'		(e.g. "SomeoneElse" in our example)
Dim strPassword			'new password to be set for local Administrator account
				'		(e.g. "Pa$$w0rd" in our example)
Dim strLogFile			'name of the file containing script logging information
Dim strPCFile			'name of the file containing list of target computers
Dim objLogFile			'object representing log file
Dim objPCFile			'object representing file containing list of target computers
Dim strGlobalAdminGroups	'semicolon-separated list of global groups to be added to the local group
				'each group is in form DOMAIN_NAME/GLOBAL_GROUP_NAME
Dim arrGlobalAdminGroups		'array of global groups to be added to the local group
				'each group is in form DOMAIN_NAME/GLOBAL_GROUP_NAME
Dim arrGlobalAdminGroup		'helper array containing two elements: domain name and global group name
Dim objUserEnv			'object used to access set of User environment variables
Dim strTempFolder		'name of the temporary folder (where the log file is stored)
Dim strComputer			'name of a target computer
Dim objComputer			'object representing the target computer
Dim blnAdminFound		'used to determine if the administrator's account has been found
Dim objLocalAdmin		'object representing member of the target local group
Dim objSID			'object referencing SID of the local Administrator account
Dim strSIDHex			'hexadecimal representation of the SID of the local Administrator account
Dim intCount			'loop counter
Dim objFSO, objShell		'Scripting.FileSystemObject and Wscript.Shell objects

strLocalGroup 			= "Administrators"
strNewAdminName 		= "SomeoneElse"
strPassword 			= "Pa$$w0rd"
strPCFile			= "PCList.txt"
strLogFile 			= "SetLocalAdmins.LOG"
strGlobalAdminGroups 		= "MyDomain\Desktop Admins;MyDomain\Domain Admins"
arrGlobalAdminGroups 		= Split(strGlobalAdminGroups,";")

'********************************************************************************************************
'***  create log file in the TEMP folder

Set objFSO	= CreateObject("Scripting.FileSystemObject")
Set objShell 	= CreateObject("WScript.Shell")
Set objUserEnv 	= objShell.Environment("USER")
strTempFolder 	= objShell.ExpandEnvironmentStrings(objUserEnv("TEMP"))
Set objLogFile 	= objFSO.CreateTextFile(strTempFolder & "\" & strLogFile, NO_OVERWRITE)

If Err.Number <> 0 Then
	WScript.Echo "Failed to create the log file. Terminating ..."
	WScript.Quit
End If

objLogFile.WriteLine("Started logging at " & Now())
objLogFile.WriteLine()

'********************************************************************************************************
'***  open file containing list of PC names

Set objPCFile 	= objFSO.OpenTextFile(strPCFile, FOR_READING)

If Err.Number <> 0 Then
	WScript.Echo "Failed to access the PC listing file. Terminating ..."
	WScript.Quit
End If

'********************************************************************************************************
'***    for each PC listed in the file :
'*** 	rename local admin account,
'*** 	change password,
'*** 	add global groups to the local group

Do While NOT objPCFile.AtEndOfStream
    strComputer = objPCFile.ReadLine
    blnAdminFound = FALSE		'indicates whether local Administrator account has been found

    WScript.Echo String(SEP,"*") & " Started processing " & strComputer & " " & String(SEP,"*")
    objLogFile.WriteLine String(SEP,"*") & " Started processing " & strComputer & " " & String(SEP,"*")
    objLogFile.WriteLine()

'********************************************************************************************************
'*** Enumerate local admin accounts

    Set objLocalGroup = GetObject("WinNT://" & strComputer & "/" & strLocalGroup)

    objLogFile.WriteLine("*** Enumerating accounts in " & strLocalGroup & " group ***")
    objLogFile.WriteLine()

    For Each objLocalAdmin In objLocalGroup.Members

	objLogFile.WriteLine("Member of " & strLocalGroup & " group: " & objLocalAdmin.Name)

	'****************************************************************************************************
	'*** Get SID Information, based on it find local Administrator account
	'*** SID for the Admistrator's account is equal to S-1-5--500

	If (NOT blnAdminFound) Then

	    Set objSID = CreateObject("ADsSID")
	    objSID.SetAs ADS_SID_WINNT_PATH, "WinNT://" & strComputer & "/" & _
						objLocalAdmin.Name & ",user"
	    strSIDHex = objSID.GetAs(ADS_SID_HEXSTRING)

	    objLogFile.WriteLine("SID of the account (if ending with F4010000 then " & _
				"it's local Administrator): " & vbCrLF & strSIDHex)

	    If (strComp(Right(strSIDHex, 8), HEX_500_LE, vbTextCompare) = 0) Then

		objLogFile.WriteLine("*** Administrator Account Found ***")

		'************************************************************************************************
		'*** Reset the password for the local Administrator account

		objLocalAdmin.SetPassword(strPassword)

		If Err.Number = 0 Then
			objLogFile.WriteLine("*** Administrator password reset ***")
		Else
			objLogFile.WriteLine("*** Problems resetting Administrator password ***")
			objLogFile.WriteLine("*** Error :" & Err.Number & " " & Err.Description & " ***")
		End If
		'************************************************************************************************
		'*** Rename the username to Administrator

		Set objComputer = GetObject("WinNT://" & strComputer)
		objComputer.MoveHere objLocalAdmin.AdsPath, strNewAdminName

		If Err.Number = 0 Then
			objLogFile.WriteLine("*** Administrator account renamed ***")
		Else
			objLogFile.WriteLine("*** Problems renaming Administrator account ***")
			objLogFile.WriteLine("*** Error :" & Err.Number & " " & Err.Description & " ***")
		End If

		blnAdminFound = TRUE

	    End If
	End If
    Next

    '****************************************************************************************************
    '*** Add global groups to local Administrators

    objLogFile.WriteLine()
    objLogFile.WriteLine("*** Adding global groups to " & strLocalGroup & " group ***")
    objLogFile.WriteLine()

    For intCount = 0 To UBound(arrGlobalAdminGroups)

	objLogFile.WriteLine("*** Adding " & arrGlobalAdminGroups(intCount) & " to " & _
							strLocalGroup & " group ***")

	arrGlobalAdminGroup = split(arrGlobalAdminGroups(intcount), "\")

	objLocalGroup.Add("WinNT://" & arrGlobalAdminGroup(0) & "/" & arrGlobalAdminGroup(1))

	If Err.Number = 0 Then
		objLogFile.WriteLine("*** " & arrGlobalAdminGroups(intCount) & _
			" added successfully to " & strLocalGroup & " group ***")
	Else
		Set objGroup = GetObject("WinNT://" & arrGlobalAdminGroup(0) & "/" & _
								arrGlobalAdminGroup(1))
		If objGroup.IsMember(objLocalGroup.aDSPath) Then
			objLogFile.WriteLine("*** The group " & arrGlobalAdminGroups(intCount) &
_
					" is already a member of " & strLocalGroup & " group ***")
		Else
			objLogFile.WriteLine("*** Problems adding " & arrGlobalAdminGroups(intCount) & _
					" to " & strLocalGroup & " group ***")
			objLogFile.WriteLine("*** Error :" & Err.Number & " " & Err.Description & " ***")
		End If
	End If

    Next

    WScript.Echo String(SEP,"*") & " Finished processing " & strComputer & " " & String(SEP,"*")
    objLogFile.WriteLine()
    objLogFile.WriteLine(String(SEP,"*") & " Finished processing " & strComputer & " " & String(SEP,"*"))
    objLogFile.WriteLine()

Loop

objLogFile.WriteLine(String(SEP,"*") & " Finished processing " & String(SEP,"*"))

objLogFile.Close
objPCFile.Close


Page 1 of 1


Comment and Contribute

Your name/nickname

Your email

(Maximum characters: 1200). You have characters left.