Logon Scripts and Scheduling

Overview

The Ability to Execute Logon scripts has always been available in the Windows NT networked environment. The scripts relied on batch files, which could perform operations such as connecting to network resources and file operations.

Although you can connect to a networked resource by using a batch file, there is not a way for you to check if you're already connected or for you to test for a specific condition. Batch files cannot perform operations such as checking user group membership or enumerating shared drives and printers.

Batch files provide a very primitive method of using environment variables, simplistic flow control, and limited error handling. Furthermore, they are not very expandable, and they are limited to the command-line programs on the system.

Windows Script Host (WSH) changes all of this. WSH has native support for enumeration and manipulation of network resources such as network shares and printers. The various scripting engines that are available to WSH provide flexible flow control and error handling.

Most important, however, is the expandability of WSH through COM objects. The Windows environment provides interfaces to perform common logon operations. Group membership checking can be performed using Active Directory Services Interface (ADSI), and database operations can be performed through ActiveX Data Objects (ADO). Windows Management Instrumentation (WMI) can be used to query the system information. Graphical logon messages can be implemented using Internet Explorer.

Connecting Network Resources at Logon

Problem

You want to connect a user to a home directory and enable the person to share a public network at logon.

Solution

You can use the WScript.Network object's MapNetworkDrive method:

'get logged on user name to display in greeting. Loop to ensure
Dim objNetwork, strUser
Set objNetwork = CreateObject("WScript.Network")
strUser =""


'get logged on user name to display in greeting. Loop to ensure
' user ID is returned correctly on Win 9x/ME computers
 Do While strUser =""
 strUser = objNetwork.UserName

Loop

'map user to home drive - assumes home drive share is combination of
'user-id and $ sign (hidden share)
objNetwork.MapNetworkDrive "H:", _
 "\THOR" & strUser & "$" , True
'connect to public area
objNetwork.MapNetworkDrive "P:", _
 "\THORPublicArea", True

Discussion

Logon scripts often connect networked file server and printer resources.

WSH scripts have a number of advantages over the corresponding command-line connection programs such as net use. WSH scripts provide more error handling and provide better control flow.

Configuring your network to execute WSH scripts depends on the clients on the network. Windows 2000/XP and Windows 98/ME can execute scripts natively by entering the script name in the User Profile Path field under the User Profiles option, as shown in Figure 3-1, or the Profile dialog box in the Windows 2000/XP Active Directory Users and Computers snap-in (dsa.msc).

click to expand
Figure 3-1: Windows NT 4 User Environment Profile dialog box

If you are working in an Active Directory-enabled Windows 2000/XP environment, you can use Group Policies to execute scripts. Group Policies determine settings that apply to objects within Active Directory. Examples of Active Directory objects include groups, containers, and users.

Using Group Policies, scripts can be executed at user logon and logoff as well as at computer start-up and shutdown. Group Policies can be set at the container (organizational unit) level, allowing specific policies to be applied to different groups of users.

For example, users within the finance organizational unit could run a different logon script than users within the accounting organizational unit.

To modify Group Policy properties, follow these steps:

  1. Start the Windows 2000 Active Directory Users and Computers snap-in.
  2. Select a container that Group Policies can be applied to, such as a domain level or organizational unit.
  3. Right-click the object and select Group Policy. A Properties dialog box appears, as shown in Figure 3-2. You can create a new domain policy or select an existing domain policy to modify.

    click to expand
    Figure 3-2: Group Policy Object Links list displaying a Default Domain Policy

  4. Click the Edit button. A Group Policy window similar to the one in Figure 3-3 appears, displaying all available policy properties. As you can see, Startup and Shutdown scripts are set under the Computer ConfigurationWindows SettingsScripts (Startup/Shutdown) entry, while user logon and logoff scripts are configured under User ConfigurationWindows SettingsScripts (Logon/Logoff).

    click to expand
    Figure 3-3: Group Policy Startup and Shutdown scripts

  5. After you've set all the properties, exit out of the Group Policy window.

To use Group Policies effectively, you must be using Windows 2000/XP with an Active Directory-enabled domain. The clients must also be running Windows 2000/XP, which limits the application in a mixed Windows client environment. Individual logon scripts assigned to users will execute together with Group Policy scripts.

Windows 2000/XP computers that are not part of an Active Directory domain can apply Group Policies to a local computer. This is done using the Group Policy editor. While you can apply the same script settings (logon, logoff, start-up, and shutdown), you cannot centrally control these settings, so it becomes impractical for a large number of computers. The Group Policy editor usually doesn't appear in the menus of a non-Active Directory computer, but you can access it by executing the gpedit.msc application located in the System32 directory.

If there are Windows NT 4.0 or Windows 9x/ME clients on the network, any WSH logon script must be executed from a batch file. Configure a batch file as the logon script, which calls the WSH script(s) you want to run at logon. Windows 2000 and XP clients do not require this step.

