Redirecting HTTP to HTTPS, part DUH.

It always helps to know what you are doing…

After much head bashing and tooth gnashing, I discovered that the real reason that most people recommending a solution to this problem present a client-side redirect is pretty simple:

When browsers swith from a http:// rooted URI to a https:// rooted URI, they effectively assume that they are switching to a new website (which, effectively, they are).

So, I implemented a client-side redirect by replacing the default “https required” IIS 403.4 error page with a custom page containing this javascript code:

<Script language="JavaScript">
<!-- begin hide

function goElseWhere()

var oldURL = window.location.hostname + window.location.pathname;

var newURL = “https://” + oldURL;

query = ” + window.location;
position = query.indexOf(‘?’);
if (position > -1)
query = query.substring(position + 1);
newURL = newURL + “?” + query;

window.location = newURL;


// end hide –>

Unfortunately, this still does not work for MS Office programs. Office refuses to recognize a redirect request (be it either server or client based), so anyone attempting a manual save to an http:// rooted URI will just get an error. Nothing to be done for it… it is an office bug. Report it to the Office team, it is not my fault.

Additional SAV installer builder instructions, updated script

Upon reviewing my earlier notes on building installers, it appears that I left out some useful info on how to build the darned administrative installation point that I am using to wrap up the patched installer. Since I had the “opportunity” to work on a v10.1.0.400 installer today, I will take this opportunity to actually document my installer builder process:

  • open a CMD shell, CD to the SAV directory on the Symantec installation media
  • extract the MSI files to a local “administrative installation point”:
    msiexec /a "Symantec Antivirus.msi"
  • Now, extract any patches downloaded from Symantec and CD to the directory that has the MSP patch file. Execute the following:
    msiexec /p "SAVCE-[version].msp" /a [path to admin install point] 
  • Now, copy the setup.exe, setup.ini, msi installer files, and that .ini file with the funny name from the SAV source directory into the “administrative installation point” directory used above.
  • Edit the “setup.ini” file in your admin install point. Modify the product version string to more closely match the version just overlayed onto the installer.
  • Copy in your custom SAV installer script. (In our case, we use “instsav.cmd”). Generally I just copy his out of the last production installer. Also grab the sav-managed.txt and sav-unmanaged.txt files from the previous installer. These just contain informational text to be pasted into the self-extracting archive prompt dialogs.
  • Now you can wrap the whole directory into a self-extracting archive, which spawns “instsav.cmd” when extraction is complete. Of late, I have been using WinRAR. Since the 10.0.1 builds, I have been extracting the archive to “%SYSTEMDRIVE%\SAVInst”, with the option to leave the extracted files in place after installation (thus creating a local installation source). You may note that the instsav.cmd installation script uses this directory path to launch the setup.exe program.

Also note that I have made some significant changes to the instsav.cmd script. Mostly I just deleted unused sections of the script… version 10.1 does not appear to bog down the computer doing “startup scans” and “Definition scans” as earlier versions did, so I am removing the custom registry key imports that halted these scans. Also, I changed the IF NOT ERRORLEVEL 1 clauses to use the syntax “IF %ERRORLEVEL% GEQ 1” instead, as this seems rather easier to understand from a logical perspective, IMO. Anyway, here is the script:

ECHO - Symantec Antivirus installation script for the University of Vermont
ECHO - version 2.6, by JGM, 2006-05-15
ECHO - This Window will close automatically when installation has completed.
REM Script can be altered to allow for either managed or unmanaged client installations.
REM For managed installs, UN-comment the "goto endFirewall" line below, and uncomment the appropriate "setup" command line.
REM For unmanaged installs, COMMENT OUT the "goto endFirewall" line below, and uncomment the appropriate "setup" command line.
REM History:
REM V2.3 - changed "reg import" commands to "regedit /s" commands for Windows 2000 compatibility.
REM v2.5 - changed setup to generate MSI error log (/le option), and to run out of %SystemDrive%\SAVInst dir created by RAR extractor.
REM v2.6 - removed the "removeStartScan.reg" procedure after the :endFirewall tag, and an experiment for v10.1.x distribution, cleaned up un-used sections, substituted "IF %errorlevel% GEQ 1" instead of "IF NOT errorlevel 1" as a experiment.
REM If performing an unmanaged AntiVirus client installation, uncomment the following line:
GOTO endFirewall
REM Determine if host is running a Windows XP build:
set OSVer=notXP
ver | find /i "xp" && set OSVer=XP
IF NOT %OSVer%==XP GOTO unsupported ELSE goto spLevel
REM Determines Service Pack Version via registry query:
set SPVer=0
REM systeminfo |find "Service Pack 1" && set SPVer=1
REM systeminfo |find "Service Pack 2" && set SPVer=2
reg QUERY HKLM\SYSTEM\CurrentControlSet\Control\Windows /v CSDVersion | find "0x200" && set SPVer=2
IF NOT %SPVer%==2 GOTO unsupported ELSE GOTO addRules
REM Adds firewall exceptions for Windows XP SP2 hosts:
ECHO - You have Windows XP Service Pack 2!  Let's Go...
ECHO - Please wait while firewall exception rules are added...
ECHO Adding exception for Symantec Realtime Virus Scan to allow managmenet of SAV Client
@netsh firewall add portopening protocol = UDP port = 2967 name = "Symantec RTVScan" mode = ENABLE scope = CUSTOM addresses = LocalSubnet,, profile = ALL
IF %errorlevel% GEQ 1 (
	GOTO failRuleAdd
	) ELSE (
	ECHO Firewall rule added successfully.
@netsh firewall add portopening protocol = UDP port = 38293 name = "Intel PDS (Symantec AV)" mode = ENABLE scope = CUSTOM addresses = LocalSubnet,, profile = ALL
IF %errorlevel% GEQ 1 (
	GOTO failRuleAdd
	) ELSE (
	ECHO Firewall rule added successfully.
GOTO endFirewall
ECHO Your system is not running XP with Service Pack 2.
ECHO You do not need firewall exceptions added to your system.
GOTO endFirewall
ECHO Deleting log files from previous installations...
@del /f /s /q "%ALLUSERSPROFILE%\Application Data\Symantec\Symantec AntiVirus Corporate Edition\7.5\Logs"
IF %errorlevel% GEQ 0 (
	ECHO No previous Symantec AV log files needed to be deleted.
	) ELSE (
	ECHO Symantec AV Log files successfully deleted.
@del /f /s /q "%ALLUSERSPROFILE%\Application Data\Symantec\Norton AntiVirus Corporate Edition\7.5\Logs"
IF %errorlevel% GEQ 0 (
	ECHO No previous Windows 2000/XP Norton AV log files needed to be deleted.
	) ELSE (
	ECHO Norton 2000/XP AV Log files successfully deleted.
ECHO Proceeding with SAV install...
REM One of the following two "setup" lines MUST BE COMMENTED OUT!
REM installation string for an UNMANAGED client install (intended for off-campus users):
"%SystemDrive%\SAVInst\setup" /s /qn /V"/qb /le %SystemDrive%\SAVInst\install.err REMOVE=Pop3Smtp,NotesSnapin ADDLOCAL=SAVMain,SAVUI,SAVHelp,QClient,OutlookSnapin NETWORKTYPE=2 RUNLIVEUPDATE=0 SYMPROTECTDISABLED=1"
REM installation string for a MANAGED client install (intended for systems that are frequently on-campus):
REM "%SystemDrive%\SAVInst\setup" /s /qn /V"/qb /le %SystemDrive%\SAVInst\install.err REMOVE=Pop3Smtp,NotesSnapin ADDLOCAL=SAVMain,SAVUI,SAVHelp,QClient,OutlookSnapin NETWORKTYPE=1 SERVERNAME=NORTON2 RUNLIVEUPDATE=0 SYMPROTECTDISABLED=1"
ECHO Product setup complete.
GOTO end
ECHO Firewall exceptions script failed!
ECHO Symantec AntiVirus NOT INSTALLED.
ECHO Take your system to Walk-in help.
GOTO end

Redirecting HTTP traffic to HTTPS in IIS

What a pain… I shore up security in IIS I reallly will need to redirect all traffic on sharepoint to HTTPS connections. It is easy to turn on SSL, but harder to automatically redirect traffic. There are many approaches to this problem, which take the form of two basic solutions:

  • Client side redirection
  • Server side redirection

With the first approach, we direct the client to a custom error page that tells the browser to reconnect to the same URI, but with an HTTPS protocol. This can be done with javascript or .asp. Either way, the disadvantage is that form and query data likely will be lost in the dedirect. At least with the Javascript approach, you lose browse ability from MS Office applications as well.

The second approach will rewrite the URL at the server, thus preserving all URL data such as form and query info. However, this approach requires custom code to be added to IIS in the form of either an ISAPI filter or web service extension. These add-on programs frequently have conflicts with the STSFLTR (Sharepoint ISAPI filter).

I have tried a lot of junk… here are some links:
– General how-to on using .asp custom error pages for client side redirect… includes security configuration details, but lacks specific syntax.
– A powerful ASP.NET module to be added to your site config files. This allows per-directory auto-SSL redirection. Looks promising, but it is too much for my feeble mind to precess at present.
– Another ASP redirect script.
Note that in the feedback on this page is some excellent Javascript to accomplish client side redirection… I think this is the solution I will have to go with.

I also have tried (extensively) several ISAPI filters which emulate the Apache “mod_rewrite”. This filters work great on other IIS web sites, but not with Sharepoint… GRRRR!

Using BartPE for system cloning

I have come across the need image sevaral servers in preparation for migrating them to new “hardware”. (The actual situation is that I have several systems running on VMWare Server Beta (formerly GSX Server), and I want to migrate them to ESX server. Since the two virtual servers use different disk formats, I cannot simply copy the virtual disks, I need to clone them using some other third-party tool. Further complicating the matter is that I plan to install ESX server on the SAME HOST that is currently running GSX, and ESX wants to take control of the ENTIRE local hard drive.)

After exploring the options, I decided to take advantage of our existing license pool for Symantec Ghost 8.0 (I had considered using MS XImage, but I am still seeing this as a beta product, and more trouble than it is worth on this particular project). Now the question is HOW to use Ghost.

I came across this excellent resource for “P2V” migrations, which also should work well for V2V (Virtual to Virtual):
This manual comes from the following page:

So, “all I had to do” was download pebuilder (which I had already done), drop the vmxnet and vmscsi drivers into the appropriate pebuilder drivers directory (already done), then activate the additional plug-ins that they provide for the vmware tools. I then needed to switch my pebuilder sources from the windowx XP i386 directory to a server 2003 i386 directory.

Ghost configuration was really easy, as pebuilder already has a ghost 8 plug in. I jest needed to extract the ghost files documented in the plugin help file into the pebuilder directory structure. Voila!

A few minutes later I had an .iSO which I mounted on VMWare and successfully booted! I am able to use “net use” to map a network drive, and then run ghost32.exe to dump an image to a separate workstation on the network.

WinPE: Building from the Windows Vista AIK Beta

So, workstation image capture is now performed using “XImage.exe” (soon to be renamed ImageX.exe). Although multiple capture methods are supported, use of Windows PE 2.0 is encouraged.

I obtained the February CTP of the Windows Automated Installation Kit (AIK). This contains several utilities for working with and creating Windows “WIM” image files, and also includes WIMs for Windows PE 2.0.

Here is the process I am working on for building a bootable Windows PE image:

  1. Install the Windows AIK
  2. cd %ProgramFiles%\Windows AIK\Tools\x86 (this directory contains all of the CLI tools for WinPE image building)
  3. mkdir \winpebuild\build
  4. ximage /apply boot.wim 1 c:\winpebuild\build (this extracts image index “1” from the boot.wim in the AIK directory to the specified build directory. All of the WinPE files are now available on the local NTFS drive)
  5. To install additional network drivers to the PE build:
    peimg /inf=[path to NIC driver INF] c:\winpebuild\build\windows
  6. copied “ximage.exe” and all other .dll files from the working AIK directory to c:\winpebuild\build\windows\system32
  7. Now save a copy of the working build directory, as the next step will make irreversable changes to the build directory:
    ximage /capture c:\winpebuild\build c:\images\winpe1.wim “Custom Base Image” /compress /max
    (this captures the build directory to a WIM file “winpe1.wim” with descriptor “Custom Base Image”, using maximum image compression to save drive space.)
  8. Now we prepare the build directoryfor capture. This step optimizes the build, but also prevents future use of the “peimg /inf” command:
    peimg /prep c:\winpebuild\build\windows
  9. Now we generate a WIM file of our customized build:
    ximage /capture c:\winpebuild\build c:\winpebuild\boot.wim “WinPE Image with VMWare Drivers” /boot /compress max
  10. In the next steps we create a separate directory structure which from which we will build a bootable .ISO WinPE image:
    mkdir \winpe\sources, mkdir \winpe\boot
  11. copy bootmgr c:\winpe
  12. xcopy /cherky .\boot c:\winpe\boot (relative to the working x86 AIK directory) (these three steps add files necessary for building a bootable ISO to the directory structure)
  13. ximage /boot /export /compress max c:\winpebuild\boot.wim 1 c:\winpe\sources\boot.wim (copies the custom WIM to the new directory scructure… I wonder if I could just use “xcopy”?)
  14. oscdimg /n /b.\boot\ c:\winpe c:\winpe.iso (creates a bootable ISO from the boot.wim using the boot code in “”.)

AARGH! It just does not work still! No networking is available when I boot to WinPE!!!!

Windows Deployment Services – Installing on VMWare

Got my hands on the WDS beta from Microsoft. Looks like a huge improvement on RIS, although the documentation really leaves something to be desitred at this point. Key features:
– Image-file based service. Uses the new “WIM” image format.
– Tools provided to edit WIM images (ie. drop in Microsoft Hotfixes and service packs)
– Improved GUI and CLI tools for managing images
– Unified answer file format for all installations
– Migration tool to allow RIS file-based image to WIM image conversion!
– WinPE-based process, uses “real” network drivers, and has more client-side options for image capture (ie. capture to local image, capture to network share). Capture can be performed independently from the WDS server.

Anyway, I installed WDS on a VMWare instance of 2003 SP1 server. The procedure was fairly straightforward:
– Install Remote Installation Services from the Add/Remove Windows Components Wizard
– Install the WDS “hotfix” (this changes the name of the RIS service from “binlsvc” to “WDSServer”.
– Initialize WDS using either the CLI “WDSUtil”. I used the CLI, but it would seem that the GUI may be better as there is more thorough prompting for installation image media.

Following installation, I had some trouble getting another VMWare host to net-boot to the WDS server. I then tried isolating the hosts onto the VMWare “host-only” network with no further luck. Eventually I read the VMWare documentation:

As it turns out, VMWare runs a virtual DHCP server on the host-only and NAT virtual network adapters (this is kind of a “duh” if you think about it. By going into the VMWare “Host” menu, then selecting “Virtual Network Settings”, I am able to disable the DHCP server. Now my other virtual hosts boot to the WDS server promptly. Cool!

Now I just have to igure out how to get some images into the system…

I plan to switch to NAT networking so that I can communicate with external systems where I intend to capture the WIM images.

Sharepoint test server configuration

I am attempting to set up a test sharepoint server environment to deploy the current production environment. This will contain a copy of the prod sharepoint Content DB, and will reflect the same general conrfiguration:
-Kerberos authentication
-separate service account for Sharepoint content managment and Sharepoint configuration
-SQL DB server and Sharepoint web components run on separate OS instances
-Sharepoint installed on non-default IIS site, using host headers to direct users to the secondary IP (do we really need a secondary IP???)

I am having some difficulties around Kerberos auth and also with prod DB import. Here are some helpful links:

Hunting down and exterminating uncompressed TIFFs

It seems that some of our constituients have not been paying overly much attention to the settings on their scanners. We have over 40Gb of black-and-white, text-only documents scanned at 24 BPP, uncompressed, consuming 10 Mb each!

This happened once before. My colleague Warren licensed a product called “2TIFF” to shrink the files in question. This works well, except in his case ALL of the images in an Application folder needed to be compressed. I only need to shrink SOME of them.

After much fooling around and wasting of time, I was able to use a win32 port of the UNIX “find” command to hunt down all of the large files, dump the list to a file, and then use this file as a source for 2TIFF. The big mess of images now occupies only about 30 Mb of space.

Here are the sommand syntax details:
> find.exe “I:\OBJECTS\PURCHASE_ORDERS” -size +3M -fprint bigfiles.txt
(searches the PURCHASE_ORDERS document tree for all files larger then 3 Mb, dumps results to the text file “bigfiles.txt)

> FOR /f %F in (bigfiles.txt) DO ( “C:\Program Files\2TIFF\2tiff” s=%F d=%~dF\shrink%~pF -namegen=”[name].[srcext]” -quantize8 -ct4 -cd4 -keepexif)
(Perform a loop operation. For each loop, set the next line in bigfiles.txt to the variable %F. Run the 2Tiff program using %F as the source file. Use \shrink as the output directory (example: when %F=”c:\objects\procurement\1\163.bin, the output directory will be “c:\shrinkProcurement\1\”).)

Here is what the 2Tiff arguments mean:
-namegen=”[name].[srcext]” -> The name of the destination file is the same as that of the source ([name] is a built in variable equal to the source file name. [srcext] equals the source file’s extention)
-quantize=8 -> sets the “quantization” level of the TIFF. This value effects the “sampling rate” and affects image quality. Eight is the maximum value, for best quality.
-ct4 -> Compression type “LZW” is used. This is the default type for color scans. We are using LZW rather than the standard “type 3” for B/W documents because tests showed that reducing these images to monochrome yielded very low quality in some cases. We are keeping some color information to allow anti-aliasing and thus better letter quality.
-cd4 -> Sets the color depth down to 4 BPP from the source 24 BPP. CD1 would be better, but as mentioned above, this results in poor readability of the destination TIFF.
-keepexif -> preserves EXIF tags in the destination file from the source. Probably there is no EXIF info in these files, but I thought we would keep it in case I am wrong.

Warren had used the “dither” switch, but IMNSHO this makes the target document look worse and also results in larger files.

Fixing the RIS image store

Our server “SYSIMG1” just does not seem to want to take on its new role of replacement RIS server. I guess it just liked being a NetWare box and resents its lot in life.

Robocopy of the image library from \\risprime\reminst is consistently a failure. I run out of drive space every time, and the Gorveler never frees up enough drive space to resume copy operations.

I followed MS advice from the KB and have tried using our backup software (Legato) to restore the whole image partition to SYSIMG1 from RISPRIME. This generally caused BSOD errors on SYSIMG1. This particular problem cleared up after I patched the iSCSI initiator from v2.0.0 to v2.0.1, set the “lanmanserver” “binlsvc” (RIS Service) and “groveler” services to be dependent on “MSiSCSI” (the iSCSI initiator service), and also disabled a misconfigured secondary NIC on the server. Now I can restore the RISPRIME volume, but the groveler does not want to start.

So, I seem to have fixed that problem by “repairing” the SIS database on the volume… (where repair=deleted the damn thing, and let the Groveler start over). The article in question is here:;en-us;247611

And here is the key information:
The SIS Groveler service database is stored in the hidden folder named SIS Common Store on each SIS managed volume. To rebuild the Groveler service database, follow these steps:
1. Stop the Single Instance Storage Groveler service.
2. Make a backup copy of the SIS Common Store folder contents to an alternate location.
3. After a backup copy of the folder contents have been made, remove all the database files in the SIS Common Store folder EXCEPT for the *.SIS and the MAXINDEX files.
4. Restart the Single Instance Storage Groveler service.

NOTE: I had to run RISetup prior to successful restart of the Groveler. All of the configuration settings for the groveler are set by RISetup. Once this is done, the gorveler restarts, and a new .mdb gets generated in the SIS directory.

SAV release, and install script updates

I made some more changes to the script and installer package:

– Decided to converge on the “Administative Install” method for wrapping the patches into the installer. This prevents the installed SAV instance from interfering with the patch portion of the install script. Features like “autoprotect” were preventing “msiexec /p” from working. Also, msiexec /p seems just plain unpredictable if the system has not been rebooted. I just don’t feel like injecting actions into the “RunOnce” registry key, or attempting to force a reboot.

– Added “AUTOPROTECT=OFF” to the msi options portion of the setup.exe line in the install script. This will prevent the SAV autoprotect from giving us grief while installation completes.

– Used WinRAR options to extract archive files to a specified directory: %SystemDrive%\SAVInst.
(this will cause a local cache of the install files to be maintained on the system)
(NOTE: We may wish to add a script line to delete the contents of this archive on reinstall)

– Mod the setup.ini file to contain a higher version number for the product being installed than the default (this should allow the setup.exe to install over existing SAV10 installs)

– Added an error logging option to the MSI options portion of the setup.exe line in the script (-le %SystemDrive%\SAVInst\install.err)

– Prefixed the setup.exe line with %SystemDrive\SAVinst\ to force run out of the directory created by the WinRAR extractor.