<#
.SYNOPSIS
    Deploy the password expiry checker to Windows machines.
.DESCRIPTION
    Downloads password-expiry-check.ps1, installs it to a configurable
    directory, creates a scheduled task for recurring checks, and
    optionally copies the script to NETLOGON for GPO deployment.
.NOTES
    Author:  Phil Connor <contact@mylinux.work>
    License: MIT (https://opensource.org/licenses/MIT)
    Version: 1.01
#>

param(
    [string]$InstallDir = "C:\Scripts",
    [int]$WarningDays = 14,
    [int]$IntervalHours = 4,
    [switch]$NetlogonCopy,
    [switch]$CmdPrompt,
    [switch]$NoProfile,
    [switch]$Remove,
    [switch]$DryRun,
    [Alias("h")]
    [switch]$Help
)

$ScriptUrl = "https://mylinux.work/downloads/password-expiry-check.ps1.zip"
$ScriptName = "password-expiry-check.ps1"
$TaskName = "PasswordExpiryCheck"

# ── Colors ────────────────────────────────────────────────────────────

function Write-OK   { param([string]$Msg) Write-Host "[OK]    $Msg" -ForegroundColor Green }
function Write-Warn { param([string]$Msg) Write-Host "[WARN]  $Msg" -ForegroundColor Yellow }
function Write-Err  { param([string]$Msg) Write-Host "[ERROR] $Msg" -ForegroundColor Red }
function Write-Info { param([string]$Msg) Write-Host "[INFO]  $Msg" -ForegroundColor Cyan }

# ── Help ──────────────────────────────────────────────────────────────

if ($Help) {
    Write-Host @"
Usage: .\deploy-password-expiry-checker.ps1 [OPTIONS]

Deploy password expiry notifications on Windows machines.

Installs:
  1. password-expiry-check.ps1 to C:\Scripts\ (configurable)
  2. Scheduled task - runs every 4 hours (configurable) under logged-on user
  3. Logon-triggered task - fires on every user logon
  4. PowerShell profile hook - warning banner in every new PowerShell window
  5. Optional cmd.exe AutoRun hook - warning banner in every new cmd window
  6. Optional NETLOGON copy for GPO deployment

Options:
  -InstallDir PATH       Installation directory (default: C:\Scripts)
  -WarningDays N         Warning threshold in days (default: 14)
  -IntervalHours N       Scheduled task interval in hours (default: 4)
  -CmdPrompt             Also add warning to cmd.exe via AutoRun registry key
  -NoProfile             Skip PowerShell profile hook (scheduled tasks only)
  -NetlogonCopy          Copy script to NETLOGON share for GPO deployment
  -Remove                Remove deployed components
  -DryRun                Show what would be done without making changes
  -Help                  Show this help

Examples:
  .\deploy-password-expiry-checker.ps1                        # install with defaults
  .\deploy-password-expiry-checker.ps1 -CmdPrompt             # also hook into cmd.exe
  .\deploy-password-expiry-checker.ps1 -NoProfile             # skip profile hook
  .\deploy-password-expiry-checker.ps1 -WarningDays 30        # 30-day warning threshold
  .\deploy-password-expiry-checker.ps1 -IntervalHours 8       # check every 8 hours
  .\deploy-password-expiry-checker.ps1 -NetlogonCopy          # also copy to NETLOGON
  .\deploy-password-expiry-checker.ps1 -DryRun                # preview changes
  .\deploy-password-expiry-checker.ps1 -Remove                # uninstall
"@
    exit 0
}

# ── Admin check ───────────────────────────────────────────────────────

$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Write-Err "Must run as Administrator"
    exit 1
}

$ScriptPath = Join-Path $InstallDir $ScriptName

# ── Remove mode ───────────────────────────────────────────────────────