A problem that can occur with Windows 95 and NT 4.0 clients is not having WSH installed, and this can be checked by the logon script and installed if required.

The following logon batch file checks the client type and determines if WSH is already installed by searching for the cscript.exe file:

REM Logon.bat
REM Checks if WSH is installed on client and attempts to install it
REM then executes WSH logon script.
@ECHO OFF

IF "%OS%" == "Windows_NT" goto WIN_NT

IF NOT EXIST %WINDIR%CSCRIPT.EXE %0..WSHBINSTE50EN.EXE /Q
GOTO ENDSCRIPT
:WIN_NT
IF NOT EXIST %WINDIR%SYSTEM32CSCRIPT.EXE %0..WSHBINSTE50EN.EXE /Q
GOTO ENDSCRIPT

:ENDSCRIPT
REM execute WSH script
 cscript login.vbs

If WSH is not found, it is installed. The WSH install file can take a /Q switch that performs a "silent" install, which doesn't display any install information or display any user prompts. The installation file STE50EN.EXE used in the batch is the name of a recent WSH installation-it may be different on newer (or older) installation packages.

  Note 

Depending on the WSH installation version, the user may be prompted to reboot his or her machine after the installation of WSH is complete (even if it's a "silent" installation). This might not be desirable upon logon and may require user education.

An issue that will arise when providing software distribution in logon scripts is the location of the source files. A central network share is an option, but this might not be as desirable in WAN environments where a computer might reside in a remote location and the data share is only accessible over a low bandwidth connection. A more flexible way to handle this issue is to locate files in the logon directory the script is executed from.

The location of a logon directory can vary (unless you only have a single domain controller), because Windows clients authenticate on the "closest" domain controller it finds. Using NT replication, the logon scripts and any associated support files can be replicated between the domain controllers.

When the logon batch file is executed, the path of the batch file is passed as a "zero" parameter. This can be referenced through the %0 variable in the DOS batch. To pass this to a WSH script, set an environment variable with the value %0..:

REM get path for logon script
SET LDIR=%0..

cscript logon.vbs

The value stored in the temporary LDIR environment variable can be retrieved using the ExpandEnvironmentStrings method in your WSH script:

Set objShell = WScript.CreateObject("WScript.Shell")
strPath = objShell.ExpandEnvironmentStrings("%LDIR%")

The following script copies a number of files to a client's desktop and fonts directory and updates flags identifying that the operation has completed:

'updfiles.vbs
'copy files upon logon
Dim strPath, objFSO, strVal, objShell, strCopyPath

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")

strPath = objShell.ExpandEnvironmentStrings("%LDIR%")
On Error Resume Next
'get reference to registry flag
strVal = _
 objShell.RegRead("HKCUSOFTWAREWSHUpdatesDeskTopShortcutsUpdate1")
'if registry key didn't exist, then copy files to desktop
If IsEmpty(strVal) Then
 strCopyPath = objShell.SpecialFolders("Desktop") & ""
 objFSO.CopyFile strPath & "E-mail Policy.doc.lnk", strCopyPath, True
 objFSO.CopyFile strPath & "Phone List.doc.lnk", strCopyPath, True
 'update registry entry to reflect the operation has been performed
 objShell.RegWrite "HKCUSOFTWAREWSHUpdatesDeskTopShortcutsUpdate1", _
 Date
End If
strVal = Empty
'get reference to font update flag under local machine
strVal = objShell.RegRead("HKLMSOFTWAREWSHUpdatesTreFontUpd")
'if registry key didn't exist, then copy files to desktop
If IsEmpty(strVal) Then
 strCopyPath = objShell.SpecialFolders("Fonts") & ""
 objFSO.CopyFile strPath & "Trebucbd.ttf", strCopyPath, True
 objShell.RegWrite "HKLMSOFTWAREWSHUpdatesTreFontUpd", Date
End If

The script performs the operations and updates a registry entry. This registry entry is checked at the execution of the script and the operations are not performed if a value has been set for the particular key.

The script assumes it has been called from a batch file and the LDIR environment variable has been set to the directory path of the logon script. The files copied to the desktop are stored in this path.

See Also

Solution 4.3, Solution 5.13, Solution 7.1, and Solution 7.2.

Scheduling Scripts

Problem

You want to schedule a WSH script.

Solution

You can use the Scheduled Tasks feature to implement script scheduling. Scheduled Tasks is integrated into Windows 2000/XP and Windows 98/ME. It is also an optional component of Internet Explorer, so it can be installed on Windows 95 and Windows NT. If Schedules Tasks is installed on Windows NT, it replaces the scheduler service.

To schedule a task, follow these steps:

  1. From My Computer, select the Scheduled Tasks icon.
  2. Double-click the Add Scheduled Task icon. The Scheduled Task Wizard dialog box appears, as shown in Figure 3-4.

    click to expand
    Figure 3-4: Scheduled Task Wizard dialog box

  3. Click the Next button to continue.
  4. You are prompted to select an application to run, as shown in Figure 3-5.

    click to expand
    Figure 3-5: Scheduled Task Wizard application selection

  5. Click the Browse button. A file dialog box appears.
  6. Select the script you want to schedule.
  7. Enter a name for the scheduled task and select the time to perform the task, as shown in Figure 3-6.

    click to expand
    Figure 3-6: Enter a task name and select a performance interval.

  8. The option dialog boxes that appear after you've selected the scheduled option depend on the interval that you select. If you select Daily, Weekly or Monthly, various time options appear that determine the time interval; if you select the "When my computer starts" or "When I log on" option, no additional options appear.
  9. If you are scheduling a task for Windows NT or Windows 2000/XP, you are prompted for a user name and password. These logon credentials are used to execute the script, as shown in Figure 3-7.

    click to expand
    Figure 3-7: Enter a user name and password.

You can now run the script.

Discussion

Scheduled Tasks settings can be modified at any time by double-clicking any task under the Scheduled Tasks folder.

The authentication credentials are important when executing the script under Windows NT/2000. The credentials are used when executing the script, and any resources accessed by the script are authenticated using these credentials. Do not use an account with excess security rights if possible, because the contents of a script could be replaced with a malicious script and executed in a security context where it could perform damaging operations.

Windows NT/2000/XP includes native scheduling capability using the DOS AT command and scheduling service. The native NT scheduling service is less flexible than Scheduled Tasks for scheduling items, especially for executing scripts at mixed intervals. Scheduled Tasks also allows tasks to be executed by different user accounts, whereas the NT scheduling services are limited to the logon account set for the scheduler service, which by default is a local system account. If you install the Scheduled Tasks feature under Windows NT, all existing tasks scheduled using the AT command are kept.

Scripts that are scheduled to run on Windows NT/2000 when the user is not logged on should be executed using cscript.exe; if graphical prompts are displayed while the user is not logged in, unpredictable operations may result. Either set cscript as the default script host or explicitly configure the scheduled script to use cscript.exe, as shown in Figure 3-8.

click to expand
Figure 3-8: Set cscript to execute a scheduled script.

There is no method included with WSH or Scheduled Tasks to automate the creation of tasks. If you wanted to set up scheduled operations on a number of computers, such as at logon, you could distribute the Scheduled Tasks file.

Scheduled Tasks are stored as .job files under the %windir%Tasks folder. If these files are copied to the Tasks folders on remote computers, they automatically appear as scheduled items on that computer.

Scheduled Tasks implemented through this method should be thoroughly tested before being distributed, especially if the tasks are being used by different operating systems, such as Windows 95 and Windows 2000.

The following script copies a .job file from a central location to the WindowsTasks directory:

'updatejob.vbs
'copy job file from logon location to Tasks folder
Const WindowsFolder = 0
Dim objShell, strPath, objFSO, strVal

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")


Set objShell = CreateObject("WScript.Shell")
'set the directory to find the job file to copy
strPath = "\odinjobfiles"

On Error Resume Next
'get reference to registry flag
strVal = _
 objShell.RegRead("HKCUSOFTWAREWSHUpdatesAddJob1")
'if registry key didn't exist, then copy files to Windows Tasks folder
If IsEmpty(strVal) Then
 strCopyPath = objFSO.GetSpecialFolder(WindowsFolder) & "Tasks"

 objFSO.CopyFile strPath & "maintenance.job", strCopyPath , True
'update registry entry to reflect the operation has been performed
 objShell.RegWrite "HKCUSOFTWAREWSHUpdatesAddJob1", Date
End If

The script can be called from a logon script to update clients' Scheduled Tasks. The registry is updated with a flag so the file is not copied again at next logon.

If the Scheduled Task is being used by Windows 2000/XP or Windows NT 4.0 as well as Windows 9x/ME computers, it should be created on the Windows NT/2000/XP platforms. Tasks created by Windows NT/2000 will run under Windows 9x, but tasks created under Windows 9x will be missing the Windows NT/2000 account authentication information that Windows 9x does not require.

Task Scheduler logs the execution of scheduled operations. You can view the log by selecting the View Log option from the Advanced menu under Scheduled Tasks.

See Also

Task Scheduler Help file mstask.chm, which is located under the Windows Help directory.

Displaying a Logon Message

Problem

You want to display a graphical welcome message upon logon. Figure 3-9 shows an example of a "welcome" screen that appears when a user logs on.

click to expand
Figure 3-9: Logon "welcome" message

Solution

You can use the ENTWSH.HTMLGen scripting component from Chapter 11 to build a graphical dialog box using Internet Explorer 5.x:

'logon.vbs
Const DOMAIN = "Acme"

Set objShell = CreateObject("WScript.Shell")
Set objNetwork = CreateObject("WScript.Network") [Be consistent.]
Set objFSO = CreateObject("Scripting.FileSystemObject")

'create a ENTWSH.HTMLGen component
Set objHTMLGen = GetObject("script:\odinwsc$htmlgen.wsc")

On Error Resume Next
objHTMLGen.StartDOC "ACME Ltd. Logon Script", True

'get logged on user name to display in greeting. Loop to ensure
' user ID is returned correctly on Win 9x/ME computers
Do While strUser =""
 strUser = objNetwork.UserName
 WScript.Sleep 100
Loop

'get ADSI User object from domain
Set objUser = GetObject("WinNT://" & DOMAIN & "/" & strUser & ",User")
'if no error occurred getting ADSI user object, set user ID to
'user full name
If Not Err Then strUser = objUser.FullName

Set objIE = objHTMLGen.Object
objIE.MenuBar = 0
objIE.Toolbar = 0

strMsg = "Good "

If Hour(Time)>=17 Then
 strMsg = strMsg & "Evening, "
ElseIf Hour(Time)>=12 Then
 strMsg = strMsg & "Afternoon, "
Else
 strMsg = strMsg & "Morning, "
End If

Err.Clear
'if OS Windows 9x/ME map home directory
If Not objShell.Environment("OS") = "Windows_NT" Then
 objNetwork.RemoveNetworkDrive "H:", True
 Err.Clear
 objNetwork.MapNetworkDrive "H:", "\Odin" & objNetwork.UserName _
 & "$", True
End If

objHTMLGen.WriteLine "

" & strMsg & strUser & _ "


" Set objTS = objFSO.OpenTextFile("\odind$datamessageshello.htm") objHTMLGen.WriteLine objTS.ReadAll objHTMLGen.WriteLine "

" objHTMLGen.EndDOC

Discussion

Messages displayed at logon can be used to provide general information to users as well as to display system information.

The Solution script uses Internet Explorer (IE) to build a logon message. An instance of IE is created through the WSHENT.HTMLGen component that is discussed in Chapter 11.

An instance of the HTMLGen component is created using the GetObject method. Windows Script components can use either CreateObject or GetObject to create new instances. Creating new instances by using GetObject only applies to WSC objects and is implemented by calling the method and then passing the path to the component prefixed with script:. The following snippet creates an instance of the HTMLGen component using the script: prefix:

Set objHTMLGen = GetObject("script:\odinwsc$ HTMLGen.wsc")

The path to the component can be a local path or UNC. The advantage of using GetObject over CreateObject is the WSC object does not need to be registered. This is useful in logon scripts because you may not be guaranteed that all clients that log on to the network have the appropriate WSC objects registered.

This method cannot be used with compiled COM components written in languages such as VB or C++. These components must be registered before being used, which can be difficult to guarantee on all client computers.

If you are implementing logon scripts that require the use of components, you can check if the component is registered and install and register it before executing the WSH script. The following sample checks if the regobj.dll registry component exists in the Windows system directory, and if not, copies it over and registers it:

IF "%OS%" == "Windows_NT" goto WIN_NT

IF NOT EXIST %WINDIR%
egobj.dll GOTO REG9X
GOTO ENDSCRIPT
:REG9X
Copy %0..DLL
egobj.dll %WINDIR%system
%0..exe
egsvr32 /s %WINDIR%system
egobj.dll
GOTO ENDSCRIPT

:WIN_NT
IF NOT EXIST %WINDIR%system32
egobj.dll GOTO REGNT
GOTO ENDSCRIPT
:REGNT
Copy %0..DLL
egobj.dll %WINDIR%system32
%0..exe
egsvr32 /s %WINDIR%system32
egobj.dll

:ENDSCRIPT
cscript login.vbs

The logon script checks for the existence of regobj.dll in the client's system directory. If it is not in the directory, it is copied over and registered using regsvr32. The regsvr32 application is not a standard Windows-installed application, so it is executed from the logon directory. The /s (silent) switch is used when registering the component to ensure no prompts appear to the user.

You can check for the existence of and register components through a WSH script upon logon. Additional checking can be performed in the script, such as version checking, error trapping, and logging, which can't be easily implemented through a batch file.

The following script contains the logic to check for the existence of a specific file and copy and register it if it does not exist:

'regit.vbs
'checks for existence of specified DLLs and registers
'them if required
Const ForAppending = 8
Dim objShell, strComputer, strSource, strDest
Dim strLogFile, objNetwork, strUser

Set objNetwork = CreateObject("WScript.Network")

'loop until user id is retrieved, required for Win9x
Do While strUser =""
 strUser = objNetwork.UserName
Loop

'set the log file name - ensure uniqueness by combining
'user id and date and time
strLogFile = "\thore$" & strUser & " "& Month(date) & "-" & _
 Day(date) & "-" & Year(date) & " "& _
 Hour(time) & "_" & Minute(time) & "_" _
 & Second(time) & ".txt"

Set objShell =CreateObject("WScript.Shell")

'set destination directory depending on OS
If objShell.ExpandEnvironmentStrings("%OS%") = "Windows_NT" Then
 strDest = objShell.ExpandEnvironmentStrings("%windir%") _
 & "system32"
Else
 strDest = objShell.ExpandEnvironmentStrings("%windir%") _
 & "system"
End If

'get the source directory to find the components to register
strSource = objShell.ExpandEnvironmentStrings("%LDIR%")

CheckRegister "regobj.dll", False


'CheckRegister
'Checks for existence of specified file and copies and registers it
'if it does not exist.
'Parameters
'strFile Name of file to check for
'bReplace Boolean value. If True then file will be updated if newer
' version exists
Sub CheckRegister(strFile, bReplace)

Dim strPath
Dim objFSO
Dim bRegister, strDstVer, strSrcVer

strComputer = ""

strDest = strDest & strFile
strSource = strSource & strFile

Set objFSO = CreateObject("Scripting.FileSystemObject")
 bRegister = False

'check if specified file exists
If Not objFSO.FileExists(strDest) Then
 objFSO.CopyFile strSource, strDest
 bRegister = True
Else
 'file exists.. replace?
 If bReplace Then

 On Error Resume Next
 'attempt to get file version of specified files
 strSrcVer = objFSO.GetFileVersion(strSource)
 strDstVer = objFSO.GetFileVersion(strDest)
 'error occurred.. unable to get version, use file size instead
 If Err Then
 strSrcVer = objFSO.GetFile(strSource).Size
 strDstVer = objFSO.GetFile(strDest).Size
 End If
 Err.Clear
 'check if the destination file version is less than source
 If Val(strSrcVer) > Val(strDstVer) Then
 'copy over existing file
 objFSO.CopyFile strSource, strDest
 'error copying file?
 If Err Then
 'error copying source to destination..
 LogIt strLogFile, "Error copying file " & strSource & _
 " to " & strDest & " on computer " & strComputer _
 & vbCrLf & Err.Description & " " & Err
 CheckRegister = False
 Exit Sub
 End If
 bRegister = True
 Else
 'more recent version of file, exit function
 LogIt strLogFile, "File " & strSource & _
 " is more recent than " & strDest & " on computer " & _
 strComputer
 Exit Sub
 End If
 End If

End If

'register the file?
If bRegister Then
 objShell.Run strSource & "regsvr32 /s " & strDest, 0, True
End If

End Sub

'Procedure Logfile
'Logs text to specified file
'Parameters
'strFile Path to log file
'strMsg Message to log
Sub LogIt(strFile, strMsg)
Dim objTS, objFSO

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTS = objFSO.OpenTextFile(strFile, ForAppending, True)
objTS.WriteLine Now & " " & strMsg

objTS.Close
End Sub

The script also compares versions of the specified component or library and attempts to replace it if the current version is older than the one to be copied. The file version is determined by the File Scripting object's GetFileVersion method.

Operation results are written to a log file, which allows for the rollout and updating of components to be monitored. Because the operating system does not allow more than one process to open and write to a file at the same time, a unique filename is used to ensure that conflicts don't occur. The file name consists of the user ID followed by the date and time-for example, FredS 7-16-2001 20_32_28.txt. An alternative method of logging is to use the event log. This is useful in a Windows NT4/2000/XP-only environment, because it allows for information to be logged in a central location.

WSH version 2.0 and later provides the ability to write events to the Windows NT/2000/XP event log using the WScript.Shell object's LogEvent method. The syntax is as follows:

objShell.LogEvent(intType, strMessage [,strTarget])

Table 3-1 lists the LogEvent method parameters.

Table 3-1: LogEvent Parameters

PARAMETER

DESCRIPTION

intType

Type of the event. Table 3-2 lists the event types.

strMessage

Message to log.

strTarget

Optional. Applies to Windows NT4/2000/XP only. The name of the system where the event should be logged. Default is local system. Parameter is ignored on Windows 9x/ME.

Table 3-2: LogEvent Types

PARAMETER

DESCRIPTION

1

Success

2

Error

4

Warning

8

Information

16

Audit_Success

On Windows NT4/2000/XP the method logs an event in the event log. The logged message is stored in an application log with the Source as WSH. The following code sample logs an information message to the event log on the remote computer Odin:

Const Information = 8
Set objShell = CreateObject("WScript.Shell")
objShell.LogEvent Information, "Error occurred when sending mail", "Odin"

On Windows 9x/ME the information is logged to the file WSH.log, which will be in the user's Windows directory. The WSH.log file will contain a timestamp, the event type, and the text of the log entry.

The method returns True if the event is successfully logged; otherwise, it returns False.

The Solution script displays a salutation to the user at logon. The salutation displays Good Morning/Afternoon/Evening followed by the user name. The user name is referenced from the Full Name field from NT User Manager, and it is retrieved using ADSI (which must be installed on the client workstation as well as domain controllers). If ADSI is not installed, the user's logon user ID is used instead.

Additional information is stored in an external html file, hello.htm, and loaded into the browser at logon. This makes for easier editing of the logon message.

See Also

Solution 11.2, Solution 14.3, and Solution 14.5.

Performing Operations Based on Group Membership

Problem

You want to check group membership upon logon.

Solution

You can get a reference to the ADSI group object that you want to check and then use the ADSI Group object's IsMember method to determine group membership:

'chkmember.vbs
Const Domain = "ACME"
Dim strUser, objGroup, strGroup, objUser

Set objNetwork = CreateObject("WScript.Network")

'get name of logged on user - loop until user id is retrieved, required for Win9x
Do While strUser = ""
 strUser = objNetwork.UserName
 WScript.Sleep 100
Loop

If CheckGroup(Domain, "Accounting", strUser) Then
 'connect to accounting share
 objWshNetwork.MapNetworkDrive "P:", "\THORAccounting", True
End If

Function CheckGroup(strDomain, strGroup, strUser)
Dim objGroup
'get ADSI User object from domain
Set objGroup = GetObject("WinNT://" & strDomain & "/" _
 & strGroup & ",Group")

If objGroup.IsMember("WinNT://" & strDomain & "/" & strUser) Then
 CheckGroup = True
Else
 CheckGroup = False
End If

End Function

Discussion

Performing actions that are based on user ID or group membership has traditionally been hard to accomplish using normal batch file logon scripts in a Windows NT networked environment.

Active Directory Services Interface (ADSI) provides a mechanism to test for group membership in a WSH script. ADSI must be installed on each client to use this feature. See Chapter 14 for more information on how to use ADSI and the IsMember method.

Testing for group membership for a large number of groups can be timeconsuming. Each reference made to a Group object requires another call to a server. Instead, get a reference to the user that is being checked and enumerate the groups the account is a member of, adding each group account to a string. The following script demonstrates this method and connects drives based on group membership:

Dim strGroups, objGroup, objUser, strUser, objNetwork
Const Domain = "acme"

Set objNetwork = CreateObject("WScript.Network")

'get logged on user name
'get name of logged on user - loop until user id is retrieved, required for Win9x
Do While strUser = ""
 strUser = objNetwork.UserName
 WScript.Sleep 100
Loop

'get ADSI User object from domain
Set objUser = GetObject("WinNT://" & Domain & "/" & strUser & ",User")

strGroups = ";"
'enumerate all user groups
For Each objGroup In objUser.Groups
 strGroups = strGroups & objGroup.Name & ";"
Next

'check if member of Accounting or Finance group
MapGroup "Accounting", "\THORAccounting", "P:"
MapGroup "Finance", "\THORFinance", "O:"
Sub MapGroup(strName, strShare, strDrive)
'check if member of specified group
 If InStr(strGroups, ";" & strName & ";", vbTextCompare) > 0 Then
 objNetwork.MapNetworkDrive strDrive, strShare, True
 End If
End Sub

If you are using Windows 2000/XP with Active Directory enabled and Windows 2000/XP clients, logon scripts can be assigned to organizational units via Group Policies. This allows scripts to be executed depending on the organizational unit to which a user belongs. See Solution 3.2 for information on setting Group Policies.

Login scripts that perform operations based on group membership and/or network user IDs can be tedious to maintain. Whenever a change is made, the script must be replicated to all domain controllers to ensure the script is available when a user logs on.

The following application, Quick and Dirty Network Administration (QADNA), provides an administrative interface that allows user accounts and groups to be assigned network resources and set registry values. Figure 3-10 illustrates the graphical user interface that is used to associate resources to a user.

click to expand
Figure 3-10: QADNA User configuration

QADNA is implemented using Microsoft Access 97 and can be found on the book's companion Web sites at http://www.apress.com/ and http://www.wshenterprise.com/. The application provides a simple interface to associate resources with a particular user or group.

Users and groups are maintained through an administrative screen that uses ADSI to search for all users, groups, and computers on the network. These are added to the Access database. The database must be manually refreshed each time a new resource (user, group, or computer resource) is added.

You can use the following script as a client logon script:

'qadna.vbs
'Quick and Dirty Network Administration interface
Const Domain = "c3i"
Const ForAppending = 8
Const DataFile= "FileDSN=\odinFileDSN$ QADNA.dsn"
Const ConnectShare = 5
Const ConnectPrinter = 4
Const UpdateRegistry = 100

Dim objConn, objRst, objNetwork
Dim strGroups, strUser, objGroup
Dim strQuery, strComputer, objShell, strLogFile

Set objShell = CreateObject("WScript.Shell")

Set objNetwork = CreateObject("WScript.Network")

'set the log filename - ensure uniqueness by combining
'user id and date and time
strLogFile = "\odinlogfiles" & strUser & " "& Month(date) & "-" & _
 Day(date) & "-" & Year(date) & " "& _
 Hour(time) & "_" & Minute(time) & "_" _
 & Second(time) & ".txt"

'get name of logged on user - loop until user id is retrieved
'required for Win9x
Do While strUser = ""
 strUser = objNetwork.UserName
 WScript.Sleep 100
Loop

strComputer = objNetwork.ComputerName

On Error Resume Next
'get ADSI User object from domain
Set objUser = GetObject("WinNT://" & Domain & "/" & strUser & ",User")

If Err Then
 LogIt strLogFile," Error getting ADSI user object for "& strUser & _
 vbCr & Err.Description & ""& Err
 WScript.Quit -1
End If

'build query to execute against QADNA database
strQuery = "Select * From qryLinkAccountsWithActions WHERE "& _
 "(AccountName In ("

'enumerate all user groups
For Each objGroup In objUser.Groups
 strQuery = strQuery & "'" & objGroup.Name & "',"
Next

'add user name to query
strQuery = Left(strQuery, Len(strQuery) - 1) & _
 ")) Or AccountName ='" & strUser & "'"

'create ADO object and open QADNA database
Set objConn = CreateObject("ADODB.Connection")
objConn.Open DataFile

If Err Then
 LogIt strLogFile," Error opening database " & DataFile & _
 " on computer " & strComputer & vbCrLf & _
 Err.Description & " " & Err
 WScript.Quit -1
End If

Set objRst = objConn.Execute(strQuery)

 'loop through each record and perform specified operation
 Do While Not objRst.Eof
 Select Case objRst("ActionType")
 Case ConnectShare
 'remove any existing connected drive
 objNetwork.RemoveNetworkDrive objRst("DriveLetter") & ":", True
 'clear any errors occurred, such as removing nonconnected drive
 Err.Clear
 'connect drive
 strPath = "\" & objRst("ObjectSource") & "" _
 & objRst("ObjectName")
 objNetwork.MapNetworkDrive objRst("DriveLetter") & ":", _
 strPath, True
 
 If Err Then
 LogIt strLogFile," Error connecting to " & strPath & _
 " on computer " & strComputer & vbCrLf & _
 Err.Description & " " & Err

 End If

Case ConnectPrinter 'add printer
 Err.Clear
 strPath = "\" & objRst("ObjectSource") & "" & _
 objRst("ObjectName")
 objNetwork.AddWindowsPrinterConnection strPath

 If Err Then
 LogIt strLogFile," Error adding printer " & strPath & _
 " on computer " & strComputer & vbCrLf & _
 Err.Description & " " & Err
 End If

Case UpdateRegistry

 'write registry value
 strPath = objRst("Path1")
 'check if DWORD type value

If objRst("DriveLetter") = "D" Then
 objShell.RegWrite strPath, objRst("Path2")," REG_DWORD"
 Else
 objShell.RegWrite strPath, objRst("Path2")
 End If

 If Err Then

 LogIt strLogFile," Error setting registry key " & strPath & _
 " on computer "& strComputer & vbCrLf & _
 Err.Description & " " & Err
 End If
 End Select
 objRst.MoveNext
 Loop

objRst.Close
objConn.Close

When a client logs on and the script is executed, the database is checked for any resources associated with the user or any groups the user belongs to and they are set accordingly. Printer resources are added, network shares are connected, and registry values are set depending on the values set in the QADNA program.

Each client must have ADO version 1.5 or later, as well as ODBC drivers for Microsoft Access 97. The following file DSN, qadna.dsn, is required by the script and stores the information required to connect to the database:

[ODBC]
DRIVER=Microsoft Access Driver (*.mdb)
UID=admin
UserCommitSync=Yes
Threads=3
SafeTransactions=0
PageTimeout=5
MaxScanRows=8
MaxBufferSize=2048
FIL=MS Access
DriverId=281
DefaultDir=\OdinDataQADNA
DBQ=\OdinDataQADNAqadna.mdb

File locations stored in the DSN file need to be changed to reflect locations in your environment. A recent version of ADSI must also be installed on the client machine to use the script.

See Also

Solution 3.1 and Solution 14.15.

Creating an Inventory of Computers at Logon

Problem

You want to inventory a computer at logon and store the details in a database.

Solution

WMI provides a large number of classes that expose system-related information. The following script uses WMI to inventory major system components and stores the information in the Access QADNA database introduced in Solution 3.5 to store and manage the information. ADO is used within the script to populate the database. The SysInfo.ENTWSH Windows script component created in Solution 10.1 is used to query O/S, memory, serial number, and CPU information:

'invcom.vbs
'inventories computer upon logon
Option Explicit

Const DataFile = "FileDSN=\odinFileDSN$QADNA.dsn"

Const adOpenDynamic= 2
Const adLockOptimistic= 3

Dim objSysInfo, objService, objNetwork, objRst, objConn
Dim strComputerName, nCompID, bUpdate, bNew

Set objNetwork = CreateObject("WScript.Network")
strComputerName = objNetwork.ComputerName

'create ADO object and open QADNA database
Set objConn = CreateObject("ADODB.Connection")
Set objRst = CreateObject("ADODB.Recordset")
objConn.Open DataFile

bUpdate = False
bNew = False

'open tblcomputers table and determine if computer exists
objRst.Open "tblComputers", objConn, adOpenDynamic, adLockOptimistic
objRst.Find "ComputerName='" & strComputerName & "'"
bUpdate = False
'if computer does not exist, add to inventory
If objRst.EOF Then
 objRst.AddNew
 objRst("ComputerName") = strComputerName
 bNew = True
Else
 'check if computer record needs updating..
 If Date>= Cdate(objRst("UpdateDate")) Then bUpdate = True
End If


If bUpdate Or bNew Then

Set objService = _
 GetObject("winmgmts:{impersonationLevel=impersonate}!rootcimv2")

'create an instance of the SysInfo object
Set objSysInfo = GetObject("script:\odinwsc$SysInfo.wsc")

objRst("BIOSVersion") = objSysInfo.BIOSVersion
objRst("CPU") = objSysInfo.CPU
objRst("Memory") = objSysInfo.Memory
objRst("OSVersion") = objSysInfo.OS
objRst("RegisteredUser") = objSysInfo.RegisteredUser
objRst("OSSerialNum") = objSysInfo.SerialNumber
objRst("VirtualMemory") = objSysInfo.VirtualMemory
objRst("UpdateDate") = Date + 180
nCompID = objRst("ComputerID")

objRst.Update
objRst.Close

'if new computer record get record ID
If bNew Then
 Set objRst = objConn.Execute("SELECT Max(ComputerID) FROM tblComputers")
 nCompID = objRst(0)
End If

'delete any existing computer inventory
objConn.Execute "Delete From tblComputerItems " & _
 "Where ComputerID = " & nCompID
WMIInv "Select Description, Size From Win32_DiskDrive" _
 , Array("Description" , "Size"),1, nCompID

WMIInv "Select AdapterType, AdapterRAM From " & _
 "Win32_VideoConfiguration" _
 ,Array("AdapterType", "AdapterRAM"), 2, nCompID

WMIInv "Select Description, MacAddress From " & _
 "Win32_NetworkAdapterConfiguration Where IPEnabled = True" _
 , Array("Description", "MacAddress"), 3, nCompID

WMIInv "Select Model, ProviderName From " & _
 "Win32_POTSModem", Array("Model", "ProviderName"), 4, nCompID

WMIInv "Select Description, Manufacturer From " & _
 "Win32_SCSIController" , Array("Description", _
 "Manufacturer"), 5, nCompID

End If

objConn.Close

'WMIInv
'returns specified information from WMI query
'Parameters:
'strQuery SQL query to execute against WMI service
'aFields Array of fields to store
'nType Type of item
'nCompID Unique computer identifier
Sub WMIInv(strQuery, aFields, nType, nCompID)
Dim objInstance, objResults, objProp
Dim nF, strSQL, strText

Set objResults = objService.ExecQuery(strQuery)

'loop through each instance and build the output lines
For Each objInstance In objResults
strSQL=" INSERT INTO tblComputerItems (ComputerID,ItemType, Item1,Item2)" _
 & "Values (" & nCompID & "," & nType & ","

'loop through each property
For nF = LBound(aFields) To UBound(aFields)
 Set objProp = objInstance.Properties_(aFields(nF))
 strText = objProp.Value
 strSQL = strSQL & "'" & strText & "',"
 Next

 strSQL = Left(strSQL, Len(strSQL) - 1) & ");"
 objConn.Execute strSQL
Next
End Sub

Discussion

Keeping an up-to-date inventory of client hardware is a never-ending, time-consuming, but important task for any IT departments.

This Solution uses Windows Management Instrumentation (WMI) to inventory the resources on the client computer. The information is stored in the QADNA Access database that was introduced in Solution 3.4. Figure 3-11 shows the computer information that has been inventoried after running the script.

click to expand
Figure 3-11: QADNA computer inventory screen

Upon logon, the script checks the database to see if a record for the computer exists. If not, the computer is added and inventoried. Each computer record also includes a Next Update date field, which controls when the next update occurs. This can be manually changed to force an update; otherwise, it will reinventory the machine after a 180-day interval. Each client must have ADO version 1.5 or later to read and write the database, ODBC drivers for Microsoft Access 97, and WMI to read system information.

See Also

Solution 3.4, Solution 10.1, Solution 13.8, and Solution 13.13.





Managing Enterprise Systems with the Windows Script Host
Managing Enterprise Systems with the Windows Script Host
ISBN: 1893115674
EAN: 2147483647
Year: 2005
Pages: 242
Authors: Stein Borge
Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net