Windows Server Hack [Electronic resources]

Mitch Tulloch

نسخه متنی -صفحه : 163/ 81
نمايش فراداده

Hack 53 Add Printers Based on Name of Computer

Here's a logon script you can use to solve a complicated problem in printer management: performing a logon task based on the name of the computer being logged into.

In various forums, I have noticed questions regarding how to perform tasks at logon based on the name of the computer that the user is logging into. In my environment (a small community college), we thought we could have fewer servers and reduce network traffic by configuring all our computers to use TCP/IP printing. This worked out pretty well for a while, but we discovered a few drawbacks of using TCP/IP printing. For example, there is no control over excessive printing and it is not possible to track costs back to a user. Also, it is difficult to update systems when printers get replaced

We soon split our thinking and were able to switch 99% of our student computers to print through a few servers. To assist us with our print-management needs, we purchased Print Manager Plus (http://www.printmanagerplus.com). Print Manager Plus has many benefits for my environment. We are an educational institution that has a number of open-use areas where students and the public can use our computers. We do not track printing costs back to users, and we were experiencing a rising cost of print supplies due to misuse of our printers. The implementation of Print Manager Plus allowed us to put controls in place that limit abuse in the following ways:

The user is able to print only 8 pages at a time. If the user's document is 10 pages long, he must print pages 1-8, then 9-10.

There is a limit on the file size of the print job. The user is unable to print a document that is larger than 15MB when it arrives at the server.

Print Manager Plus has the ability to inform the user when he exceeds the defined limits. I have customized the messages sent from Print Manager Plus to the user so that they present him with options on how to print the document in question.

Server-based printers, however, created a few headaches of their own. In particular, any room is pretty much fair game for us to use when we provide training to not only our students, but also our faculty and staff. We needed a way to set the right printer on any given computer for any user who logs on. Also, we wanted to use one logon script for all users in any domain.

We also had a Windows 2000 Terminal Server available but had not made good use of it until recently. The original thinking was to install a bunch of printers on it and trust users to select the appropriate printer before hitting the print button. We soon had calls asking, "What are all these documents coming out of my printer?"

Anyway, I thought about this awhile and decided that the best approach would be to add the printers based on the name of the computer. We have a standard naming convention in use that made this task possible.

This hack contains the code that I came up with. The code should be pretty readable by itself, but I'll spend some time briefly discussing some of its more major parts.

The Code

To get the code for the script, I suggest downloading the Logon.vbs file from the O'Reilly web site (http://www.oreilly.com/catalog/winsvrhks/), because it's too long to type from scratch. This version of the script was tested on Windows 2000 Service Pack 2 running Internet Explorer 6 Service Pack 1 with Microsoft Windows Script v5.6. It was also tested on Windows XP Professional participating in a small Active Directory domain.

I have had a variation of this script in production for a long time now with great success. But, as always, either the differences in your environment or something I missed in editing the script for this hack might cause things behave unexpectedly.

Depending on your environment, the code requires:

A recent version of Internet Explorer (http://www.microsoft.com/windows/ie/default.asp).

Windows Script 5.6 for Windows 98/ME/NT (http://www.microsoft.com/downloads/details.aspx?FamilyID=0a8a18f6-249c-4a72-bfcf-fc6af26dc390)

Windows Script for 2000/XP (http://www.microsoft.com/downloads/details.aspx?FamilyID=c717d943-7e4b-4622-86eb-95a22b832caa)

Active Directory Client Extensions for Windows 9x, ME or NT4 (http://www.microsoft.com/windows2000/techinfo/howitworks/activedirectory/adsilinks.asp).

For more information on using Internet Explorer for status messages, see "Using an IE Window to Display Progress" (http://www.myitforum.com/articles/11/view.asp?id=3489), "VBScript Forms (Part 1): Using Internet Explorer for Data Input/Output Forms" (http://www.myitforum.com/articles/11/view.asp?id=4390), and "Using IE to Browse for Files" (http://www.myitforum.com/articles/11/view.asp?id=4229).

Perform initial tasks

This section sets up the basics of the script. In this script, I also call a few subroutines/functions (listed further in later sections) that either gather information or perform my required tasks. I like using subroutines and functions, because it makes my code reusable or easily stored in a code library for future coding endeavors. This section accomplishes the following major tasks:

Call a subroutine that gathers basic system information

Exit the script if user is logged on locally to the server

Call subroutines to gather group memberships

The script also performs other tasks, as discussed in comments throughout the code.

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' File:     Logon.vbs
' Updated:  April 2003
' Version:  2.1
' Author:   Dan Thomson, myITforum.com columnist
'           I can be contacted at dethomson@hotmail.com
'
' Usage:
'           This script can be directly assigned as a logon script for
'           Windows 2000 or greater clients. For older systems, this
'           script will need to be called from a logon batch file.
'
' Input:
'
' Requirements:
'           Win 9x, ME or NT 4:
'           - Active Directory Client Extensions
'             http://www.microsoft.com/windows2000/techinfo/howitworks/
'             activedirectory/adsilinks.asp
'           - Windows Script
'             http://msdn.microsoft.com/library/default.asp?url=/downloads
'             /list/webdev.asp
'           - A recent version of Internet Explorer
'
' Notes:
'           Tested on Windows 2000 Professional running Windows Script v5.6
'           and participating in an AD domain
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
On Error Resume Next
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Define Variables and Constants
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim objFileSys
Dim objIntExplorer
Dim objWshNetwork
Dim objWshShell
Dim strDomain           'Domain of the user
Dim strHomePage         'Homepage to be set for user
Dim strLogonPath        'Path to location from where the script is running
Dim strOSProdType       'OS Product type (WinNT, LanmanNT, ServerNT)
Dim strWorkstation      'Local Computer Name
Dim strUserGroups       'List of groups the user is a meber of
Dim intCounter          'General counter
Const UseNTServer = 0   'Sets whether this script runs when logging on locally
'to Windows Servers.
'Values are: 1 (Yes) OR 0 (No)
'Initialize common scripting objects
Set objFileSys    = CreateObject( "Scripting.FileSystemObject" )
Set objWshNetwork = CreateObject( "WScript.Network" )
Set objWshShell   = CreateObject( "WScript.Shell" )
'Pause script until user is fully logged on (applies only to Win 9x or ME)
'This will timeout after 10 seconds
strUser = "
intCounter = 0
Do
strUserID = objWshNetwork.Username
intCounter = intCounter + 1
Wscript.Sleep 500
Loop Until strUserID <> " OR intCounter > 20
'Check for error getting username
If strUserID = " Then
objWshShell.Popup "Logon script failed - Contact the Helpdesk @ x 345", , _
"Logon script", 48
Call Cleanup
End If
'Setup IE for use as a status message window
Call SetupIE
'Display welcome message
Call UserPrompt ("Welcome " & strUserID)
'Add horizontal line as a 'break'
objIntExplorer.Document.WriteLn("<hr style="width:100%"></hr>")
'Gather some basic system info
Call GetSystemInfo
If IsTerminalServerSession <> True Then
'Exit if we are logging on locally to a server and the 
'script is set to NOT run on servers
IF UseNTServer = 0 AND (strOSProdType = "LanmanNT" OR strOSProdType = "ServerNT") Then
objWshShell.Popup "Windows Server - Exiting Logon Script!", 10, _
"Logon to " & strDomain, 16
Call CleanUp
End if
End If
'Get group memberships
strUserGroups = "
Call GetLocalGroupMembership
Call GetGlobalGroupMembership
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Map drives, add shared printers and set default homepage
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Determining workstation settings

This section determines which settings should be applied to the workstation, based on the name of the workstation. Our environment has a nice naming convention: the building, room number, and station number are identified in the name. For example, the name Blg4Rm105-03 identifies a computer as being station 3, located in building 4, room 105. To determine which mappings get assigned to a computer, all I have to do is base my criteria on everything on the left of the dash (-).

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Part A
' This section performs actions based on computer name
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'The left side of the computer name contains building and room information
If Instr( 1, strWorkstation, "-", 1) > 0 Then
strWorkstation = _
Left( strWorkstation, ( Instr( 1, strWorkstation, "-", 1)))
End If
Select Case UCase( strWorkstation )
Case "BLD1RM101-"
Call MapDrive ("U:", "MyShareSvr1", "MyShare1")
Call AddPrinter ("Mydomain2", "MyPrtSvr2", "Bld1Rm101-HP4050")
objWshNetwork.SetDefaultPrinter "\\MyPrtSvr2\Bld1Rm101-HP4050"
strHomePage = "http://www.chesapeake.edu/academic_info/ " & _
"acad_computing.asp"
Case "BLD1RM202-"
Call MapDrive ("U:", "MyShareSvr2", "MyShare2")
Call AddPrinter ("Mydomain1", "MyPrtSvr1", "Bld1Rm202-HP4000")
objWshNetwork.SetDefaultPrinter "\\MyPrtSvr1\Bld1Rm202-HP4000"
strHomePage = "http://www.chesapeake.edu/library/default.asp"
Case "BLD3RM104-"
'This room uses TCP/IP printing instead of a print server. 
'Only set homepage
strHomePage = "http://www.chesapeake.edu/writing/wchome"
Case Else
End Select
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Adding mappings based on group membership

Adding mappings based upon the computer name is cool. However, there will always be a need to perform tasks based on specific group membership. This section takes care of such tasks.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Part B
' This section performs actions based on group membership
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If InGroup( "ShareForStaff" ) Then
Call MapDrive ("X:", "StaffSvr1", "StaffShare1")
strHomePage = "http://www.chesapeake.edu/generalinfo/cambridge.asp"
End If
If InGroup( "ShareForStudents" ) Then
Call MapDrive ("Y:", "StudentSvr1", "StudentShare1")
strHomePage = "http://www.chesapeake.edu"
End If
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' End section
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Setting the IE home page and final message

This section sets the IE home page (if specified), starts SMSls.bat, and posts a final message to the user. The script tests to determine if the user is a member of the Domain Admins or DoNotInstallSMS groups. If the user is a member of either of these groups, SMSls.bat is skipped. This is helpful if you want to get in quick to do a small task or to keep SMS off some of your more persnickety users' computers.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Set default homepage
If strHomePage <> " Then
Err.Clear
objWshShell.RegWrite _
"HKCU\Software\Microsoft\Internet Explorer\Main\Start Page", strHomePage
If Err = 0 Then Call UserPrompt ("Set Internet home page to " & strHomePage)
End If
'Start SMSls.bat
'Do not run if a member of the Domain Administrators
'or in the global group DoNotInstallSMS
If InGroup("Domain Admins") OR InGroup("DoNotInstallSMS") Then
Call UserPrompt ("Skipping SMSLS.BAT")
Else
objWshShell.Run "%COMSPEC% /c " & strLogonPath & "\smsls.bat", 0, False
End If
'Add horizontal line as a 'break'
objIntExplorer.Document.WriteLn("<hr style="width:100%"></hr>")
'Inform user that logon process is done
Call UserPrompt ("Finished network logon processes")
'Wait 10 seconds
Wscript.Sleep (10000)
'Close Internet Explorer
objIntExplorer.Quit( )
Call Cleanup
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

That's the end of the first major section of the script. The following subsections list and explain the various subroutines and functions.

Connecting to a shared network printer

The following routine is where the printer mapping occurs. It first verifies that the share is accessible and creates the mapping. If the share is not accessible or is not a valid print share, the user will be prompted with an error message that lets her know she should call the help desk.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub:      AddPrinter
'
' Purpose:  Connect to shared network printer
'
' Input:
'           strPrtServerDomain  Domain in which print server is a member
'           strPrtServer        Name of print server
'           strPrtShare         Share name of printer
'
' Output:
'
' Usage:
'           Call AddPrinter ("Mydomain2", "MyPrtSvr2", "Bld1Rm101-HP4050")
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub AddPrinter(strPrtServerDomain, strPrtServer, strPrtShare)
On Error Resume Next
Dim strPrtPath    'Full path to printer share
Dim objPrinter    'Object reference to printer
Dim strMsg        'Message output to user
Dim blnError      'True / False error condition
blnError = False
'Build path to printer share
strPrtPath = "\\" & strPrtServer & "\" & strPrtShare
'Test to see if shared printer exists.
'Proceed if yes, set error condition msg if no.
Set objPrinter = GetObject _
("WinNT://" & strPrtServerDomain & "/" & strPrtServer & "/" & _ 
strPrtShare)
If IsObject( objPrinter ) AND _
(objPrinter.Name <> " AND objPrinter.Class = "PrintQueue") Then
'Different mapping techniques depending on OS version
If objWshShell.ExpandEnvironmentStrings( "%OS%" ) = "Windows_NT" Then
Err.Clear
'Map printer
objWshNetwork.AddWindowsPrinterConnection strPrtPath
Else
'Mapping printers for Win9x & ME is a pain and unreliable.
End If
Else
blnError = True
End IF
'Check error condition and output appropriate user message
If Err <> 0 OR blnError = True Then
strMsg = "Unable to connect to network printer. " & vbCrLf & _
"Please contact the Helpdesk @ ext 345" & vbCrLf & _
"and ask them to check the " & strPrtServer & " server." & _
vbCrLf & vbCrLf & _
"Let them know that you are unable to connect to the '" _
& strPrtShare & "' printer"
objWshShell.Popup strMsg,, "Logon Error !", 48
Else
Call UserPrompt ("Successfully added printer connection to " & _ 
strPrtPath)
End If
Set objPrinter = Nothing
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Mapping a drive to a shared folder

This routine is where the drive mapping occurs. It first removes any preexisting drive mapping that might be using the designated drive letter. Then, it verifies that the share is accessible and creates the mapping. If the share is not accessible, the user will be prompted with an error message that lets him know he should call the help desk.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub:      MapDrive
'
' Purpose:  Map a drive to a shared folder
'
' Input:
'           strDrive    Drive letter to which share is mapped
'           strServer   Name of server that hosts the share
'           strShare    Share name
'
' Output:
'
' Usage:
'           Call MapDrive ("X:", "StaffSvr1", "StaffShare1")
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub MapDrive( strDrive, strServer, strShare )
On Error Resume Next
Dim strPath       'Full path to printer share
Dim blnError      'True / False error condition
blnError = False
'Disconnect Drive if drive letter is already mapped.
'This assures everyone has the same drive mappings
If objFileSys.DriveExists(strDrive) = True Then
objWshNetwork.RemoveNetworkDrive strDrive, , True
End If
'Build path to share
strPath = "\\" & strServer & "\" & strShare
'Test to see if share exists. Proceed if yes, set error condition if no.
If objFileSys.DriveExists(strPath) = True Then
Err.Clear
objWshNetwork.MapNetworkDrive strDrive, strPath
Else
blnError = True
End If
'Check error condition and output appropriate user message
If Err.Number <> 0 OR blnError = True Then
'Display message box informing user that the connection failed
strMsg = "Unable to connect to network share. " & vbCrLf & _
"Please contact the Helpdesk @ ext 345 and ask them " & _
"to check the " & strServer & " server." & vbCrLf & _
"Let them know that you are unable to connect to the " & _
"'" & strPath & "' share"
objWshShell.Popup strMsg,, "Logon Error !", 48
Else
Call UserPrompt ("Successfully added mapped drive connection to " & strPath)
End If
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Gathering local group memberships

This routine collects information about any local groups to which the user might belong. The names of these groups get placed into the strUserGroups variable for future reference.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub:      GetLocalGroupMembership
'
' Purpose:  Gather all local groups to which the current user belongs
'
' Input:
'
' Output:   Local group names are added to strUserGroups
'
' Usage:    Call GetLocalGroupMembership
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub GetLocalGroupMembership
On Error Resume Next
Dim colGroups   'Collection of groups on the local system
Dim objGroup    'Object reference to individual groups
Dim objUser     'Object reference to individual group member
'Verify system is not Windows 9x or ME
If objWshShell.ExpandEnvironmentStrings( "%OS%" ) = "Windows_NT" Then
'Connect to local system
Set colGroups = GetObject( "WinNT://" & strWorkstation )
colGroups.Filter = Array( "group" )
'Process each group
For Each objGroup In colGroups
'Process each user in group
For Each objUser in objGroup.Members
'Check if current user belongs to group being processed
If LCase( objUser.Name ) = LCase( strUserID ) Then
'Add group name to list
strUserGroups = strUserGroups & objGroup.Name & ","
End If
Next
Next
Set colGroups = Nothing
End If
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Gathering global group memberships

This routine is similar to the previous one, except it collects information about any global (rather than local) groups to which the user might belong. The names of the groups also get placed into the strUserGroups variable for future reference. Since some users might still be running Windows NT domains, I use the WinNT syntax instead of LDAP to perform the query, for cross-platform interoperability. This way is a little easier anyway.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub:      GetGlobalGroupMembership
'
' Purpose:  Gather all global groups the current user belongs to
'
' Input:
'
' Output:   Global group names are added to strUserGroups
'
' Usage:    Call GetGlobalGroupMembership
'
' Notes:    Use WinNT connection method to be backwards
'           compatible with NT 4 domains
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub GetGlobalGroupMembership
On Error Resume Next
Dim objNameSpace
Dim objUser
Const ADS_READONLY_SERVER = 4
Set objNameSpace = GetObject( "WinNT:" )
'Use the OpenDSObject method with the ADS_READONLY_SERVER
'value to grab the "closest" domain controller
'Connect to user object in the domain
Set objUser = objNameSpace.OpenDSObject( _
"WinNT://" & strDomain & "/" & strUserID, ", ", ADS_READONLY_SERVER)
'Process each group
For Each objGroup In objUser.Groups
'Add group name to list
strUserGroups = strUserGroups & objGroup.Name & ","
Next
Set objNameSpace = Nothing
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Determining if user belongs to a specified group

This simple routine searches the list of group names that is contained in the strUserGroups variable for the specified group and returns True if the group is found.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Function: InGroup
'
' Purpose:  Determine if user belongs to specified group
'
' Input:    Name of group to test for membership
'
' Output:   True or False
'
' Usage:    If InGroup("Domain Admins") Then <do something>
'
' Requirements:
'           strUserGroups must have been previously populated via
'           GetLocalGroupMembership and/or GetGlobalGroupMembership
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function InGroup(strGroup)
On Error Resume Next
InGroup = False
'Search strUserGroups for strGroup
If Instr( 1, LCase( strUserGroups ), LCase( strGroup ), 1) Then InGroup = True
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Gathering basic information about the local system

Here is another routine that gathers specific information about the local computer, such as the user domain, workstation name, product type, and the path to the location from which the script is running.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub:      GetSystemInfo
'
' Purpose:  Gather basic information about the local system
'
' Input:
'
' Output:   strDomain, strOSProdType, strWorkstation, strLogonPath
'
' Usage:    Call GetSystemInfo
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub GetSystemInfo
On Error Resume Next
'Get domain name
If objWshShell.ExpandEnvironmentStrings( "%OS%" ) = "Windows_NT" Then
strDomain = objWshNetwork.UserDomain
Else
strDomain = objWshShell.RegRead( "HKLM\System\CurrentControlSet\" & _
"Services\MSNP32\NetWorkProvider\AuthenticatingAgent" )
End If
'Get Product Type from Registry (WinNT, LanmanNT, ServerNT)
strOSProdType = objWshShell.RegRead( _
"HKLM\System\CurrentControlSet\Control\ProductOptions\ProductType")
'Get computer name
If IsTerminalServerSession = True Then
'Set strWorkstation to the real name and not the name of the server
strWorkstation = objWshShell.ExpandEnvironmentStrings( "%CLIENTNAME%" )
Else
strWorkstation = objWshNetwork.ComputerName
End If
'Get the path to the location from where the script is running
strLogonPath = Left( Wscript.ScriptFullName, _
( InstrRev( Wscript.ScriptFullName, "\") -1))
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Determining if the script is running in a terminal server session

The following routine identifies whether the user is logging on via a Windows terminal session and returns True if this is the case. The determinant test criteria is whether the workstation has a valid %ClientName% environment variable set.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Function: IsTerminalServer
'
' Purpose:  Determine if the script is running in a terminal server session
'
' Input:
'
' Output:
'           True if running in a terminal server session
'           False if not running in a terminal server session
' Usage:
'           If IsTerminalServerSession = True Then <Do Something>
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function IsTerminalServerSession
On Error Resume Next
Dim strName
'Detect if this is a terminal server session
'If it is, set some names to the terminal server client name
strName = objWshShell.ExpandEnvironmentStrings( "%CLIENTNAME%" )
If strName <> "%CLIENTNAME%" AND strName <> " Then _
IsTerminalServerSession = True
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Setting up IE for use as a status message window

I like to use Internet Explorer as a general status message screen for users. This routine gets Internet Explorer set up and ready for this purpose.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub:      SetupIE
'
' Purpose:  Set up Internet Explorer for use as a status message window
'
' Input:
'
' Output:
'
' Usage:    Call SetupIE
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub SetupIE
On Error Resume Next
Dim strTitle    'Title of IE window
Dim intCount    'Counter used during AppActivate
strTitle = "Logon script status"
'Create reference to objIntExplorer
'This will be used for the user messages. Also set IE display attributes
Set objIntExplorer = Wscript.CreateObject("InternetExplorer.Application")
With objIntExplorer
.Navigate "about:blank"
.ToolBar   = 0
.Menubar   = 0
.StatusBar = 0
.Width     = 600
.Height    = 350
.Left      = 100
.Top       = 100
End With
'Set some formating
With objIntExplorer.Document
.WriteLn ("<!doctypel public>")
.WriteLn   ("<head>")
.WriteLn    ("<title>" & strTitle & "</title>")
.WriteLn     ("<style type="text/css">")
.WriteLn      ("body {text-align: left; font-family: arial; _
font-size: 10pt}")
.WriteLn     ("</style>")
.WriteLn   ("</head>")
End With
'Wait for IE to finish
Do While (objIntExplorer.Busy)
Wscript.Sleep 200
Loop
'Show IE
objIntExplorer.Visible = 1
'Make IE the active window
For intCount = 1 To 100
If objWshShell.AppActivate(strTitle) Then Exit For
WScript.Sleep 50
Next
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Using IE as a status message window

Finally, the last routine is just a little helper for the status message window. There's nothing fancy going on here.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub:      UserPrompt
'
' Purpose:  Use Internet Explorer as a status message window
'
' Input:    strPrompt
'
' Output:   Output is sent to the open Internet Explorer window
'
' Usage:
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub UserPrompt( strPrompt )
On Error Resume Next
objIntExplorer.Document.WriteLn (strPrompt & "<br />")
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub:      Cleanup
'
' Purpose:  Release common objects and exit script
'
' Input:
'
' Output:
'
' Usage:    Call Cleanup
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub Cleanup
On Error Resume Next
Set objFileSys     = Nothing
Set objWshNetwork  = Nothing
Set objWshShell    = Nothing
Set objIntExplorer = Nothing
'Exit script
Wscript.Quit( )
End Sub

Running the Hack

Since I still have a few NT clients on my network, I place a batch file named logon.bat in the NETLOGON shares on my domain controllers. All users are then assigned this logon.bat file as their startup script. This logon.bat file verifies that the user is on a supported platform (NT, 2000, or XP) and then kicks in the logon.vbs script via a call like this (depending on the path to the script):

cscript //nologo %0\..\logon.vbs

To keep the user informed of the logon progress, status messages are posted to an Internet Explorer window.

These are the three results of running the logon script:

The user gets the appropriate printer added.

The user gets mapped drives added where appropriate.

The user's homepage is reset (depending on group membership and computer name).

This sample logon script can prove useful for small organizations. However, storing all the mapping information in the script can soon become unwieldy. If you are in a large organization and want to perform tasks at logon based on computer names, it might be best to offload the mapping information to a network database that can be queried via the logon script.

Dan Thomson