<#
.SYNOPSIS
    Installs an PKI Trust Manager Windows CA API Proxy ASP.NET application on IIS with Domain User Identity and SSL options.

.DESCRIPTION
    This script automates the deployment of an Securetron PKI Trust Manager Win. CA Proxiy application on Windows Server 2022 or higher.
    It performs the following steps:
    1. Creates/Verifies a Domain User.
    2. Configures an IIS Application Pool with the Domain User identity.
    3. Deploys application files and creates an IIS Website.
    4. Configures SSL (ADCS or Self-Signed).
    5. Updates web.config with a unique deployment GUID.

.PARAMETER user
    The SamAccountName for the domain user to create/use.

.PARAMETER password
    The password for the domain user.

.PARAMETER domain
    The domain name (e.g., contoso.com) to be used for the website binding and AD context.

.PARAMETER srcdir
    The source directory containing the application files.

.PARAMETER webdir
    The destination directory for the IIS application.

.PARAMETER tls
    Boolean flag to enable TLS/SSL configuration.

.EXAMPLE
    .\install.ps1 -user app-svc -password "P@ssw0rd123!" -domain contoso.com -srcdir "C:\downloads\caproxyapi" -webdir "C:\inetpub\caproxyapi" -tls $true
#>

param(
    [Parameter(Mandatory = $true)]
    [string]$user,

    [Parameter(Mandatory = $true)]
    [string]$password,

    [Parameter(Mandatory = $true)]
    [string]$domain,

    [Parameter(Mandatory = $true)]
    [string]$srcdir,

    [Parameter(Mandatory = $true)]
    [string]$webdir,

    [Parameter(Mandatory = $true)]
    [string]$tls
)

# Determine if TLS is requested (handle string "true" logic if passed as string, though type implies validation)
$useTls = ($tls -eq "true" -or $tls -eq $true)

Write-Host "Starting IIS Application Deployment..." -ForegroundColor Cyan

# Define User Variables
if ($user -match "\\") {
    $user = ($user -split "\\")[-1]
    Write-Warning "User input contained domain prefix. Using username part: '$user'"
}

$domainParts = $domain -split "\."
# Get actual Domain NetBIOS name for the user identity (current domain context)
try {
    $adDomainInfo = Get-ADDomain -Current LocalComputer
    $netbiosDomain = $adDomainInfo.NetBIOSName
}
catch {
    $netbiosDomain = $env:USERDOMAIN
}

$fullUserName = "$netbiosDomain\$user"
$appPoolName = "caapi"
$siteName = "caapi"

# ---------------------------------------------------------------------------
# Prerequisites Check
# ---------------------------------------------------------------------------
Write-Host "Checking modules..."
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
    Write-Error "ActiveDirectory module is required. Please install RSAT."
    exit 1
}
if (-not (Get-Module -ListAvailable -Name WebAdministration)) {
    Write-Error "WebAdministration module is required. Please install IIS Management Scripts and Tools."
    exit 1
}

Import-Module ActiveDirectory
Import-Module WebAdministration

# ---------------------------------------------------------------------------
# A. Domain User Creation
# ---------------------------------------------------------------------------
Write-Host "Step A: Configuring Domain User '$user'..." -ForegroundColor Yellow

$securePassword = ConvertTo-SecureString $password -AsPlainText -Force