if ($Remove) {
    Write-Info "Removing password expiry checker deployment..."
    Write-Host ""

    # Remove scheduled tasks
    foreach ($name in @($TaskName, "${TaskName}Logon")) {
        $task = Get-ScheduledTask -TaskName $name -ErrorAction SilentlyContinue
        if ($task) {
            if ($DryRun) {
                Write-Info "Would remove scheduled task: $name"
            } else {
                Unregister-ScheduledTask -TaskName $name -Confirm:$false
                Write-OK "Removed scheduled task: $name"
            }
        } else {
            Write-Info "Scheduled task '$name' not found, skipping"
        }
    }

    # Remove script
    if (Test-Path $ScriptPath) {
        if ($DryRun) {
            Write-Info "Would remove: $ScriptPath"
        } else {
            Remove-Item -Path $ScriptPath -Force
            Write-OK "Removed $ScriptPath"
        }
    }

    # Remove PowerShell profile hook
    $profileMarker = "# PasswordExpiryCheck"
    $allUsersProfile = $PROFILE.AllUsersAllHosts
    if ((Test-Path $allUsersProfile) -and (Select-String -Path $allUsersProfile -Pattern $profileMarker -Quiet)) {
        if ($DryRun) {
            Write-Info "Would remove profile hook from $allUsersProfile"
        } else {
            $content = Get-Content $allUsersProfile | Where-Object { $_ -notmatch $profileMarker }
            if ($content) {
                Set-Content -Path $allUsersProfile -Value $content
            } else {
                Remove-Item -Path $allUsersProfile -Force
            }
            Write-OK "Removed PowerShell profile hook"
        }
    }

    # Remove cmd.exe AutoRun
    $cmdAutoRun = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Command Processor" -Name "AutoRun" -ErrorAction SilentlyContinue
    if ($cmdAutoRun -and $cmdAutoRun.AutoRun -match "password-expiry-check") {
        if ($DryRun) {
            Write-Info "Would remove cmd.exe AutoRun registry key"
        } else {
            $existing = $cmdAutoRun.AutoRun
            # Remove our command, handle single command or chained with ampersand
            $cleaned = ($existing -split '\s*&\s*' | Where-Object { $_ -notmatch 'password-expiry-check' }) -join ' & '
            if ($cleaned.Trim()) {
                Set-ItemProperty -Path "HKLM:\Software\Microsoft\Command Processor" -Name "AutoRun" -Value $cleaned.Trim()
            } else {
                Remove-ItemProperty -Path "HKLM:\Software\Microsoft\Command Processor" -Name "AutoRun" -ErrorAction SilentlyContinue
            }
            Write-OK "Removed cmd.exe AutoRun hook"
        }
    }

    # Remove install dir if empty
    if ((Test-Path $InstallDir) -and @(Get-ChildItem $InstallDir -Force).Count -eq 0) {
        if ($DryRun) {
            Write-Info "Would remove empty directory: $InstallDir"
        } else {
            Remove-Item -Path $InstallDir -Force
            Write-OK "Removed empty directory: $InstallDir"
        }
    }

    Write-Host ""
    if (-not $DryRun) {
        Write-OK "Removal complete."
    }
    exit 0
}

# ── Install mode ──────────────────────────────────────────────────────

Write-Info "Deploying password expiry checker..."
Write-Host ""

# 1. Create install directory
if (-not (Test-Path $InstallDir)) {
    if ($DryRun) {
        Write-Info "Would create directory: $InstallDir"
    } else {
        New-Item -Path $InstallDir -ItemType Directory -Force | Out-Null
        Write-OK "Created directory: $InstallDir"
    }
}

# 2. Download script
if (Test-Path $ScriptPath) {
    Write-Info "Script already exists at $ScriptPath - downloading latest version"
}

if ($DryRun) {
    Write-Info "Would download $ScriptUrl and extract to $ScriptPath"
} else {
    $zipPath = Join-Path $env:TEMP "password-expiry-check.ps1.zip"
    try {
        Invoke-WebRequest -Uri $ScriptUrl -OutFile $zipPath -UseBasicParsing -ErrorAction Stop
        Expand-Archive -Path $zipPath -DestinationPath $InstallDir -Force
        Remove-Item $zipPath -Force -ErrorAction SilentlyContinue
        if (Test-Path $ScriptPath) {
            Write-OK "Downloaded and extracted $ScriptPath"
        } else {
            Write-Err "Zip extracted but $ScriptName not found in $InstallDir"
            exit 1
        }
    } catch {
        Write-Err "Failed to download: $($_.Exception.Message)"
        exit 1
    }
}

