Leveraging Sample Scripts


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 Policies

The 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).

[View full width]

Dim GP(10000,2) Set FSO = CreateObject("Scripting.FileSystemObject") Set oGPList = FSO.OpenTextFile("OrphanGP.txt",2,True) Set RootDSE = GetObject("LDAP://RootDSE") DomainNC = RootDSE.Get("RootDomainNamingContext") Set con = CreateObject("ADODB.Connection") con.Provider = "ADsDSOObject" con.Open "DS Query" Set command = CreateObject("ADODB.Command") Set command.ActiveConnection = con Command.Properties("searchscope") = 2 wscript.echo "Retrieving list of all containers in the domain..." command.CommandText = "select GPLink,Name,ADsPath from 'LDAP://" & DomainNC & "' where objectclass='organizationalunit' or objectclass='container' or objectclass='site' or objectclass='domain'" Set rs = Command.Execute wscript.echo "Creating list of all assigned Group Policy objects..." i = 0 Do While NOT rs.EOF tempGPLink = rs.Fields("GPLink") GPList = ParseGPLink(tempGPLink) 'GPList returns a Tab-separated string 'Split() function parses the string and returns an array GPArray = Split(GPList,vbTab) For j = 0 To UBound(GPArray) GP(i,0) = "{" & Split(GPList,vbTab)(j) & "}" GP(i,1) = rs.Fields("ADsPath") i = i + 1 Next rs.MoveNext Loop Ngp = i wscript.echo "Retrieving list of all Group Policy objects..." command.CommandText = "select cn,DisplayName,name from 'LDAP://" & DomainNC & " ' where objectclass='GroupPolicyContainer'" Set rs = Command.Execute wscript.echo "Detecting orphan Group Policy objects..." Do While NOT rs.EOF GPName = rs.Fields("DisplayName") If TypeName(GPName) = "String" Then OUFound = False 'Searching for a GP in the array of all assigned GPs created in the previous step 'It would be more efficient to use a Dictionary object instead of array, 'but for arrays of this size the performance difference is not significant For i = 0 to Ngp - 1 If rs.Fields("name") = GP(i,0) Then OUFound = True End If Next If NOT OUFound Then wscript.echo GPName oGPList.WriteLine GPName & vbTab & rs.Fields("cn") End If End If rs.MoveNext Loop Function ParseGPLink(GPLink) 'GPLink attribute can contain links to multiple group policies: '"[LDAP://CN={217E2467-F743-4300-812C-2F87FBF9AFD3},CN=Policies,CN=System, DC=mydomain ,DC=com;2][LDAP://CN={3CEF68F7-0201-407F-87E9-DF6CF8255E2D}, CN=Policies,CN=System,mydomain=domain-name,DC=com;0]" 'This function reformats the value to make it a Tab-separated string: '"217E2467-F743-4300-812C-2F87FBF9AFD3 3CEF68F7-0201-407F-87E9-DF6CF8255E2D" 'Strings like that are much easier to work with Dim j, TempArray ParseGPLink = "" If TypeName(GPLink) = "String" AND Trim(GPLink) <> "" Then TempArray = Split(GPLink,"{") For j = 1 To UBound(TempArray) ParseGPLink = ParseGPLink & Left(TempArray(j), InStr(TempArray(j),"}") - 1) & vbTab Next ParseGPLink = Left(ParseGPLink, Len(ParseGPLink)-1) End If End Function


Scanning for Installed Software Components

Many 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 Membership

The 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 Printers

The 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:

  • Local printers (connected to Win9x and other client OS computers) are skipped.

  • The script uses LDAP query to create a recordset of all servers in the domain.

  • Another query is used to find all printers for every server.

  • The script uses WMI to bind to Win32_Printer objects.

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 File

The 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 Space

The 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 





Microsoft Windows Server 2003 Unleashed(c) R2 Edition
Microsoft Windows Server 2003 Unleashed (R2 Edition)
ISBN: 0672328984
EAN: 2147483647
Year: 2006
Pages: 499

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net