|
- [CmdletBinding()]
- param(
- [string]$SiteName = 'WscMvc',
- [string]$PoolName = 'WscMvc',
- [string]$PhysicalPath,
- [int]$Port = 8090
- )
-
- $ErrorActionPreference = 'Stop'
-
- Import-Module WebAdministration
-
- if (-not $PhysicalPath) {
- # IIS's site root is the "public" folder only - Framework/Controllers/
- # tests/tools/docs/logs are siblings of it, never served. See
- # docs/ARCHITECTURE.md.
- $PhysicalPath = Join-Path (Split-Path -Parent $PSScriptRoot) 'public'
- }
-
- if (-not (Test-Path $PhysicalPath)) {
- throw "PhysicalPath does not exist: $PhysicalPath"
- }
-
- if (-not (Test-Path "IIS:\AppPools\$PoolName")) {
- New-WebAppPool -Name $PoolName | Out-Null
- Set-ItemProperty "IIS:\AppPools\$PoolName" -Name managedRuntimeVersion -Value ''
- Set-ItemProperty "IIS:\AppPools\$PoolName" -Name enable32BitAppOnWin64 -Value $false
- Write-Output "Created app pool $PoolName (64-bit, no managed code)"
- } else {
- Write-Output "App pool $PoolName already exists"
- }
-
- if (-not (Test-Path "IIS:\Sites\$SiteName")) {
- New-Website -Name $SiteName -Port $Port -PhysicalPath $PhysicalPath -ApplicationPool $PoolName | Out-Null
- Write-Output "Created site $SiteName on port $Port -> $PhysicalPath"
- } else {
- $existingPath = (Get-Website -Name $SiteName).PhysicalPath
- if ($existingPath -ne $PhysicalPath) {
- Set-ItemProperty "IIS:\Sites\$SiteName" -Name physicalPath -Value $PhysicalPath
- Write-Output "Site $SiteName already existed; updated physicalPath $existingPath -> $PhysicalPath"
- } else {
- Write-Output "Site $SiteName already exists with the correct physicalPath"
- }
- }
-
- # Default.asp needs Server.MapPath("../logs") to reach logs/, which lives
- # outside the "public" webroot by design. Scoped to just this site via
- # /commit:apphost (writes a <location path="SiteName"> block in
- # applicationHost.config) rather than unlocking system.webServer/asp
- # machine-wide, which would affect every site on the host. See
- # docs/DECISIONS.md for why the machine-wide unlock approach is avoided.
- $appcmd = "$env:windir\system32\inetsrv\appcmd.exe"
- & $appcmd set config $SiteName -section:system.webServer/asp "/enableParentPaths:True" /commit:apphost | Out-Null
- $parentPathsNow = & $appcmd list config $SiteName -section:system.webServer/asp
- Write-Output "enableParentPaths config: $parentPathsNow"
-
- # logs/ is a sibling of $PhysicalPath (see Default.asp's Server.MapPath("../logs")).
- # Classic ASP impersonates IUSR for anonymous requests on this host - grant it
- # (via IIS_IUSRS) write access scoped to exactly this folder, nothing else.
- # Idempotent: re-running icacls /grant is safe, it doesn't duplicate the ACE.
- $logsPath = Join-Path (Split-Path -Parent $PhysicalPath) 'logs'
- if (-not (Test-Path $logsPath)) {
- New-Item -ItemType Directory -Path $logsPath | Out-Null
- Write-Output "Created $logsPath"
- }
- & icacls $logsPath /grant "IIS_IUSRS:(OI)(CI)M" | Out-Null
- Write-Output "Granted IIS_IUSRS write access on $logsPath"
-
- Start-WebAppPool -Name $PoolName -ErrorAction SilentlyContinue
- Start-Website -Name $SiteName -ErrorAction SilentlyContinue
-
- Get-Website -Name $SiteName | Select-Object Name, State, PhysicalPath, ApplicationPool
|