Tuesday, August 29, 2006

 

VBScript and %windir%\Registration

I loathe the typical and all to frequent support response to weird desktop issues: reimage it! If your company has an SLA established where by issues that cannot be resolved within a certain time period, yadda, yadda, yadda; but I see it too often where these SLAs don't exist, and folks just jump to reimaging the system when a solution isn't easily available.

Case in point: User logs onto their workstation one morning and receives the error:

Can't find script engine "VBScript" for script \\server\sysvol\domain.com\Policies\{1E6FB511-C1A1-49AB-8E4C-BC34076F683B}\User\Scripts\Logon\Drivemapping.vbs
They click OK and then nothing happens. Explorer doesn't load; you can't even manually start it. Yet when you logon as an administrator, all is well.

Little could be found via Google on this error. I tried a few things (re-register vbscript.dll, reinstall IE6 SP1, patch) - no dice. I was able to replicate the error when logged on as an admin by using runas /user:domain\username "wscript myscript.vbs" which caused the same error. I assumed it was a permissions issue, so I whipped out the handy regmon and filemon tools. Nothing in the regmon capture log (filtered to just wscript) indicated a problem, but filemon quickly showed the source of the problem: access denied to C:\WINNT\Registration\R000000000006.clb. I checked the privs - System & Admins Full Control, Everyone special Read (everything but execute). The permissions were unique to the folder, not inherited from the system root.

The fix:

cacls %windir%\Registration /e /g Users:R
It took me about an hour of total work to come up with a single command-line fix, versus the hours of toil and trouble to backup the user data, reimage the system, replace the data, etc. Of course that's another task for me for a rainy day: automate that process with SMS OSD.... :)

Sunday, August 27, 2006

 

CSG/CWI Interaction

For someone who has been working with Citrix for years, this is probably a very simple concept, but it just "clicked" for me the other day. (You know when a concept is just out of reach but then one day it just clicks and suddenly makes sense? I love it when that happens!)

I'm talking about the interaction between Citrix Secure Gateway (CSG) and Citrix Web Interface (CWI). In some environments, these roles are separated out onto multiple servers so that this interaction makes much more sense, but in my case they are both on the same physical server.

I was having an issue where after I thought I had it all configured and it should be working, the clients were receiving an IIS "Bad Request (Invalid Hostname)" error. It turns out this was because I had defined a host header value on the IIS Default Web Site (used for the Citrix Web Interface).

The SSL certificate for the URL is primarily used by CSG. When the client hits the server on 443, it's talking with CSG. Then CSG internally hits the CWI site at http://localhost, not the URL. I found a post on Brian Madden's forums that suggested for additional security you should configure the IIS website to only listen on 127.0.0.1 instead of a specific external IP or All Unassigned. So removing the host header value from the IIS site fixed my problem, but I also set it to only listen on the local IP and all is still good.

Here's a diagram that I whipped up to show the interaction. I'm very much a visual learner, so I often create things like to this to help me visualize what's happening. The diagram also gives which ports are needed through the firewalls; once setup this is all visible using netstat on each system.

Citrix CSG-CWI Interaction

Monday, August 14, 2006

 

CLI Tab-Completion for Win2k

[HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
"CompletionChar"=dword:00000009


It exists by default in XP. How to Enable Automatic Complete for the Command Prompt implies that it did exist in NT.

I wish I would have found this months ago, since all I have at work (other than my laptop) is Win2k.

Wednesday, August 02, 2006

 

CreatePrinters.vbs

As previously mentioned, I wrote a script to loop through creation of multiple printers.

It makes a lot of assumptions, but does the trick. There are probably better ways to do some of the steps of this script, but again: it works.

CreatePrinters.vbs
' Creates printers on local system from input file
' Input file:
' - Must be plain text
' - No header or whitespace
' - Tab-delimited columns: Printer Name, IP Address, Driver Name, Location, Comment
' Assumptions:
' - The Standard TCP/IP Port will be named IP_%IPADDRESS% where %IPADDRESS% is the input value and it will use the RAW protocol on port 9100
' - The driver will be for Windows 2000/XP/2003 only and must be included with Windows source
' - The share name is the same as the printer name
' - The share will be published
' - The printer will use bi-directional support when available
' - Everything else is the default value
' The resulting printers are as if manually created accepting default values.

' create shell object (used later)
set objWsh = WScript.CreateObject ( "WScript.Shell" )

' create FileSystemObject
set objFSO = WScript.CreateObject ( "Scripting.FileSystemObject" )

' open file, create TextStream Object
set objTSO = objFSO.OpenTextFile ( "printers.txt" )

' loop through the file
Do Until objTSO.AtEndofStream

' read a line
strLine = objTSO.ReadLine

' split the line into an array
strArray = Split ( strLine, vbTab )

' build command lines
strTask1 = "cmd /c cscript %windir%\system32\prnport.vbs -a -r IP_" & strArray(1) & " -h " & strArray(1) & " -o raw -n 9100 > c:\" & strArray(0) & "-1.log"
strTask2 = "cmd /c cscript %windir%\system32\prndrvr.vbs -a -m """ & strArray(2) & """ -v 3 -e ""Windows NT x86"" > c:\" & strArray(0) & "-2.log"
strTask3 = "cmd /c cscript %windir%\system32\prnmngr.vbs -a -p """ & strArray(0) & """ -m """ & strArray(2) & """ -r IP_" & strArray(1) & " > c:\" & strArray(0) & "-3.log"
strTask4 = "cmd /c cscript %windir%\system32\prncnfg.vbs -t -p """ & strArray(0) & """ -l """ & strArray(3) & """ -m """ & strArray(4) & """ -h """ & strArray(0) & """ +shared +published +enablebidi > c:\" & strArray(0) & "-4.log"

' run the commands
objWsh.Run strTask1, 1, 1
objWsh.Run strTask2, 1, 1
objWsh.Run strTask3, 1, 1
objWsh.Run strTask4, 1, 1
Loop

' cleanup
objTSO.Close
set objFSO = Nothing

Sample Input File, printers.txt
Test1 10.10.1.5 HP LaserJet 4100 Series PCL Test Lab Test Printer
Test2 10.10.1.6 HP LaserJet 8150 Series PCL Engineering Rick's printer
Test3 10.10.1.7 HP Business Inkjet 2280 PCL 5C Operations Dave's printer
Using this sample file, Test1 and Test2 are created, Test3 is not because the driver is not in the Windows source.

The script dumps out four log files (one for each task) for each printer, e.g., PRINTER_NAME-1.log, PRINTER_NAME-2.log, PRINTER_NAME-3.log, PRINTER_NAME-4.log. So if you have a lot of printers in the input file, it will create a LOT of log files. Fortunately they are extremely small in size.

Sample Log Files

C:\Test1-1.log
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

Created/updated port IP_10.10.1.5

C:\Test1-2.log
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

Added printer driver HP LaserJet 4100 Series PCL

C:\Test1-3.log
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

Added printer Test1

C:\Test1-4.log
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

Configured printer Test1

If any task fails, the error(s) will be in the log file for that task. If any one step fails, all later tasks for that printer will also fail.

 

Password Change Errors

I changed my password today. And then promptly forgot it. It was obivously too complicated, because after a meeting, I could not unlock my Win2k workstation. So I asked a fellow admin to reset my password; he did not set "must change password at next logon." So When I went to manually change my password, I received the "your password is not complex" message. I tried a variety of complex passwords, including

RiadBsc-0
(Prohe, can you figure out the source of this?)

4 of 4 by 9, no part of my name, not similar to a previously used password. WTF?

It turns out, policy has a two day password maximum. SO WHY DIDN'T THE ERROR MESSAGE SAY SO! Comma DAMNIT!

<grumble>

Prohe, here's a hint: WuiAccountCreator :)

 

Scripting Printer Creation

Windows XP and Windows 2003 include the following scripts in %windir%\system32 for CLI printer management

Prncnfg.vbs
Prndrvr.vbs
Prnjobs.vbs
Prnmngr.vbs
Prnport.vbs
Prnqctl.vbs

This is (IMO) much improved over the printui.dll hackery.

While there's some basic usage info out there on these scripts, I couldn't find anything that gives any good practical advice; aka "notes from the field."

Scenario: you have to create 50 printers on a print server. You have the following data: Name, Location, IP, Driver Name. Some additional assumptions: you only have Win2k/XP clients, you want to share each printer consistently, and default permissions (Everyone: Print) are sufficient.

There are four steps you need to do:
1. Create the port
2. Install the driver
3. Create the printer
4. Configure the printer

A sample script:
cscript C:\WINDOWS\system32\prnport.vbs -a -r IP_10.10.1.5 -h 10.10.1.5 -o raw -n 9100
cscript c:\WINDOWS\system32\prndrvr.vbs -a -m "HP LaserJet 4100 Series PCL" -v 3 -e "Windows NT x86"
cscript c:\windows\system32\prnmngr.vbs -a -p "Test1" -m "HP LaserJet 4100 Series PCL" -r IP_10.10.1.5
cscript C:\WINDOWS\system32\prncnfg.vbs -t -p "Test1" -l "Test Lab" -m "Comment" -h Test1 +shared +published +enablebidi

Line 1 creates the port named "IP_10.10.1.5" with the IP address 10.10.1.5, using RAW protocol on port 9100.

Line 2 installs the HP LJ 4100 PCL driver for Windows 2000/XP clients.

Line 3 creates the printer named "Test1" using the previously created port and driver.

Line 4 sets the location "Test Lab", comment "Comment", shares and publishes it as "Test1" and enables bi-directional support (if available).

The result is a shared printer identical to as if you had done it manually accepting the default settings.

I haven't yet written a script to loop through these commands with the input data for all 50 printers, but that will come shortly (and depending upon how well I do it I may or may not post it).

This page is powered by Blogger. Isn't yours?