Using Subroutines and Functions in Microsoft VBScript
- 12/29/2006
Header Information
The Header information section of CreateUsersLogAction.vbs is used to declare all the variables used in the script. Thirteen variables are used in the script. The variable i is a simple counter and is not listed in Table 15-1 with the other variables.
Table 15-1 Variables Used in CreateUsersLogAction.vbs
Variable |
Description |
objOU |
Holds connection to target OU in Active Directory. |
objUser |
Holds hook for Create user command; takes TxtIn(0) as input for user name. |
objGroup |
Holds hook for the add command; takes TxtIn(1) as input for name of group and TxtIn(0) as name of user to add. |
objFSO |
Holds hook that comes back from the CreateObject command used to create the FileSystemObject. |
objFile |
Holds hook that comes back from the OpenTextFile command issued to objFSO. |
objFolder |
Holds hook that comes back from the CreateFolder command issued to objFSO if the folder does not exist. |
objTextFile |
Holds the data stream that comes from the OpenTextFile command that is used to open the UsersAndGroups.txt file. |
TxtIn |
An array that is created from parsing strNextLine. Each field split by the comma becomes an element in the array. Holds user name to be created and the group that the user is to be added to. |
strNextLine |
Holds one line worth of data from the UsersAndGroups.txt file. |
TxtFile |
Holds path and name of text file to be parsed as input data. |
LogFolder |
Holds path and name of folder used to hold logging information. |
LogFile |
Holds path and name of text file to be used as the log file. |
Reference Information
The Reference information section of the script is used to assign values to some of the variables in the script. In addition to the mundane items such as defining the path and title for the text file used to hold the users and groups, in this section, you create three constants that are used in working with text files.
These constants are ForReading, ForWriting, and ForAppending. The use of these constants was discussed in detail in Chapter 4, “Working with Arrays.” The last two tasks done in the Reference information section of the script are creating an instance of the FileSystemObject and using the OpenTextFile command so that you can read it in the list of users that need to be created and the group to which each user will be assigned. Here is the Reference information section of the script:
TxtFile = "C:\UsersAndGroups.txt" LogFolder = "C:\FSO" LogFile = "C:\FSO\fso.txt" Const ForReading = 1 Const ForWriting = 2 Const ForAppending = 8 Set objFSO = CreateObject("Scripting.FileSystemObject") Set objTextFile = objFSO.OpenTextFile _ (TxtFile, ForReading)
Worker Information
The Worker information section of the script is where the users are actually created and assigned to a group. To work through the UsersAndGroups.txt file, you need to make a connection to the file. This was done in a previous Reference information section of the script, in which we assigned objTextFile to be equal to the hook that came back once the connection into the file was made. Think back to the pipe analogy (in Chapter 5, “More Arrays”), in which you set up a pump and pulled the text, one line at a time, into a variable called strNextLine. As long as data is in the text file, you can continue to pump the information by using the ReadLine command. However, if you reach the end of the text stream, you exit the Do Until...Loop statement you created.
Do Until objTextFile.AtEndOfStream strNextLine = objTextFile.ReadLine TxtIn = Split(strNextLine , ",") Set objOU = GeCreateUsersLogAction.vbstObject("LDAP://OU=Mred," _ & "dc=nwtraders,dc=msft") Set objUser = objOU.Create("User", "cn="& TxtIn(0)) objUser.Put "sAMAccountName", TxtIn(0) objUser.SetInfo Set objGroup = GetObject _ ("LDAP://CN="& TxtIn(1) & ",cn=users," _ & "dc=nwtraders,dc=msft") objGroup.add _ "LDAP://cn="& TxtIn(0) & ",ou=Mred," _ & "dc=nwtraders,dc=msft" Logging Loop
Output Information
Once you create a new user and assign that user to a group, you need to log the script changes. To do this, you call a subroutine (in our script, called Logging) that opens a log file and writes the name of the new user that was created as well as the time in which the creation occurred. The first task the Logging subroutine does is check for the existence of the logging folder that is defined by the variable LogFolder. To check for the presence of the folder, you use the FolderExists method. If the folder is present on the system, you next check for the existence of the logging file defined by the LogFile variable. To check for the presence of the logging file, you use the FileExists method. If both of these conditions are copasetic, you open the log file by using the OpenTextFile command and specify that you will append to the file instead of overwriting it (which is normally what you want a log file to do). In writing to the file, you use two different methods: WriteBlankLines to make the log a little easier to read, and WriteLine to write the user name and the time that user was created in the log.
If, on the other hand, the log folder exists but the log file does not exist, you need to create the log file prior to writing to it. This is the subject of the first Else command present in the subroutine. You use the CreateTextFile command and the LogFile variable to create the log file. After the file is created, you must close the connection to the file; if you do not, you get an error message stating that the file is in use. After you close the connection to the log file, you reopen it by using the OpenTextFile command, and then you write your information to the file.
The other scenario our subroutine must deal with is if neither the folder nor the log file is in existence, in which case you have to create the folder (by using the CreateFolder method) and then create the file (by using the CreateTextFile method). It is necessary to use objFile.Close to close the connection to the newly created text file so that you can write your logging information to the file. Once you write to the log file, you exit the subroutine by using the End Sub command, and you enter Do Until...Loop again. The Logging subroutine is shown here:
Sub Logging If objFSO.FolderExists(LogFolder) Then If objFSO.FileExists(LogFile) Then Set objFile = objFSO.OpenTextFile _ (LogFile, ForAppending) objFile.WriteBlankLines(1) objFile.WriteLine "Creating User " & Now objFile.WriteLine TxtIn(0) objFile.Close Else Set objFile = objFSO.CreateTextFile(LogFile) objFile.Close Set objFile = objFSO.OpenTextFile _ (LogFile, ForWriting) objfile.WriteLine "Creating User " & Now objFile.WriteLine TxtIn(0) objFile.Close End If Else Set objFolder = objFSO.CreateFolder(LogFolder) Set objFile = objFSO.CreateTextFile(LogFile) objFile.Close Set objFile = objFSO.OpenTextFile _ (LogFile, ForWriting) objfile.WriteLine "Creating User " & Now objFile.WriteLine TxtIn(0) objFile.Close End If End Sub WScript.Echo("all done")
Using a subroutine to retrieve service information from WMI
Open the \My Documents\Microsoft Press\VBScriptSBS\Templates\wmiTemplate.vbs script in Notepad or your favorite script editor and save it as YourNameListServicesInProcesses.vbs.
Comment out On Error Resume Next.
Edit the wmiQuery line so that you are selecting only processID and the name from win32_Process. You want to, however, exclude the process ID that equals 0. This query will look like the following:
wmiQuery = "Select processID, name from win32_Process where processID <> 0"
In the Header section of the script, declare a new variable to hold the process ID. Call this variable intPID.
Inside the For Each...Next loop, delete all the WScript.Echo “:” & objItem lines except for one. The completed For Each...Next loop will look like the following:
For Each objItem in colItems WScript.Echo ": " & objItem. Next
Modify the WScript.Echo line so that it prints out the name and the processed properties from the win32_Process class. Include labels with each property to identity each of the properties as belonging to a process. My code to do this looks like the following:
WScript.Echo "Process Name: " & objItem.Name & " ProcessID: " & objItem.ProcessID
Store the value of the process ID in the variable intPID. This is seen below:
intPID = objItem.ProcessID
Save and run YourNameListServicesInProcesses.vbs. There should be no errors at this point, and you should see an output similar to the following (of course your list of processes will be different). The process names and the process IDs seen in the output from your script will compare to the ones seen in Taskmanager.exe (refer to Figure 15-1).
Process Name: System ProcessID: 4 Process Name: smss.exe ProcessID: 776 Process Name: csrss.exe ProcessID: 868 Process Name: winlogon.exe ProcessID: 892 Process Name: services.exe ProcessID: 940 Process Name: lsass.exe ProcessID: 952 Process Name: svchost.exe ProcessID: 1136 Process Name: svchost.exe ProcessID: 1228 Process Name: svchost.exe ProcessID: 1352 Process Name: spoolsv.exe ProcessID: 1640 Process Name: explorer.exe ProcessID: 832 Process Name: wmiprvse.exe ProcessID: 632 Process Name: wmiprvse.exe ProcessID: 1436 Process Name: WINWORD.EXE ProcessID: 3764 Process Name: svchost.exe ProcessID: 2428 Process Name: PrimalScript.exe ProcessID: 2872 Process Name: cscript.exe ProcessID: 584 Process Name: wmiprvse.exe ProcessID: 3652
Figure 15-1 Taskmanager.exe view of processes and services; Svchost is comprised of several services.
Create a subroutine called SubGetServices. This is seen below:
' *** subs are below *** Sub subGetServices End Sub
Inside your new subroutine, declare three variables that will be used in the secondary Windows Management Instrumentation (WMI) query. One variable will contain the query, one will contain the collection returned by the query, and one will hold the individual service instances retrieved from the collection. The three variables you want to declare correspond to the variables used in the main body of the script: wmiQuery1, colItems1, objItem1.
Dim wmiQuery1 Dim colItems1 Dim objItem1
Under the new variables you declared in the subroutine, assign a new query to wmiQuery1 that selects the name from WIN32_Service, where processID is the same as the one stored in intPID. This query will look like the following:
wmiQuery1 = "Select name from win32_Service where processID = " & intPID
On the line following wmiQuery1, use the colItems1 variable to hold the collection that is returned by using the execQuery method to execute the query contained in wmiQuery1. This code will look like the following:
Set colItems1 = objWMIService.ExecQuery(WmiQuery1)
Use For Each...Loop to walk through colItems1. Use WScript.Echo to print out the name of each service that corresponds to the query defined in wmiQuery1. This is seen below:
For Each objItem1 In colItems1 WScript.Echo vbTab, "Service Name: ", objItem1.Name Next
In the main body of the script, after the line where the process ID is assigned to intPID, call the subroutine you just created. The placement of the call to subGetServices is seen below:
intPID = objItem.ProcessID subGetServices
Save and run your script. You should see a printout that now lists services running inside processes. Compare your results with the listing below. If you do not see something like this (realizing the processes and services will be different), compare your script with \My Documents\Microsoft Press\VBScriptSBS\ch15\ListServicesIn Processes.vbs.
Process Name: System ProcessID: 4 Process Name: smss.exe ProcessID: 776 Process Name: csrss.exe ProcessID: 868 Process Name: winlogon.exe ProcessID: 892 Process Name: services.exe ProcessID: 940 Service Name: Eventlog Service Name: PlugPlay Process Name: lsass.exe ProcessID: 952 Service Name: ProtectedStorage Service Name: SamSs Process Name: svchost.exe ProcessID: 1136 Service Name: DcomLaunch Process Name: svchost.exe ProcessID: 1228 Service Name: RpcSs Process Name: svchost.exe ProcessID: 1352 Service Name: AudioSrv Service Name: CryptSvc Service Name: EventSystem Service Name: Nla Service Name: RasMan Service Name: SENS Service Name: ShellHWDetection Service Name: TapiSrv Service Name: winmgmt Process Name: spoolsv.exe ProcessID: 1640 Service Name: Spooler Process Name: explorer.exe ProcessID: 832 Process Name: wmiprvse.exe ProcessID: 632 Process Name: wmiprvse.exe ProcessID: 1436 Process Name: WINWORD.EXE ProcessID: 3764 Process Name: svchost.exe ProcessID: 2428 Service Name: stisvc Process Name: wmplayer.exe ProcessID: 172 Process Name: Dancer.exe ProcessID: 1180 Process Name: PrimalScript.exe ProcessID: 1920 Process Name: wmiprvse.exe ProcessID: 3156 Process Name: cscript.exe ProcessID: 3468