Setting scriptmaps: step one
The first step in setting the proper scriptmaps is to decide what method we'll use to set them on the target machine at install time. While there might be several ways to do this, the simplest and most direct is to execute the tool aspnet_regiis.exe which was installed with the .Net 2.0 Framework, and the simplest and most direct method is always best with installation. Each framework has its own version of aspnet_regiis.exe, and there may be several frameworks installed, so it's critical that we find the right one. Windows Installer provides an AppSearch function for doing this.
We need to add a new AppSearch entry to the MSI. If you crack open your unmodified MSI with Orca, you'll see that there's already one AppSearch entry:
| Property |
Signature_ |
| IISVERSION |
__EBAF7BE89E354100ACD2C1841DCBEEEC |
This searches the registry for the value of the installed Internet Information Server's major version number, then assigns that number to the installer property IISVERSION. It uses a RegLocator table entry to accomplish this; the key is the value of the Signature_ field, and the registry neatly contains the major version number of the installed IIS:
| Signature_ |
Root |
Key |
Name |
Type |
| __EBAF7BE89E354100ACD2C1841DCBEEEC |
2 |
SYSTEM\CurrentControlSet\Services\W3SVC\Parameters |
MajorVersion |
2 |
We don't have a handy registry key to locate the file we're interested in, and guessing the path to the correct version could be quite tricky, so we use an AppSearch referencing a CompLocator table entry instead by adding this row to the AppLocator table:
| Property |
Signature_ |
| REGIISDIR |
REGIIS_COMPLOC |
...and this row to the CompLocator table:
| Signature_ |
ComponentId |
Type |
| REGIIS_COMPLOC |
{72D0920F-8758-4EF8-A415-E6E44332AF49} |
1 |
The ComponentId is the GUID which was associated with the file aspnet_regiis.exe in the v2.0.50727 installer, and type "1" means "return the path to the directory that the file was installed in." To find this GUID I had to crack open the vs_setup.msi which installed Visual Studio 8.0 and search for things like "aspnet_regiis," which really didn't take long (although it might not be obvious.) This sets the value of the REGIISDIR property to the path of the exact version of the utility that we want, or leaves the property undefined if the file is not found.
Then, to get the file spec of the utility which we intend to run we have to add the file name to the path. In an MSI we need to use a built-in Custom Action to accomplish this. We add the following row to the Custom Action Table:
| Action |
Type |
Source |
Target |
| SSMCA_CreateRegIISPath |
51 |
REGIISPATH |
[REGIISDIR]aspnet_regiis.exe |
Type 51 means "take the formatted string in the Target field and evaluate it to set the value of the property named in the Source field. Here evaluating the formatted text means replacing [REGIISDIR] with the value of the property, which we set with the AppSearch entry. Once this Custom Action is performed, we have the full path file spec of the appropriate version of aspnet_regiis.exe in the property REGIISPATH.
But what if the appropriate aspnet_regiis.exe wasn't found? And how is this action performed in the proper sequence? The InstallExecuteSequence table is the key. It lists every standard action and custom action to be performed in the order they're performed, with optional conditions for each step. AppSearch is the very first step in the sequence, so the AppSearch table is evaluated at the beginning of the install and REGIISDIR is set (or not) at this time. We add the following entry to the InstallExecuteSequence table:
| Action |
Condition |
Sequence |
| AppSearch |
|
100 |
| ... |
| SSMCA_CreateRegIISPath |
REGIISDIR AND NOT (REMOVE OR (ACTION~="ADMIN")) |
6450 |
...and our named Custom Action is performed right near the end of the sequence, but only if the property REGIISDIR has a value, if we're not performing a "remove" function (why register scriptmaps while we're removing?) and if we're not performing an administrative installation, which is actually a deployment for later installation rather than an actual product installation.
That's four of our eight changes, and all we've got so far is the path to the utility that we want to run. But it's the right path and we haven't had to do anything risky or unreliable to get it. The rest of the process should all be downhill.
Almost...