\
MAKEMSI Installs...
Samples Installed by MAKEMSI
Samples - Build New MSI/MSM
TryMeCreateIisSite.MM
This is one of the MAKEMSI samples which build a new MSI/MSM.
This MSI makes use of these "TryMe.MM" files:
- TryMe.ver
- TryMe.rtf
See the Internet Information Services Applet to see
how the created web sites look in that tool.
You should also be sure to read the "IIS configuration"
section of this manual.
;----------------------------------------------------------------------------
; MODULE NAME: TryMeCreateIisSite.MM
;
; $Author: USER "Dennis" $
; $Revision: 1.3 $
; $Date: 01 Nov 2006 17:38:20 $
; $Logfile: C:/DBAREIS/Projects.PVCS/Win32/MakeMsi/TryMeCreateIisSite.MM.pvcs $
;
; DESCRIPTION
; ~~~~~~~~~~~
; Demonstrates a number of IIS things, it creates web sites under the
; default plus a new one under port 1234.
;
; The code backups the metabase but I highly recommend before testing any
; code that modifies the metabase that you also MANUALLY back it up to be
; obsolutely positive you have something you can restore.
; The IIS/ADSI bit can easily get stuffed up while you are "playing"
; around.
;
; Personally I would always use an "IisWebVirtualDir" over an
; "IisWebDirectory" (where possible) and you can google these class
; names or any of the properties or methods demonstrated here to find
; documentation or other example code.
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
;--- Some configuration for this script -------------------------------------
;----------------------------------------------------------------------------
#define IIS_IS_RESTRICTED_TO_1_SITE_AT_A_TIME Y ;;Y/N - WIN2000/WINXP PRO won't allow secondary sites to start (licencing)
#define BACKUP_IIS_CONFIGURATION_TO_PLAY_SAFE Y ;;Y/N
#define IIS_SUPPORTS_APPPOOLS N ;;Y/N - Certainly WINXP PRO doesn't...
#define DEBUG_USER_ADSI_PROPERTY_ASSIGNMENT Y ;;Y/N - Add some debug code....
#define IIS_STOP_START_SERVICES N ;;Y/N - Used to always do, but lately haven't found the need (maybe IIS fixes etc!)...
#define IIS_MAX_BACKUPS_PER_DAY 1 ;;No more than this number will be made per day (0= No restriction)
;----------------------------------------------------------------------------
;--- Include MAKEMSI support (with my customisations and MSI branding) ------
;----------------------------------------------------------------------------
#define VER_FILENAME.VER TryMe.Ver ;;I only want one VER file for all samples!
#include "ME.MMH"
;----------------------------------------------------------------------------
;--- Display a message to the user if IIS isn't installed! ------------------
;----------------------------------------------------------------------------
;---[4Doco-IsIisInstalled?]---
#(
;--- Look for a service registry value ----------------------------------
<$RegistryRead
Property="IISINSTALLED4CONFIG"
HKEY="LOCAL_MACHINE"
KEY="SYSTEM\CurrentControlSet\Services\W3SVC"
NAME="DisplayName"
Condition="not Installed"
Default="NoIIS"
>
#)
#(
<$AbortIf
condition=^IISINSTALLED4CONFIG = "NoIIS"^
Message=^The install of "<$ProdInfo.ProductName>"
version <$Productversion> can't continue as it
requires IIS (and IIS isn't installed on this machine).^
Seq="AppSearch-"
SeqTable="InstallUISequence InstallExecuteSequence"
>
#)
;---[4Doco-IsIisInstalled?]---
;----------------------------------------------------------------------------
;--- Create INSTALLDIR ------------------------------------------------------
;----------------------------------------------------------------------------
<$DirectoryTree Key="INSTALLDIR" Dir="c:\program files\TryMe (makemsi sample)\<$MAKEMSI_MM_BASENAME>" CHANGE="\" PrimaryFolder="Y">
;----------------------------------------------------------------------------
;--- Lets install some pretty average HTML files for errors -----------------
;----------------------------------------------------------------------------
#define BUILD_HTML_DIR <$MAKEMSI_OTHER_DIR>\BuiltHtml
#(
#define InstallPrettyAverageHtmlFile
;--- Create a file ------------------------------------------------------
#define SHORTNAME.{$#1}.File My{$#1}Message.html ;;Name of file we will create for message
<$FileMake "<$BUILD_HTML_DIR>\<$SHORTNAME.{$#1}.File>">
#( '<?NewLine>'
<html>
<head>
<title>My pretty average error message for {$#1}</title>
</head>
<body>
<p>My pretty average error message for {$#1}
</body>
</html>
#)
<$/FileMake>
;--- Add to installation directory --------------------------------------
<$File
Source="<$BUILD_HTML_DIR>\<$SHORTNAME.{$#1}.File>"
Destination="[INSTALLDIR]\"
Comment=^This is the new error message for server error number "{$#1}".^
>
#)
<$InstallPrettyAverageHtmlFile "400">
<$InstallPrettyAverageHtmlFile "404">
<$InstallPrettyAverageHtmlFile "405">
;----------------------------------------------------------------------------
;--- Demonstrate a way to automatically add debug code ----------------------
;----------------------------------------------------------------------------
#if ['<$DEBUG_USER_ADSI_PROPERTY_ASSIGNMENT $$UPPER>' = 'N']
#info "Not automatically adding some debug lines to user code..."
#else
#info "Automatically adding some debug lines to user code..."
;---[4Doco-DebugProperyAssignmentOrMethodCall]---
#DefineRexx '@@AdsiInterCeptUserCode'
;--- If line starts with "." then log it --------------------------------
FileLine = strip(FileLine)
if left(FileLine, 1) = '.' then
do
;--- Debug the debug code! ------------------------------------------
call info FileLine;
;--- Add a command to log the assignment or method invokation -------
@@DbgTxt = 'CaDebug 0, "<<USER LINE>>: ' || ReplaceString(FileLine, '"', '""') || '"';
FileLine = @@DbgTxt || '<?NewLine>' || FileLine;
end;
#DefineRexx
#define+ ADSI_APPCFG_BEFORE_#INCLUDE \
#intercept '@@AdsiInterCeptUserCode'
#define+ ADSI_APPCFG_AFTER_#INCLUDE \
#intercept
;---[4Doco-DebugProperyAssignmentOrMethodCall]---
#endif
;----------------------------------------------------------------------------
;--- I recommend you backup IIS metabase! -----------------------------------
;----------------------------------------------------------------------------
#if ['<$BACKUP_IIS_CONFIGURATION_TO_PLAY_SAFE $$UPPER>' <> 'N']
;---[4Doco-BackupIisMetaBase]---
#define? IIS_MAX_BACKUPS_PER_DAY 5 ;;set a default value
<$Adsi "LocalHost" PARENT="IIS:/" Dump="Y">
;--- Need some VB constants (dumped the lot, you can search for doco) ----
const MD_BACKUP_FORCE_BACKUP = 4 ;;Backup
const MD_BACKUP_HIGHEST_VERSION = &HFFFFFFFE ;;Backup, Delete, Restore
const MD_BACKUP_MAX_VERSION = 9999 ;;Limit
const MD_BACKUP_MAX_LEN = 100 ;;Limit
const MD_BACKUP_NEXT_VERSION = &HFFFFFFFF ;;Backup
const MD_BACKUP_OVERWRITE = 1 ;;Backup
const MD_BACKUP_SAVE_FIRST = 2 ;;Backup
const MD_BACKUP_NO_MORE_BACKUPS = &H80070103
;--- Create a "today" based backup name (we may restrict backups under this name) ---
dim BackupName : BackupName = "MAKEMSI - " & day(date()) & " " & MonthName(month(date())) & " " & year(date()) ;;Example = "MAKEMSI - 18 May 2006"
;--- Now perhaps we'd like to restrict number of backups made today? -----
dim MakeBackup
#if ['<$IIS_MAX_BACKUPS_PER_DAY>' = '0']
CaDebug 0, "No restrictions on the number of backups made..."
MakeBackup = true
#elseif
;--- User does want to restrict number of backups -------------------
CaDebug 0, "We don't want more than <$IIS_MAX_BACKUPS_PER_DAY> backups made..."
VbsCaLogInc(1)
on error resume next
dim Index : Index = 0
dim BuVersion, BuLocation, BuDateTime
do while true
;--- See if this "index" exists -----------------------------
.EnumBackups BackupName, Index, BuVersion, BuLocation, BuDateTime
if (err.number <> 0) then
if (err.number = MD_BACKUP_NO_MORE_BACKUPS) then
exit do
End If
end if
;--- Found a backup -------------------------------------------------
Index = Index + 1
CaDebug 0, "BACKUP #" & Index & " created at " & BuDateTime & " UTC"
loop
on error goto 0
CaDebug 0, "Found " & Index & " backups made today." 'Note backup name includes todays date!
VbsCaLogInc(-1)
if Index < <$IIS_MAX_BACKUPS_PER_DAY> then
MakeBackup = true
else
MakeBackup = false
end if
#endif
;--- Backup the IIS configuration ----------------------------------------
if not MakeBackup then
CaDebug 0, "We don't want to make any more backups today..."
else
CaDebug 0, "Backing up the complete IIS configuration..."
.Backup BackupName, MD_BACKUP_NEXT_VERSION, (MD_BACKUP_SAVE_FIRST or MD_BACKUP_FORCE_BACKUP)
CaDebug 0, "Successfully backed up the IIS configuration"
end if
<$/Adsi>
;---[4Doco-BackupIisMetaBase]---
#endif
;----------------------------------------------------------------------------
;--- Define Some directories ------------------------------------------------
;----------------------------------------------------------------------------
<$DirectoryTree Key="WWWROOTDIR" Dir="c:\Inetpub\wwwroot" MAKE="Y">
#(
;--- Need to know the "Default Web Site" directory ----------------------
<$RegistryRead
Property="WWWROOTDIR" ;;Typical value is "c:\Inetpub\wwwroot"
HKEY="LOCAL_MACHINE"
KEY="SOFTWARE\Microsoft\InetStp"
NAME="PathWWWRoot"
Condition="not Installed"
>
#)
<$Component "CreateEmptyFolders" Create="Y" Directory_="<$AnyDir>" LM="Y">
<$DirectoryTree Key="WWWDIR" Dir="[WWWROOTDIR]WwwNewIisWebDirectory" MAKE="Y"> ;;Must match name of "IisWebDirectory" below!
<$DirectoryTree Key="WEBDIR1" Dir="[INSTALLDIR]WEBDIR1" MAKE="Y">
<$DirectoryTree Key="WEBDIR2" Dir="[INSTALLDIR]WEBDIR2" MAKE="Y">
<$DirectoryTree Key="WEBDIR3" Dir="[INSTALLDIR]WEBDIR3" MAKE="Y">
<$/Component>
#data 'CaIisData' 2 ;;Used to pass data to the ADSI commands
;--- Our ADSI user code references these items --------------------------
"INSTALLDIR" "[INSTALLDIR]"
"WEBDIR1" "[WEBDIR1]"
"WEBDIR2" "[WEBDIR2]"
"WEBDIR3" "[WEBDIR3]"
;--- Configuration (the "ADSI" command will examine these) --------------
"P1234NewWebApplication.SiteId" "1234,1000,2000,3000,*" ;;Specify one or more proposed "Site ID" numbers to use (* indicates its OK if these are all already used and we need to assign another)
#data
;----------------------------------------------------------------------------
;--- Create a new site under the standard IIS "Default Web Site" ------------
;----------------------------------------------------------------------------
<$Adsi "Default Web Site" Class="IIsWebServer"> ;;/1 (normally? Always?)
;--- Disable this site if required (is licence means we have a 1 site limit) ---
#if ['<$IIS_IS_RESTRICTED_TO_1_SITE_AT_A_TIME $$UPPER>' = 'Y']
;--- We want to start the OTHER main site we create (on port "1234") ---
CaDebug 0, "CONFIG ""IIS_IS_RESTRICTED_TO_1_SITE_AT_A_TIME"" = ""<$IIS_IS_RESTRICTED_TO_1_SITE_AT_A_TIME>"" so stopping default web site to allow another to be started below!"
.Stop()
CaDebug 0, "Stop completed"
#endif
;--- Need to create web sites under the "ROOT" ---------------------------
<$Adsi "ROOT"> ;;/1/ROOT
;--- Disable this site if required (if licence means we have a 1 site limit) ---
;#if ['<$IIS_IS_RESTRICTED_TO_1_SITE_AT_A_TIME $$UPPER>' = 'Y']
; CaDebug 0, "CONFIG ""IIS_IS_RESTRICTED_TO_1_SITE_AT_A_TIME"" = ""<$IIS_IS_RESTRICTED_TO_1_SITE_AT_A_TIME>"" so disabling default web site to allow another to be created!"
; .AppDisable() ;;The AppDisable method has no effect if the application is running in-process (it doesn't work here...)
; CaDebug 0, "AppDisable completed"
;#endif
;--- If "C:\Inetpub\wwwroot\NewIisWebDirectory" doesn't exist then you won't get an error but it won't show up in admin tool until you create it either) ---
<$Adsi "WwwNewIisWebDirectory" Class="IisWebDirectory" Create="Y">
.ContentIndexed = False
.DontLog = True
;--- Change 400 --------------------------------------------------
CaDebug 0, "Processing .HttpErrors (400)..."
VbsCaLogInc(1)
dim HDIR : HDIR = VbsCaCadGet("INSTALLDIR") ;;We installed the HTML for errors here...
dim New400 : New400 = "400,*,FILE," & HDIR & "<$SHORTNAME.400.File>"
dim Errors : Errors = oParent.HttpErrors 'This object doesn't exist yet, will get parent's by default
dim Fnd400 : Fnd400 = -1 '-1 = Not found
dim i
for i = lbound(Errors) to ubound(Errors)
;--- Try to determine index of a message to modify -----------
CaDebug 0, "Found #" & i & " = " & Errors(i)
dim ErrPart : ErrPart = split(Errors(i), ",")
if ErrPart(0) = "400" then
Fnd400 = i
VbsCaLogInc(1)
CaDebug 0, "Found 400..."
VbsCaLogInc(-1)
end if
next
i = ubound(Errors)
if Fnd400 = -1 then
;--- We didn't find one to replace, so create new entry -----
i = i + 1
Fnd400 = i
CaDebug 0, "Resizing array so we can add a 400 message at #" & Fnd400
redim preserve Errors(Fnd400)
end if
Errors(Fnd400) = New400
.HttpErrors = Errors
VbsCaLogInc(-1)
CaDebug 0, "Finished processing .HttpErrors (400)..."
<$/Adsi>
;--- "NewIisWebVirtualDir" better as "path" not "forced" by IIS ------
<$Adsi "WwwNewIisWebVirtualDir" Class="IisWebVirtualDir" Create="Y" DATA="CaIisData">
;--- Point this site to a particular directory -------------------
.path = VbsCaCadGet("WEBDIR1")
;--- Now update "Custom Errors" ----------------------------------
dim HDIR : HDIR = VbsCaCadGet("INSTALLDIR")
#(
;--- Note that this clears all existing entries and adds 2 new ---
.HttpErrors = array(
"404,*,FILE," & HDIR & "<$SHORTNAME.404.File>", ;;Obviously this MSI hasn't actually installed these (its just an example)...
"405,*,FILE," & HDIR & "<$SHORTNAME.405.File>"
)
#)
<$/Adsi>
<$/Adsi>
<$/Adsi>
;----------------------------------------------------------------------------
;--- Create a new IIS Application Pool --------------------------------------
;----------------------------------------------------------------------------
#if ['<$IIS_SUPPORTS_APPPOOLS $$UPPER>' = 'Y']
<$Adsi "AppPools" Class="IIsApplicationPools">
<$Adsi "My.New.AppPool" Class="IIsApplicationPool" Create="Y">
<$/Adsi>
<$/Adsi>
#endif
;----------------------------------------------------------------------------
;--- Create a new IIS web server/site ---------------------------------------
;----------------------------------------------------------------------------
<$Adsi "P1234NewWebApplication" Class="IISWebServer" Create="Y" DATA="CaIisData"> ;;Won't "start" on non-server versions of Windows (error 0x80070032 (-2147024846): "The request is not supported.")
;--- Basic configuration -------------------------------------------------
.ServerBindings = array(":1234:") ;;Binds to TCP-IP port 1234
.ContentIndexed = False
.DontLog = True
;--- A web server MUST have a "ROOT" entry -------------------------------
<$Adsi "ROOT" Class="IisWebVirtualDir" Create="Y">
;--- Basic configuration (for this virtual directory) ----------------
.ContentIndexed = False
.DontLog = True
.path = VbsCaCadGet("WEBDIR2")
#if ['<$IIS_SUPPORTS_APPPOOLS $$UPPER>' = 'Y']
.AppPoolId = "My.New.AppPool"
#endif
;--- Modify characteristics for one specific file --------------------
<$Adsi "ThisAsp.asp" Class="IIsWebFile" create="Y"> ;;Bote that this does not create or modify the file!
.AuthAnonymous = True
.AuthNTLM = True
<$/Adsi>
;--- Make it possible to web "browse" a directory tree ---------------
<$Adsi "P1234BrowsableDirTree" Class="IisWebVirtualDir" Create="Y">
.path = VbsCaCadGet("WEBDIR3")
.AuthAnonymous = False ;;No anonymous access
.AuthNTLM = True ;;Use Windows Integrated security
.AccessExecute = False
.AccessNoRemoteExecute = False
.AccessRead = True
.AccessScript = False
.AccessSource = False
.AspEnableParentPaths = False
.ContentIndexed = False
.DefaultDoc = ""
.DirBrowseShowExtension = True
.DirBrowseShowLongDate = True
.DirBrowseShowSize = True
.DontLog = True
.EnableDirBrowsing = True
<$/Adsi>
<$/Adsi>
<$/Adsi>
;----------------------------------------------------------------------------
;--- Stop/start IIS services ------------------------------------------------
;----------------------------------------------------------------------------
#if ['<$IIS_STOP_START_SERVICES $$UPPER>' <> 'N']
#info "Adding stop/start IIS services code..."
;---[4Doco-StopStartIisServices]---
<$Component "StopStartIisServices" Directory_="<$AnyDir>" LM="Y">
<$ServiceControl Name="IISADMIN" AtInstall="start stop" AtUnInstall="start stop" Wait="Y">
<$ServiceControl Name="W3SVC" AtInstall="start stop" AtUnInstall="start stop" Wait="Y"> ;;You may also want to restart ftp (maybe others)!
<$/Component>
;---[4Doco-StopStartIisServices]---
#endif