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

  1. Open the \My Documents\Microsoft Press\VBScriptSBS\Templates\wmiTemplate.vbs script in Notepad or your favorite script editor and save it as YourNameListServicesInProcesses.vbs.

  2. Comment out On Error Resume Next.

  3. 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"
  4. In the Header section of the script, declare a new variable to hold the process ID. Call this variable intPID.

  5. 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
  6. 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
  7. Store the value of the process ID in the variable intPID. This is seen below:

    intPID = objItem.ProcessID
  8. 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

    Figure 15-1 Taskmanager.exe view of processes and services; Svchost is comprised of several services.

  9. Create a subroutine called SubGetServices. This is seen below:

    ' *** subs are below ***
    
    Sub subGetServices
    
    End Sub
  10. 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
  11. 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
  12. 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)
  13. 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
  14. 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
  15. 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