In the following sections, we've included a few sample scripts that leverage and combine some of the interfaces and object models referenced throughout this chapter. These scripts are ready to run if you type them in as shown. However, these scripts do query and return values from the entire domain, so you should test these scripts in an isolated lab environment or scale down and modify the scripts as necessary. Finding Orphaned Group PoliciesThe following script searches for Group Policies that are not linked to any specific container in a domain or are otherwise orphaned. It can be saved as a .vbs script (for example, OrphanedGP.vbs).
Scanning for Installed Software ComponentsMany times administrators need to quickly and easily scan a computer or group of computers to determine whether or not a specific software component has been installed. Although the following script scans for Macromedia Flash Player, it can also be used to scan for computers with a specific update installed. For instance, you can change the Query variable: Query = "SELECT * FROM Win32_QuickFixEngineering WHERE HotFixID='Q329115'" (where Q329115 is the update you are looking for). Set RootDSE = GetObject("LDAP://RootDSE") DomainNC = RootDSE.Get("RootDomainNamingContext") Set ws = CreateObject("WScript.Shell") Set FSO = CreateObject("Scripting.FileSystemObject") Set oSoftwareScan = FSO.OpenTextFile("SoftwareScan.csv",2,True) Set con = CreateObject("ADODB.Connection") con.Provider = "ADsDSOObject" con.Open "DS Query" Set command = CreateObject("ADODB.Command") Set command.ActiveConnection = con Command.Properties("Sort on") = "cn" Command.Properties("searchscope") = 2 command.CommandText = "select cn,ADsPath from 'LDAP://" & DomainNC & " ' where objectclass='computer' and operatingsystem='Windows 2000 Professional'" Set rs = command.Execute Query = "SELECT * FROM Win32_Product WHERE Name='Macromedia Flash Player'" Do While NOT rs.EOF ComputerName = rs.Fields("cn") Version = "" If Online(ComputerName) Then Set WMIRef = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & ComputerName) Set colProducts = WMIRef.ExecQuery(Query) Status = "Not installed" For Each oProduct In colProducts Version = oProduct.Version Status = "Installed" Next Else Status = "Offline" End If wscript.echo ComputerName & vbTab & Status & vbTab & Version oSoftwareScan.WriteLine ComputerName & "," & Status & "," & Version ComputerName = Null Status = Null rs.MoveNext Loop oSoftwareScan.Close Function Online(HostName) 'Shell ping command is used here to determine whether the computer is online 'It's done this way only for the purpose of compatibility with Windows 2000 'Win32_PingStatus class is available for Windows Server 2003 and should be used instead Dim ReturnCode, Results, Line Online = False Returncode = ws.Run("%comspec% /c ping " & HostName & ".domain-name.com -n 1 -w 500 > ping.tmp",0,"True") set Results = fso.OpenTextFile("ping.tmp",1,False) Do While NOT Results.AtEndOfStream Line = Results.ReadLine If (InStr(Line, "Reply from") > 0) AND (InStr(Line, "unreachable") = 0) Then Online = True End If Loop Results.Close Set Results = Nothing FSO.DeleteFile "ping.tmp" End Function Checking Local Group MembershipThe following script determines local group membership. The script first finds the computer object in Active Directory and then it analyzes group membership of that object by finding the group whose name includes the "-Computers" substring. For example, if a group named "Marketing-Computers" exists, it indicates that the computer belongs to the Marketing department. The script then enumerates members of the local Administrators group to determine whether the Marketing-Admins group is already a member of the local Administrators group. If it isn't, then the script adds it in there. The script also contains code to write Application log events if the group is added and whether or not critical errors occurred. Another important piece of this script is the section of code containing the Option Explicit and declared variables. This is a good habit to practice with all scripts even though all the examples in this chapter do not contain them. Option Explicit enforces variable declaration. Option Explicit Dim RootDSE, DomainNC, ws, WNetwork, CompName, Department Dim AdminGroup, AdminGroupFound, oUser, oGroup on error resume next Const EventERROR = 1, EventWARNING = 2, EventINFORMATION = 4 Set RootDSE = GetObject("LDAP://RootDSE") DomainNC = RootDSE.Get("RootDomainNamingContext") Set ws = CreateObject("WScript.Shell") Set WNetwork = Wscript.CreateObject("WScript.Network") CompName = WNetwork.ComputerName 'Determining department where the computer account belongs Department = GetDepartment(CompName) If Department <> "" Then AdminGroup = Department & "-Admins" Else AdminGroup = "IT-Admins" 'if the computer is not a member of any XXX-Computers group, then it should be managed by IT End If 'Enumerating members of the local Administrators group Set oGroup = GetObject("WinNT://" & CompName & "/Administrators,group") AdminGroupFound = False For Each oUser in oGroup.Members If oUser.Name = AdminGroup Then AdminGroupFound = True End If Next If Err.Number <> 0 Then 'creating an event in the Application log and exiting the script ws.Logevent EventERROR, "Error occurred while enumerating members of the local Administrators group" wscript.quit End If 'Adding Admin group only if it wasn't found in the local Administrators group If NOT AdminGroupFound Then oGroup.Add "WinNT://" & AdminGroup & ",group" If Err.Number <> 0 Then ws.Logevent EventERROR, "Error occurred while adding group " & AdminGroup & " into the local Administrators group" Else ws.Logevent EventINFORMATION, "Successully added group " & AdminGroup & " into the local Administrators group" End If End If Set oGroup = Nothing Set ws = Nothing Set WNetwork = Nothing Function GetDepartment(ComputerName) Dim oConnection, oCommand, rs, MemberOf, oGroup, oComputer, i Set oConnection = CreateObject("ADODB.Connection") oConnection.Provider = "ADsDSOObject" oConnection.Open "DS Query" Set oCommand = CreateObject("ADODB.Command") Set oCommand.ActiveConnection = oConnection oCommand.Properties("searchscope") = 2 oCommand.CommandText = "Select ADsPath,cn From 'LDAP://" & DomainNC & " ' Where name='" + ComputerName + "' and objectclass='computer'" Set rs = oCommand.Execute GetDepartment = "" If NOT rs.EOF Then Set oComputer = GetObject(rs.Fields("ADsPath")) MemberOf = oComputer.GetEx("memberOf") If Err.Number <> 0 Then 'MemberOf attribute is not populated (the object is not a member of any group) Err.Clear Exit Function End If If TypeName(MemberOf) = "String" Then 'MemberOf attribute is single-valued (the object is a member of a single group) Set oGroup = GetObject("LDAP://" & MemberOf) If Instr(oGroup.cn,"-Computers") > 0 Then GetDepartment = Left(oGroup.cn, Len(oGroup.cn) - 10) End If Else 'MemberOf attribute is multi-valued (the object is a member of multiple groups) For i = 0 To UBound(MemberOf) Set oGroup = GetObject("LDAP://" & MemberOf(i)) If Instr(oGroup.cn,"-Computers") > 0 Then GetDepartment = Left(oGroup.cn, Len(oGroup.cn) - 10) Exit For End If Set oGroup = Nothing Next End If End If End Function Locating Domain PrintersThe following script creates a list of all printers in Active Directory and outputs the information gathered in a text file called AllPrinters.csv. Here is some other pertinent information:
The full script is as follows: Option Explicit Dim RootDSE, DomainDN, FSO, oFullLog, oConnection, oCommand, rsServers, rsPrinters Dim Sep, PrintServer, oPrinter Set RootDSE = GetObject("LDAP://RootDSE") DomainDN = RootDSE.Get("RootDomainNamingContext") Set FSO = CreateObject("Scripting.FileSystemObject") Set oFullLog = FSO.OpenTextFile("AllPrinters.csv", 2, True) Set oConnection = CreateObject("ADODB.Connection") oConnection.Provider = "ADsDSOObject" oConnection.Open "DS Query" Set oCommand = CreateObject("ADODB.Command") Set oCommand.ActiveConnection = oConnection oCommand.Properties("searchscope") = 2 oCommand.Properties("Sort on") = "cn" oCommand.CommandText = "Select cn,ADsPath from 'LDAP://" & DomainDN & "' Where objectClass='computer' and OperatingSystem= 'Windows 2000 Server' OR OperatingSystem='Windows Server 2003'" Set rsServers = oCommand.Execute Sep = Chr(34) & "," & Chr(34) On Error Resume Next Do While NOT rsServers.EOF PrintServer = False oCommand.CommandText = "Select PrinterName,cn from '" & rsServers.Fields("ADsPath") & "' where objectClass='printQueue'" Set rsPrinters = oCommand.Execute Do While NOT rsPrinters.EOF If NOT PrintServer Then Wscript.echo rsServers.Fields("cn") PrintServer = True End If Set oPrinter = GetObject("winmgmts:{impersonationLevel=impersonate}! \\" & rsServers.Fields("cn") & "\root\cimv2:Win32_Printer.DeviceID= " & Chr(34) & rsPrinters.Fields("PrinterName") & Chr(34)) Wscript.echo vbTab & rsPrinters.Fields("PrinterName") & vbTab & txtPrinterStatus(oPrinter.PrinterStatus) oFullLog.WriteLine Chr(34) & rsServers.Fields("cn") & Sep & rsPrinters.Fields("PrinterName") & Sep & oPrinter.DriverName & Sep & oPrinter.Location & Sep & oPrinter.Description & Sep & txtPrinterStatus(oPrinter.PrinterStatus) & Chr(34) Set oPrinter = Nothing rsPrinters.MoveNext Loop Set rsPrinters = Nothing rsServers.MoveNext Loop Set rsServers = Nothing Set oCommand = Nothing Set oConnection = Nothing oFullLog.Close Set oFullLog = Nothing Set FSO = Nothing Set RootDSE = Nothing Function txtPrinterStatus(PrinterStatus) Select Case PrinterStatus Case 1 : txtPrinterStatus = "Other" Case 2 : txtPrinterStatus = "Unknown" Case 3 : txtPrinterStatus = "Idle" Case 4 : txtPrinterStatus = "Printing" Case 5 : txtPrinterStatus = "Warmup" Case Else txtPrinterStatus = "Unknown Status" End Select End Function Creating Users from Data in a CSV FileThe following script creates users in the Users container in Active Directory. The script reads data for user creation in a Users.csv file. The file header defines attributes that will be populated. Only two attributes are mandatory: SamAccountName (also called the logon name) and CN (the canonical name). All other attributes are optional, including the password. The sample data used for this script would appear as follows if the Users.csv file were opened in Notepad: SamAccountName,CN,GivenName,SN,Initials,Password jsmith,John Smith,John,Smith,T,mysecretpassword brobinson,Bob Robinson,Bob,Robinson,K,mysecretpassword Attribute names should be specified exactly as they are defined in the Active Directory schema. Probably the best tool to determine which attributes should be specified is the ADSI Edit tool. If the script fails to create a user, an error message appears. Usually, errors are caused by an invalid attribute value or by the fact that a user with the same SamAccountName already exists in the domain. If at least one of the fields is specified incorrectly, an error will be reported for all users. Finally, all users are enabled after the creation. The full script is as follows: Option Explicit Dim RootDSE, DomainDN, oContainer, FSO, oUserList Dim Line, Header, SamaccountnameIndex, CnIndex, PasswordIndex, AttributeValue, oUser, i Set RootDSE = GetObject("LDAP://RootDSE") DomainDN = RootDSE.Get("RootDomainNamingContext") Set oContainer = GetObject("LDAP://CN=Users," + DomainDN) Set FSO = CreateObject("Scripting.FileSystemObject") Set oUserList = FSO.OpenTextFile("Users.csv",1,False) on error resume next Line = LCase(oUserList.ReadLine) Header = Split(Line,",") SamaccountnameIndex = -1 CnIndex = -1 PasswordIndex = -1 For i = LBound(Header) To UBound(Header) If Header(i) = "samaccountname" Then SamaccountnameIndex = i ElseIf Header(i) = "cn" Then CnIndex = i ElseIf Header(i) = "password" Then PasswordIndex = i End If Next If SamaccountnameIndex = -1 OR CnIndex = -1 Then Wscript.echo "Incorrect header. One of the mandatory fields is missing." wscript.quit End If Do While NOT oUserList.AtEndOfStream Line = oUserList.ReadLine AttributeValue = Split(Line,",") Wscript.echo AttributeValue(CnIndex) set oUser = oContainer.Create("user","cn="& AttributeValue(CnIndex)) oUser.samAccountName = AttributeValue(SamAccountNameIndex) oUser.SetInfo If Err.Number <> 0 Then Wscript.echo vbTab + "Error occurred while creating the user" Else Wscript.echo vbTab + "User created successfully" For i = LBound(Header) To UBound(Header) If i <> CnIndex AND i <> SamaccountnameIndex AND i <> _ PasswordIndex Then oUser.Put Header(i),AttributeValue(i) ElseIf i = PasswordIndex Then oUser.SetPassword AttributeValue(i) End If Next oUser.AccountDisabled = False oUser.SetInfo If Err.Number <> 0 Then Wscript.echo vbTab + "Error occurred while setting user properties" Err.Clear Else Wscript.echo vbTab + "User properties were set successfully" End If End If Set oUser = Nothing Line = Null AttributeValue = Null Loop oUserList.Close Set oUserList = Nothing Set FSO = Nothing Set RootDSE = Nothing Checking Domain Servers for Volume Free SpaceThe following script expands on the sample WMI script outlined earlier in this chapter. The script scans all Windows 2000 and Windows Server 2003 servers in a domain and reports free space and total capacity (in megabytes and percents) on every logical drive. The script uses LDAP query to create a recordset of all servers in the domain. It also uses Windows Management Instrumentation to demonstrate usage of this technology, but the same information can also be collected using the File System Object model. Option Explicit Dim oRootDSE, DomainDN, FSO, oLogFile, oConnection, oCommand, rsServers Dim ComputerName, oWMIService, colDisks, oDisk Dim PercentFree Set oRootDSE = GetObject("LDAP://RootDSE") DomainDN = oRootDSE.Get("RootDomainNamingContext") Set FSO = CreateObject("Scripting.FileSystemObject") Set oLogFile = FSO.OpenTextFile("FreeSpace.csv",2,True) Set oConnection = CreateObject("ADODB.Connection") oConnection.Provider = "ADsDSOObject" oConnection.Open "DS Query" Set oCommand = CreateObject("ADODB.Command") Set oCommand.ActiveConnection = oConnection oCommand.Properties("searchscope") = 2 oCommand.CommandText = "Select ADsPath,cn From 'LDAP://" & DomainDN & _ "' Where objectClass='computer' and OperatingSystem='Windows 2000 Server' OR OperatingSystem='Windows Server 2003'" Set rsServers = oCommand.Execute On Error Resume Next Do While NOT rsServers.EOF ComputerName = rsServers.fields("cn").value Wscript.echo ComputerName Set oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}! \\" & ComputerName & "\root\cimv2") Set colDisks = oWMIService.ExecQuery ("Select * from Win32_LogicalDisk") For Each oDisk In colDisks If oDisk.DriveType = 3 Then 'Local Hard Drive PercentFree = Round(oDisk.FreeSpace/oDisk.Size*100) Wscript.echo oDisk.Name & vbTab & _ CStr(Round(oDisk.FreeSpace/1048576)) & "/" & _ CStr(Round(oDisk.Size/1048576)) & vbTab & CStr(PercentFree) & "%" oLogFile.WriteLine ComputerName & "," & oDisk.Name & "," & CStr(Round(oDisk.FreeSpace/1048576)) & "," & _ CStr(Round(oDisk.Size/1048576)) & "," & CStr(PercentFree) End If Next If Err.Number <> 0 Then Wscript.echo "Error while collecting information from " & ComputerName Err.Clear End If Set oWMIService = Nothing Set colDisks = Nothing rsServers.MoveNext Loop Set rsServers = Nothing Set oCommand = Nothing Set oConnection = Nothing oLogFile.Close Set oLogFile = Nothing Set FSO = Nothing |