try {
    $adUser = Get-ADUser -Identity $user -ErrorAction Stop
    Write-Host "User '$user' already exists."
}
catch {
    Write-Host "User '$user' does not exist. Creating..."
    try {
        New-ADUser -Name $user `
            -SamAccountName $user `
            -AccountPassword $securePassword `
            -Enabled $true `
            -PasswordNeverExpires $true `
            -ErrorAction Stop
        Write-Host "Domain user created successfully."
    }
    catch {
        Write-Error "Failed to create domain user: $_"
        exit 1
    }
}

# Add user to local IIS_IUSRS group to allow running web apps
# Note: Since this is a domain user, we add "DOMAIN\User" to the local group.
try {
    # Check if user is already a member
    $member = Get-LocalGroupMember -Group "IIS_IUSRS" | Where-Object { $_.Name -like "*$user" }
    if (-not $member) {
        Write-Host "Adding '$fullUserName' to local IIS_IUSRS group..."
        Add-LocalGroupMember -Group "IIS_IUSRS" -Member $fullUserName -ErrorAction Stop
    }
    else {
        Write-Host "User is already a member of IIS_IUSRS."
    }
}
catch {
    Write-Warning "Failed to add user to IIS_IUSRS group via local cmdlets. Attempting manual net.exe fallback or skipping if permissions issue."
    # Fallback usually not needed on Server 2022 if RSAT features installed, but good measure
    & net localgroup IIS_IUSRS $fullUserName /add
}

# ---------------------------------------------------------------------------
# B. IIS Application Pool Creation
# ---------------------------------------------------------------------------
Write-Host "Step B: Configuring Application Pool '$appPoolName'..." -ForegroundColor Yellow

if (Test-Path "IIS:\AppPools\$appPoolName") {
    Write-Host "App Pool '$appPoolName' exists. Updating settings..."
    $pool = Get-Item "IIS:\AppPools\$appPoolName"
}
else {
    Write-Host "Creating App Pool '$appPoolName'..."
    $pool = New-WebAppPool -Name $appPoolName
}

# Set .NET Framework Version to v4.0
$pool.managedRuntimeVersion = "v4.0"
$pool | Set-Item

# Set Identity to SpecificUser
Set-ItemProperty -Path "IIS:\AppPools\$appPoolName" -Name processModel.identityType -Value 3 # SpecificUser
Set-ItemProperty -Path "IIS:\AppPools\$appPoolName" -Name processModel.userName -Value $fullUserName
Set-ItemProperty -Path "IIS:\AppPools\$appPoolName" -Name processModel.password -Value $password

Write-Host "App Pool configured."

# ---------------------------------------------------------------------------
# C. Deployment and Web Site Creation
# ---------------------------------------------------------------------------
Write-Host "Step C: Deploying files and Website..." -ForegroundColor Yellow

# Create Destination Directory
if (-not (Test-Path $webdir)) {
    Write-Host "Creating web directory '$webdir'..."
    New-Item -Path $webdir -ItemType Directory -Force | Out-Null
}

# Copy Files
if (Test-Path $srcdir) {
    Write-Host "Copying files from '$srcdir' to '$webdir'..."
    Copy-Item -Path "$srcdir\*" -Destination $webdir -Recurse -Force
}
else {
    Write-Error "Source directory '$srcdir' not found!"
    exit 1
}

# Create Website
# Note: Prompt asks for "IIS Web Application".
# Given "-domain" argument, a dedicated Site is best practice.
# We will check if site exists.
if (Test-Path "IIS:\Sites\$siteName") {
    Write-Host "Website '$siteName' already exists. Removing to recreate/update..."
    Remove-WebSite -Name $siteName
}

Write-Host "Creating Website '$siteName' bound to '$domain'..."
New-WebSite -Name $siteName `
    -Port 80 `
    -HostHeader $domain `
    -PhysicalPath $webdir `
    -ApplicationPool $appPoolName `
    -Force

# ---------------------------------------------------------------------------
# D. SSL Configuration
# ---------------------------------------------------------------------------
if ($useTls) {
    Write-Host "Step D: Configuring SSL..." -ForegroundColor Yellow
    
    $cert = $null

    # 1. Attempt using internal CA (ADCS)
    Write-Host "Attempting script check for ADCS..."
    # A simple check: Can we find an Enrollment Policy?
    # Or just try to request and catch error.
    
    try {
        # This assumes a template named "WebServer" exists and is available.
        # This command is available in module PKI (Server 2012+)
        Write-Host "Requesting certificate from ADCS (Template: WebServer)..."
        $certReq = Get-Certificate -Template "WebServer" `
            -DnsName $domain `
            -CertStoreLocation "Cert:\LocalMachine\My" `
            -ErrorAction Stop
        $cert = $certReq.Certificate
        Write-Host "Successfully enrolled certificate from CA."
    }
    catch {
        Write-Warning "ADCS CA not ready or enrollment failed: $_"
        Write-Host "Generating Self-Signed Certificate..."
        
        $cert = New-SelfSignedCertificate -DnsName $domain `
            -CertStoreLocation "Cert:\LocalMachine\My" `
            -FriendlyName "SelfSigned-$domain" `
            -Force
    }

    if ($cert) {
        Write-Host "Binding Certificate to Website..."
        # Add HTTPS binding
        New-WebBinding -Name $siteName -Protocol https -Port 443 -HostHeader $domain -IPAddress "*" -SslFlags 1 # SNI enabled
        
        # Assign Certificate
        $binding = Get-WebBinding -Name $siteName -Protocol https -Port 443 -HostHeader $domain
        $binding.AddSslCertificate($cert.Thumbprint, "My")
        Write-Host "SSL Bound Successfully."
    }
}

# ---------------------------------------------------------------------------
# E. Web.Config Modification
# ---------------------------------------------------------------------------
Write-Host "Step E: Updating web.config..." -ForegroundColor Yellow

$webConfigPath = Join-Path $webdir "web.config"
$guid = [guid]::NewGuid().ToString()

if (Test-Path $webConfigPath) {
    [xml]$xml = Get-Content $webConfigPath

    # Ensure appSettings exists
    if (-not $xml.configuration.appSettings) {
        if (-not $xml.configuration) {
            Write-Error "Invalid web.config structure."
        }
        else {
            $appSettingsNode = $xml.CreateElement("appSettings")
            $xml.configuration.AppendChild($appSettingsNode) | Out-Null
        }
    }

    # Create new add element
    # <add key="the GUID value is generated" value="1"/>
    # Implementation: Key is the GUID, Value is "1"
    $newEntry = $xml.CreateElement("add")
    $newEntry.SetAttribute("key", $guid)
    $newEntry.SetAttribute("value", "1")

    $xml.configuration.appSettings.AppendChild($newEntry) | Out-Null

    $xml.Save($webConfigPath)
    Write-Host "Updated web.config with GUID: $guid"
}
else {
    Write-Warning "web.config not found at '$webConfigPath'. Creating basic one..."
    
    $newConfig = @"
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="$guid" value="1" />
  </appSettings>
  <system.web>
    <compilation targetFramework="4.7" />
  </system.web>
</configuration>
"@
    Set-Content -Path $webConfigPath -Value $newConfig
    Write-Host "Created new web.config with GUID."
}

Write-Host "Deployment Complete!" -ForegroundColor Green