# 3. Scheduled task - recurring interval
$taskArgs = "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$ScriptPath`" -Quiet -WarningDays $WarningDays"

$existingTask = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
if ($existingTask) {
    Write-Info "Scheduled task '$TaskName' already exists - recreating"
    if (-not $DryRun) {
        Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
    }
}

if ($DryRun) {
    Write-Info "Would create scheduled task: $TaskName (every ${IntervalHours}h)"
} else {
    $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $taskArgs
    $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).Date.AddHours(9) `
        -RepetitionInterval (New-TimeSpan -Hours $IntervalHours) `
        -RepetitionDuration (New-TimeSpan -Days 365)
    $settings = New-ScheduledTaskSettingsSet `
        -AllowStartIfOnBatteries `
        -DontStopIfGoingOnBatteries `
        -StartWhenAvailable `
        -RunOnlyIfNetworkAvailable:$false
    $principal = New-ScheduledTaskPrincipal -GroupId "S-1-5-32-545" -RunLevel Limited

    Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger $trigger `
        -Settings $settings -Principal $principal `
        -Description "Check password expiry every $IntervalHours hours (mylinux.work)" | Out-Null
    Write-OK "Created scheduled task: $TaskName (every ${IntervalHours}h)"
}

# 4. Logon trigger task
$logonTaskName = "${TaskName}Logon"
$existingLogon = Get-ScheduledTask -TaskName $logonTaskName -ErrorAction SilentlyContinue
if ($existingLogon) {
    Write-Info "Logon task '$logonTaskName' already exists - recreating"
    if (-not $DryRun) {
        Unregister-ScheduledTask -TaskName $logonTaskName -Confirm:$false
    }
}

if ($DryRun) {
    Write-Info "Would create logon trigger task: $logonTaskName"
} else {
    $logonAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $taskArgs
    $logonTrigger = New-ScheduledTaskTrigger -AtLogOn
    $logonSettings = New-ScheduledTaskSettingsSet `
        -AllowStartIfOnBatteries `
        -DontStopIfGoingOnBatteries `
        -StartWhenAvailable `
        -ExecutionTimeLimit (New-TimeSpan -Minutes 5)
    # Delay 30 seconds after logon to let the desktop load
    $logonTrigger.Delay = "PT30S"
    $logonPrincipal = New-ScheduledTaskPrincipal -GroupId "S-1-5-32-545" -RunLevel Limited

    Register-ScheduledTask -TaskName $logonTaskName -Action $logonAction -Trigger $logonTrigger `
        -Settings $logonSettings -Principal $logonPrincipal `
        -Description "Check password expiry at logon (mylinux.work)" | Out-Null
    Write-OK "Created logon trigger task: $logonTaskName"
}

# 5. NETLOGON copy (optional)
if ($NetlogonCopy) {
    $logonServer = $env:LOGONSERVER
    if ($logonServer) {
        $netlogonPath = Join-Path "$logonServer\NETLOGON" $ScriptName
        if ($DryRun) {
            Write-Info "Would copy $ScriptPath to $netlogonPath"
        } else {
            try {
                Copy-Item -Path $ScriptPath -Destination $netlogonPath -Force -ErrorAction Stop
                Write-OK "Copied to $netlogonPath"
            } catch {
                Write-Warn "Could not copy to NETLOGON: $($_.Exception.Message)"
                Write-Warn "Copy manually: Copy-Item '$ScriptPath' '$netlogonPath'"
            }
        }
    } else {
        Write-Warn "LOGONSERVER not set - machine may not be domain-joined"
        Write-Warn "Copy manually to \\DC\NETLOGON\$ScriptName"
    }
}

# 6. PowerShell profile hook (default, skip with -NoProfile)
$profileMarker = "# PasswordExpiryCheck"
$profileLine = "& `"$ScriptPath`" -Quiet -WarningDays $WarningDays $profileMarker"

if (-not $NoProfile) {
    $allUsersProfile = $PROFILE.AllUsersAllHosts
    $profileDir = Split-Path $allUsersProfile -Parent

    # Check if hook already exists
    $hookExists = (Test-Path $allUsersProfile) -and (Select-String -Path $allUsersProfile -Pattern $profileMarker -Quiet)

    if ($hookExists) {
        Write-Info "PowerShell profile hook already present - updating"
        if (-not $DryRun) {
            $content = Get-Content $allUsersProfile | Where-Object { $_ -notmatch $profileMarker }
            $content += $profileLine
            Set-Content -Path $allUsersProfile -Value $content
        }
    } else {
        if ($DryRun) {
            Write-Info "Would add profile hook to $allUsersProfile"
        } else {
            if (-not (Test-Path $profileDir)) {
                New-Item -Path $profileDir -ItemType Directory -Force | Out-Null
            }
            Add-Content -Path $allUsersProfile -Value $profileLine
        }
    }
    Write-OK "PowerShell profile hook: $allUsersProfile"
} else {
    Write-Info "Skipping PowerShell profile hook (-NoProfile)"
}

# 7. cmd.exe AutoRun hook (optional, enable with -CmdPrompt)
if ($CmdPrompt) {
    $cmdCommand = '@powershell.exe -NoProfile -ExecutionPolicy Bypass -File "' + $ScriptPath + '" -Quiet -WarningDays ' + $WarningDays
    $regPath = "HKLM:\Software\Microsoft\Command Processor"

    $existing = Get-ItemProperty -Path $regPath -Name "AutoRun" -ErrorAction SilentlyContinue
    if ($existing -and $existing.AutoRun -match "password-expiry-check") {
        Write-Info "cmd.exe AutoRun hook already present - updating"
        if (-not $DryRun) {
            $cleaned = ($existing.AutoRun -split '\s*&\s*' | Where-Object { $_ -notmatch 'password-expiry-check' }) -join ' & '
            if ($cleaned.Trim()) {
                $newValue = $cleaned.Trim() + " & " + $cmdCommand
            } else {
                $newValue = $cmdCommand
            }
            Set-ItemProperty -Path $regPath -Name "AutoRun" -Value $newValue
        }
    } elseif ($existing -and $existing.AutoRun.Trim()) {
        if ($DryRun) {
            Write-Info "Would append to existing cmd.exe AutoRun"
        } else {
            $newValue = $existing.AutoRun.Trim() + " & " + $cmdCommand
            Set-ItemProperty -Path $regPath -Name "AutoRun" -Value $newValue
        }
    } else {
        if ($DryRun) {
            Write-Info "Would create cmd.exe AutoRun registry key"
        } else {
            Set-ItemProperty -Path $regPath -Name "AutoRun" -Value $cmdCommand
        }
    }
    Write-OK "cmd.exe AutoRun hook: $regPath"
}

# ── Summary ───────────────────────────────────────────────────────────

Write-Host ""
Write-Host "Deployment summary:" -ForegroundColor White
Write-Host "  Script:         $ScriptPath"
Write-Host "  Warning:        $WarningDays days"
Write-Host "  Interval task:  $TaskName (every ${IntervalHours}h)"
Write-Host "  Logon task:     $logonTaskName (at user logon, 30s delay)"
if (-not $NoProfile) {
    Write-Host "  PS profile:     $($PROFILE.AllUsersAllHosts) (all users)"
}
if ($CmdPrompt) {
    Write-Host "  cmd.exe:        AutoRun registry hook (HKLM)"
}
if ($NetlogonCopy) {
    Write-Host "  NETLOGON:       $env:LOGONSERVER\NETLOGON\$ScriptName"
}
Write-Host ""
Write-Host "Users will see warnings via:" -ForegroundColor White
Write-Host "  MessageBox popup every $IntervalHours hours (scheduled task)"
Write-Host "  MessageBox popup at logon (logon trigger task)"
Write-Host "  Terminal banner in new PowerShell windows (profile hook)"
if ($CmdPrompt) {
    Write-Host "  Terminal banner in new cmd.exe windows (AutoRun hook)"
}
Write-Host ""
Write-Info "Test with: & '$ScriptPath' -Test"
Write-Info "Remove with: .\deploy-password-expiry-checker.ps1 -Remove"
