Scripts

Share this post:

These scripts are shared publicly to help others save time, learn, and reuse proven solutions.
The goal is simple: give back to the community by making real‑world remediation and automation scripts easy to access and use.

(HP) debloat script

In the example HP software removal is set, however you can customize by replacing or adding software display names in the $softwareList array

Manual run version

# List of software to check
$softwareList = @(
    "HP Wolf Security",
    "HP Wolf Security - Console",
    "Poly Lens",
    "HP Sure Run Module",
    "HP Sure Recover",
    "HP Security Update Service",
    "HPSureShieldAI",
    "HP Client Security Manager",
    "HP Sure Click",
    "HP Sure Run"
)

# Check if any software is installed
$installedSoftware = Get-WmiObject -Class Win32_Product -ErrorAction SilentlyContinue |
    Where-Object { $softwareList -contains $_.Name }

$removedSoftware = @()

if ($installedSoftware) {
    foreach ($software in $installedSoftware) {
        Write-Host "$($software.Name) is installed on the computer. Removing..."

        $result = $software.Uninstall()
        if ($result.ReturnValue -eq 0) {
            Write-Host "Removed: $($software.Name)"
            $removedSoftware += $software.Name
        }
        else {
            Write-Host "Failed to remove: $($software.Name) (ReturnValue: $($result.ReturnValue))"
        }
    }
}
else {
    Write-Host "None of the listed bloatware found on your PC."
}
if ($removedSoftware.Count -eq 0 -and -not $installedSoftware) {
    exit
}
if ($removedSoftware.Count -eq $softwareList.Count) {
    Write-Host "All applications were successfully removed."
}
else {
    Write-Host "Some applications were not removed."
}

Custom Remediation – detection script

upload this one to Intune custom remediation scripts to detect if any software in the $software is installed on a targeted device

# List of software to check
$softwareList = @(
    "HP Wolf Security",
    "HP Wolf Security - Console",
    "Poly Lens",
    "HP Sure Run Module",
    "HP Sure Recover",
    "HP Security Update Service",
    "HPSureShieldAI",
    "HP Client Security Manager",
    "HP Sure Click",
    "HP Sure Run"
)

# Create the 'C:\install' folder if it does not exist
$installFolderPath = "C:\install"
if (-not (Test-Path -Path $installFolderPath)) {
    New-Item -ItemType Directory -Path $installFolderPath | Out-Null
}

# Check if any software is installed
$installedSoftware = Get-WmiObject -Class Win32_Product -ErrorAction SilentlyContinue | Where-Object { $softwareList -contains $_.Name }

if ($installedSoftware) {
    foreach ($software in $installedSoftware) {
        "$($software.Name) is installed on the computer." | Out-File -FilePath "$installFolderPath\HP_Bloatware.txt" -Append
    }
    exit 1
}
else {
    foreach ($software in $softwareList) {
        "$software is not installed on the computer." | Out-File -FilePath "$installFolderPath\HP_Bloatware.txt" -Append
    }
    exit 0
}

exit 0

Custom remediation – Removal Script

upload this one to Intune custom remediation scripts to remediate if any software in the $software is installed on a targeted device

# List of software to check
$softwareList = @(
    "HP Wolf Security",
    "HP Wolf Security - Console",
    "Poly Lens",
    "HP Sure Run Module",
    "HP Sure Recover",
    "HP Security Update Service",
    "HPSureShieldAI",
    "HP Client Security Manager",
    "HP Sure Click",
    "HP Sure Run"
)

# Create the 'C:\install' folder if it does not exist
$installFolderPath = "C:\install"
if (-not (Test-Path -Path $installFolderPath)) {
    New-Item -ItemType Directory -Path $installFolderPath | Out-Null
}

# Check if any software is installed
$installedSoftware = Get-WmiObject -Class Win32_Product -ErrorAction SilentlyContinue | Where-Object { $softwareList -contains $_.Name } 

$removedSoftware = @()

if ($installedSoftware) {
    foreach ($software in $installedSoftware) {
        # "$($software.Name) is installed on the computer. Removing..." | Out-File -FilePath "$installFolderPath\HP_Bloatware.txt" -Append
        $software.Uninstall()
        $removedSoftware += $software.Name
    }
    # $removedSoftware | ForEach-Object { "removed: $_" } | Out-File -FilePath "$installFolderPath\HP_Bloatware.txt" -Append
}
else {
    # "No HP Bloatware found on your PC" | Out-File -FilePath "$installFolderPath\HP_Bloatware.txt" -Append
    exit 0
}

if ($removedSoftware.Count -eq $softwareList.Count) {
    # "All applications were successfully removed." | Out-File -FilePath "$installFolderPath\HP_Bloatware.txt" -Append
    exit 0
}
else {
    # "Some applications were not removed." | Out-File -FilePath "$installFolderPath\HP_Bloatware.txt" -Append
    exit 0
}

exit 0

Hp Connection Optimizer removal scripts

# Check if the file exists
if (Test-Path "C:\Program Files (x86)\InstallShield Installation Information\{6468C4A5-E47E-405F-B675-A70A70983EA6}\Setup.exe") {
    # Write the message to the file
    # "HP Connection Optimizer is installed on the computer" | Out-File -FilePath "C:\install\HP_Bloatware_CO.txt"
    # Exit with code 1 (for rememdiation script usage in Itnue)
    exit 1
} else {
    # "HP Connection Optimizer is not installed on the computer" | Out-File -FilePath "C:\install\HP_Bloatware-CO.txt"
    # Exit with code 0 (for rememdiation script usage in Itnue)
    exit 0
}
exit 0


# silently uninstall HP Connection Optimizer

# create c:\install folder if it does not exist
$installFolderPath = "C:\install"
if (-not (Test-Path -Path $installFolderPath)) {
    New-Item -ItemType Directory -Path $installFolderPath | Out-Null
}


If (Test-Path "C:\Program Files (x86)\InstallShield Installation Information\{6468C4A5-E47E-405F-B675-A70A70983EA6}\Setup.exe") {
    $optimizerUninstallAnswer = "[InstallShield Silent]
Version=v7.00
File=Response File
[File Transfer]
OverwrittenReadOnly=NoToAll
[{6468C4A5-E47E-405F-B675-A70A70983EA6}-DlgOrder]
Dlg0={6468C4A5-E47E-405F-B675-A70A70983EA6}-SdWelcomeMaint-0
Count=3
Dlg1={6468C4A5-E47E-405F-B675-A70A70983EA6}-MessageBox-0
Dlg2={6468C4A5-E47E-405F-B675-A70A70983EA6}-SdFinishReboot-0
[{6468C4A5-E47E-405F-B675-A70A70983EA6}-SdWelcomeMaint-0]
Result=303
[{6468C4A5-E47E-405F-B675-A70A70983EA6}-MessageBox-0]
Result=6
[Application]
Name=HP Connection Optimizer
Version=2.0.18.0
Company=HP Inc.
Lang=0409
[{6468C4A5-E47E-405F-B675-A70A70983EA6}-SdFinishReboot-0]
Result=1
BootOption=0
"
    $optimizerUninstallAnswer | Out-File $env:TEMP\optimizer.iss
    $arguments = "/s /f1`"$env:Temp\optimizer.iss`" /f2`"$env:TEMP\Uninstall.log`""
    Start-Process "C:\Program Files (x86)\InstallShield Installation Information\{6468C4A5-E47E-405F-B675-A70A70983EA6}\Setup.exe" -ArgumentList $arguments -PassThru -Wait
    "Removing HP Connection Optimizer from the computer." | Out-File -FilePath "$installFolderPath\HP_Bloatware_CO.txt" -Append
    exit 0
}
else {
    "Removal found HP Connection Optimizer is not installed on the computer." | Out-File -FilePath "$installFolderPath\HP_Bloatware_CO.txt" -Append
    exit 0
}
    
exit 0

Corporate Device Identifiers script

$manufacturer = (Get-CimInstance -ClassName Win32_ComputerSystem).Manufacturer
$model = (Get-CimInstance -ClassName Win32_ComputerSystem).Model
$serialNumber = (Get-CimInstance -ClassName Win32_BIOS).SerialNumber

"$manufacturer,$model,$serialNumber"

Script to fix public firewall profile
Run to install as a scheduled task, checks if profile is wrong, resets the network connection only if needed

$scriptContent = @"
# FixPubFWProfile.ps1
# This script fixes the public network profile

# Get the network profiles
`$networkProfiles = Get-NetConnectionProfile

# Wait for 60 seconds
Start-Sleep -Seconds 60

# Loop through each profile and reset the nic if it is public
foreach (`$Nprofile in `$networkProfiles) {
    if (`$Nprofile.NetworkCategory -eq "Public") { 
        Restart-NetAdapter -Name `$Nprofile.InterfaceAlias
    }
}
"@

$scriptPath = "c:\Install\Scripts\FixPubFWProfile.ps1"

# Create the directory if it doesn't exist
if (-not (Test-Path -Path (Split-Path -Path $scriptPath))) {
    New-Item -ItemType Directory -Path (Split-Path -Path $scriptPath) -Force
}

# Write the script content to the file
Set-Content -Path $scriptPath -Value $scriptContent

Write-Output "Script created at $scriptPath"

$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -NoProfile -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable

#check if the task already exists
$taskExists = Get-ScheduledTask -TaskName "FixPublicNetworkProfile" -ErrorAction SilentlyContinue
if ($taskExists) {
    Write-Output "Scheduled task 'FixPublicNetworkProfile' already exists"
}
else {
    Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -Settings $settings -TaskName "FixPublicNetworkProfile" -Description "Fixes the public network profile 1 minute after startup"
    Write-Output "Scheduled task 'FixPublicNetworkProfile' created to run at startup with a 1 minute delay in the script"
}

Fix-Public-Network-Profile.ps1

SpaceMonger

Script that checks for misconfigurations caused by unsupported scripts for optimization/debloating/gaming

<#
.SYNOPSIS
    Detect unsupported Windows optimization, debloater, privacy, or gaming tweak damage.

.DESCRIPTION
    Non-elevated Windows health detection script.

    It checks:
    - Critical Windows services
    - Defender health
    - Defender policy sabotage
    - Defender running mode
    - Windows Firewall service and profiles
    - Windows Update services and policies
    - Delivery Optimization
    - Microsoft Store services and package presence
    - Edge and WebView2 presence
    - SmartScreen
    - UAC
    - VBS
    - Credential Guard
    - Memory Integrity
    - LSASS protection
    - Intune / MDM related service
    - Windows Search
    - Disabled critical scheduled tasks
    - RDP and NLA hardening

.NOTES
    Recommended Intune settings:
    - Run this script using the logged-on credentials: Yes
    - Run script in 64-bit PowerShell: Yes

    Exit codes:
    - 0 = No blocking issues found
    - 1 = Blocking issues found
#>

# -------------------------------------------------------------------------
# Configuration
# -------------------------------------------------------------------------

$FailOnSeverity = @("High")

$ReportFileName = "WindowsOptimizationHealthReport.html"

$PreferredReportFolders = @(
    "$(Join-Path ([Environment]::GetFolderPath('Desktop')) 'WindowsOptimizationHealth')",
    "$env:LOCALAPPDATA\WindowsOptimizationHealth",
    "$env:TEMP\WindowsOptimizationHealth"
)

$Checks = @()

$IgnoreDisabledTasks = @(
    "\Microsoft\Windows\Servicing\OOBEFodSetup",
    "\Microsoft\Windows\InstallService\WakeUpAndContinueUpdates",
    "\Microsoft\Windows\InstallService\WakeUpAndScanForUpdates"
)

# -------------------------------------------------------------------------
# Helper functions
# -------------------------------------------------------------------------

function Add-Check {
    param(
        [string]$Category,
        [string]$Component,
        [string]$DisplayName,
        [ValidateSet("Pass","Fail","Warning","Info")]
        [string]$State,
        [ValidateSet("High","Medium","Low","Info")]
        [string]$Severity,
        [string]$Expected,
        [string]$CurrentValue,
        [string]$Details
    )

    $script:Checks += [PSCustomObject]@{
        Category     = $Category
        Component    = $Component
        DisplayName  = $DisplayName
        State        = $State
        Severity     = $Severity
        Expected     = $Expected
        CurrentValue = $CurrentValue
        Details      = $Details
    }
}

function Get-RegValue {
    param(
        [string]$Path,
        [string]$Name
    )

    try {
        $Item = Get-ItemProperty -Path $Path -Name $Name -ErrorAction Stop
        return $Item.$Name
    }
    catch {
        return $null
    }
}

function Get-ServiceStartupType {
    param(
        [string]$ServiceName
    )

    try {
        $ServicePath = "HKLM:\SYSTEM\CurrentControlSet\Services\$ServiceName"
        $ServiceReg = Get-ItemProperty -Path $ServicePath -ErrorAction Stop

        switch ($ServiceReg.Start) {
            0 { return "Boot" }
            1 { return "System" }
            2 { return "Automatic" }
            3 { return "Manual" }
            4 { return "Disabled" }
            default { return "Unknown" }
        }
    }
    catch {
        return "Unknown"
    }
}

function Test-PathAny {
    param(
        [string[]]$Paths
    )

    foreach ($Path in $Paths) {
        if (Test-Path $Path) {
            return $true
        }
    }

    return $false
}

function Get-ReportPath {
    foreach ($Folder in $PreferredReportFolders) {
        try {
            if (-not (Test-Path $Folder)) {
                New-Item -Path $Folder -ItemType Directory -Force -ErrorAction Stop | Out-Null
            }

            $TestFile = Join-Path $Folder "write-test.tmp"
            "test" | Out-File -FilePath $TestFile -Encoding utf8 -Force -ErrorAction Stop
            Remove-Item -Path $TestFile -Force -ErrorAction SilentlyContinue

            return (Join-Path $Folder $ReportFileName)
        }
        catch {
        }
    }

    return (Join-Path $env:TEMP $ReportFileName)
}

function ConvertTo-HtmlEncoded {
    param(
        [object]$Value
    )

    if ($null -eq $Value) {
        return ""
    }

    return [System.Net.WebUtility]::HtmlEncode([string]$Value)
}

function Test-EdgeUpdateClient {
    param(
        [string]$ProductName
    )

    $ClientRoots = @(
        "HKLM:\SOFTWARE\Microsoft\EdgeUpdate\Clients",
        "HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients"
    )

    foreach ($Root in $ClientRoots) {
        if (-not (Test-Path $Root)) {
            continue
        }

        try {
            $Clients = Get-ChildItem -Path $Root -ErrorAction Stop

            foreach ($Client in $Clients) {
                $Props = Get-ItemProperty -Path $Client.PSPath -ErrorAction SilentlyContinue

                $Name = $Props.name
                $Version = $Props.pv

                if ($Name -and $Name -like "*$ProductName*" -and $Version) {
                    return $true
                }
            }
        }
        catch {
        }
    }

    return $false
}

function Get-StateCssClass {
    param(
        [string]$State
    )

    switch ($State) {
        "Pass" { return "state-pass" }
        "Fail" { return "state-fail" }
        "Warning" { return "state-warning" }
        "Info" { return "state-info" }
        default { return "state-info" }
    }
}

function Get-SeverityCssClass {
    param(
        [string]$Severity
    )

    switch ($Severity) {
        "High" { return "severity-high" }
        "Medium" { return "severity-medium" }
        "Low" { return "severity-low" }
        "Info" { return "severity-info" }
        default { return "severity-info" }
    }
}

# -------------------------------------------------------------------------
# 1. Critical service startup checks
# -------------------------------------------------------------------------

$ExpectedServices = @(
    # Windows Update and content delivery
    @{ Name = "wuauserv";              DisplayName = "Windows Update";                         Expected = @("Manual","Automatic"); Required = $true;  Severity = "High" }
    @{ Name = "BITS";                  DisplayName = "Background Intelligent Transfer Service"; Expected = @("Manual","Automatic"); Required = $true;  Severity = "High" }
    @{ Name = "UsoSvc";                DisplayName = "Update Orchestrator Service";             Expected = @("Manual","Automatic"); Required = $true;  Severity = "High" }
    @{ Name = "DoSvc";                 DisplayName = "Delivery Optimization";                   Expected = @("Manual","Automatic"); Required = $true;  Severity = "High" }
    @{ Name = "CryptSvc";              DisplayName = "Cryptographic Services";                  Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "TrustedInstaller";      DisplayName = "Windows Modules Installer";               Expected = @("Manual");             Required = $true;  Severity = "High" }

    # Defender and security
    @{ Name = "WinDefend";             DisplayName = "Microsoft Defender Antivirus";            Expected = @("Manual","Automatic"); Required = $true;  Severity = "High" }
    @{ Name = "SecurityHealthService"; DisplayName = "Windows Security Service";                Expected = @("Manual","Automatic"); Required = $true;  Severity = "High" }
    @{ Name = "MpsSvc";                DisplayName = "Windows Defender Firewall";               Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "Sense";                 DisplayName = "Microsoft Defender for Endpoint";         Expected = @("Manual","Automatic"); Required = $false; Severity = "High" }

    # Core Windows functionality
    @{ Name = "EventLog";              DisplayName = "Windows Event Log";                       Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "RpcSs";                 DisplayName = "Remote Procedure Call";                   Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "DcomLaunch";            DisplayName = "DCOM Server Process Launcher";            Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "RpcEptMapper";          DisplayName = "RPC Endpoint Mapper";                     Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "Schedule";              DisplayName = "Task Scheduler";                          Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "ProfSvc";               DisplayName = "User Profile Service";                    Expected = @("Automatic");          Required = $true;  Severity = "High" }

    # Networking
    @{ Name = "Dhcp";                  DisplayName = "DHCP Client";                             Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "Dnscache";              DisplayName = "DNS Client";                              Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "LanmanWorkstation";     DisplayName = "Workstation";                             Expected = @("Automatic");          Required = $true;  Severity = "High" }
    @{ Name = "LanmanServer";          DisplayName = "Server";                                  Expected = @("Manual","Automatic"); Required = $true;  Severity = "Medium" }

    # Store and app platform
    @{ Name = "InstallService";        DisplayName = "Microsoft Store Install Service";         Expected = @("Manual","Automatic"); Required = $true;  Severity = "Medium" }
    @{ Name = "AppXSvc";               DisplayName = "AppX Deployment Service";                 Expected = @("Manual","Automatic"); Required = $true;  Severity = "Medium" }
    @{ Name = "ClipSVC";               DisplayName = "Client License Service";                  Expected = @("Manual","Automatic"); Required = $true;  Severity = "Medium" }

    # Intune / MDM related
    @{ Name = "dmwappushservice";      DisplayName = "Device Management WAP Push Routing";      Expected = @("Manual","Automatic"); Required = $true;  Severity = "Medium" }

    # User experience
    @{ Name = "Appinfo";               DisplayName = "Application Information";                 Expected = @("Manual");             Required = $true;  Severity = "Medium" }
    @{ Name = "Themes";                DisplayName = "Themes";                                  Expected = @("Automatic");          Required = $true;  Severity = "Low" }
    @{ Name = "WpnService";            DisplayName = "Windows Push Notifications";              Expected = @("Manual","Automatic"); Required = $true;  Severity = "Medium" }
    @{ Name = "WSearch";               DisplayName = "Windows Search";                          Expected = @("Manual","Automatic"); Required = $true;  Severity = "Medium" }

    # Microsoft Edge update services
    @{ Name = "edgeupdate";            DisplayName = "Microsoft Edge Update Service";           Expected = @("Manual","Automatic"); Required = $false; Severity = "Medium" }
    @{ Name = "edgeupdatem";           DisplayName = "Microsoft Edge Update Service Machine";   Expected = @("Manual","Automatic"); Required = $false; Severity = "Medium" }

    # Remote Desktop
    @{ Name = "TermService";           DisplayName = "Remote Desktop Services";                 Expected = @("Manual","Automatic"); Required = $true;  Severity = "Medium" }
)

foreach ($Svc in $ExpectedServices) {

    $Service = Get-Service -Name $Svc.Name -ErrorAction SilentlyContinue
    $ExpectedText = $Svc.Expected -join ", "

    if (-not $Service) {

        if ($Svc.Required) {
            Add-Check `
                -Category "Services" `
                -Component $Svc.Name `
                -DisplayName $Svc.DisplayName `
                -State "Fail" `
                -Severity $Svc.Severity `
                -Expected $ExpectedText `
                -CurrentValue "Missing" `
                -Details "Required service was not found."
        }
        else {
            Add-Check `
                -Category "Services" `
                -Component $Svc.Name `
                -DisplayName $Svc.DisplayName `
                -State "Warning" `
                -Severity $Svc.Severity `
                -Expected $ExpectedText `
                -CurrentValue "Missing" `
                -Details "Optional service was not found. Verify this is expected for this device."
        }

        continue
    }

    $StartupType = Get-ServiceStartupType -ServiceName $Svc.Name
    $CurrentValue = "$StartupType / $($Service.Status)"

    if ($StartupType -in $Svc.Expected) {
        Add-Check `
            -Category "Services" `
            -Component $Svc.Name `
            -DisplayName $Svc.DisplayName `
            -State "Pass" `
            -Severity "Info" `
            -Expected $ExpectedText `
            -CurrentValue $CurrentValue `
            -Details "Service startup type matches the expected baseline."
    }
    else {
        Add-Check `
            -Category "Services" `
            -Component $Svc.Name `
            -DisplayName $Svc.DisplayName `
            -State "Fail" `
            -Severity $Svc.Severity `
            -Expected $ExpectedText `
            -CurrentValue $CurrentValue `
            -Details "Unexpected service startup type. This is commonly caused by optimizer, debloater, privacy, or gaming tweak tools."
    }
}

# -------------------------------------------------------------------------
# 2. Defender health checks
# -------------------------------------------------------------------------

try {
    $MpStatus = Get-MpComputerStatus -ErrorAction Stop

    if ($MpStatus.PSObject.Properties.Name -contains "AMRunningMode") {
        if ($MpStatus.AMRunningMode -match "Disabled") {
            Add-Check "Defender" "AMRunningMode" "Defender Running Mode" "Fail" "High" "Normal / Active" $MpStatus.AMRunningMode "Defender is disabled."
        }
        elseif ($MpStatus.AMRunningMode -match "Passive") {
            Add-Check "Defender" "AMRunningMode" "Defender Running Mode" "Warning" "Medium" "Normal / Active" $MpStatus.AMRunningMode "Defender is in passive mode. This may be expected with another antivirus, but should be verified."
        }
        else {
            Add-Check "Defender" "AMRunningMode" "Defender Running Mode" "Pass" "Info" "Normal / Active" $MpStatus.AMRunningMode "Defender running mode looks healthy."
        }
    }

    $DefenderBooleanChecks = @(
        @{ Name = "AntivirusEnabled";          DisplayName = "Defender Antivirus";              Severity = "High" }
        @{ Name = "RealTimeProtectionEnabled"; DisplayName = "Real-time Protection";             Severity = "High" }
        @{ Name = "AMServiceEnabled";          DisplayName = "Defender Antimalware Service";     Severity = "High" }
        @{ Name = "AntispywareEnabled";        DisplayName = "Defender Antispyware";             Severity = "High" }
        @{ Name = "BehaviorMonitorEnabled";    DisplayName = "Behavior Monitoring";              Severity = "High" }
        @{ Name = "IoavProtectionEnabled";     DisplayName = "Downloaded File Scanning";         Severity = "High" }
        @{ Name = "OnAccessProtectionEnabled"; DisplayName = "On-access Protection";             Severity = "High" }
        @{ Name = "NISEnabled";                DisplayName = "Network Inspection System";        Severity = "Medium" }
        @{ Name = "IsTamperProtected";         DisplayName = "Tamper Protection";                Severity = "High" }
    )

    foreach ($Check in $DefenderBooleanChecks) {
        if ($MpStatus.PSObject.Properties.Name -contains $Check.Name) {
            $Value = $MpStatus.($Check.Name)

            if ($Value -eq $true) {
                Add-Check "Defender" $Check.Name $Check.DisplayName "Pass" "Info" "Enabled" "Enabled" "Defender setting is enabled."
            }
            elseif ($Value -eq $false) {
                Add-Check "Defender" $Check.Name $Check.DisplayName "Fail" $Check.Severity "Enabled" "Disabled" "Defender setting is disabled."
            }
            else {
                Add-Check "Defender" $Check.Name $Check.DisplayName "Info" "Info" "Enabled" $Value "Defender setting returned an unexpected value."
            }
        }
    }
}
catch {
    Add-Check `
        -Category "Defender" `
        -Component "Get-MpComputerStatus" `
        -DisplayName "Defender Health" `
        -State "Warning" `
        -Severity "Medium" `
        -Expected "Readable Defender status" `
        -CurrentValue "Unable to query" `
        -Details "Could not query Defender health. Defender may be removed, broken, disabled, or managed by another antivirus."
}

# -------------------------------------------------------------------------
# 3. Defender policy sabotage checks
# -------------------------------------------------------------------------

$DefenderPolicyChecks = @(
    @{ Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender"; Name = "DisableAntiSpyware"; DisplayName = "Disable Defender Antispyware Policy"; Severity = "High" }
    @{ Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender"; Name = "DisableAntiVirus"; DisplayName = "Disable Defender Antivirus Policy"; Severity = "High" }
    @{ Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection"; Name = "DisableRealtimeMonitoring"; DisplayName = "Disable Real-time Monitoring Policy"; Severity = "High" }
    @{ Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection"; Name = "DisableBehaviorMonitoring"; DisplayName = "Disable Behavior Monitoring Policy"; Severity = "High" }
    @{ Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection"; Name = "DisableIOAVProtection"; DisplayName = "Disable Downloaded File Scanning Policy"; Severity = "High" }
    @{ Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection"; Name = "DisableScriptScanning"; DisplayName = "Disable Script Scanning Policy"; Severity = "High" }
)

foreach ($PolicyCheck in $DefenderPolicyChecks) {
    $Value = Get-RegValue -Path $PolicyCheck.Path -Name $PolicyCheck.Name

    if ($Value -eq 1) {
        Add-Check "Defender Policy" $PolicyCheck.Name $PolicyCheck.DisplayName "Fail" $PolicyCheck.Severity "Not configured or 0" $Value "Policy disables or weakens Defender protection."
    }
    elseif ($null -eq $Value) {
        Add-Check "Defender Policy" $PolicyCheck.Name $PolicyCheck.DisplayName "Pass" "Info" "Not configured or 0" "Not configured" "Policy is not configured."
    }
    else {
        Add-Check "Defender Policy" $PolicyCheck.Name $PolicyCheck.DisplayName "Pass" "Info" "Not configured or 0" $Value "Policy is not configured to disable protection."
    }
}

# -------------------------------------------------------------------------
# 4. Windows Update policy checks
# -------------------------------------------------------------------------

$WindowsUpdatePolicyChecks = @(
    @{ Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"; Name = "DisableWindowsUpdateAccess"; DisplayName = "Disable Windows Update Access"; Severity = "High" }
    @{ Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"; Name = "NoAutoUpdate"; DisplayName = "Disable Automatic Updates"; Severity = "High" }
)

foreach ($WUCheck in $WindowsUpdatePolicyChecks) {
    $Value = Get-RegValue -Path $WUCheck.Path -Name $WUCheck.Name

    if ($Value -eq 1) {
        Add-Check "Windows Update Policy" $WUCheck.Name $WUCheck.DisplayName "Fail" $WUCheck.Severity "Not configured or 0" $Value "Windows Update is disabled or restricted by policy."
    }
    elseif ($null -eq $Value) {
        Add-Check "Windows Update Policy" $WUCheck.Name $WUCheck.DisplayName "Pass" "Info" "Not configured or 0" "Not configured" "Policy is not configured."
    }
    else {
        Add-Check "Windows Update Policy" $WUCheck.Name $WUCheck.DisplayName "Pass" "Info" "Not configured or 0" $Value "Policy is not configured to block Windows Update."
    }
}

# -------------------------------------------------------------------------
# 5. Microsoft Store checks
# -------------------------------------------------------------------------

$StorePolicyDisabled = $false
$StorePolicyPaths = @(
    "HKLM:\SOFTWARE\Policies\Microsoft\WindowsStore",
    "HKCU:\SOFTWARE\Policies\Microsoft\WindowsStore"
)

foreach ($Path in $StorePolicyPaths) {
    $RemoveWindowsStore = Get-RegValue -Path $Path -Name "RemoveWindowsStore"

    if ($RemoveWindowsStore -eq 1) {
        $StorePolicyDisabled = $true
        break
    }
}

if ($StorePolicyDisabled) {
    Add-Check "Microsoft Store" "RemoveWindowsStore" "Microsoft Store Policy" "Warning" "Medium" "Not configured or 0" "Disabled by policy" "Microsoft Store is disabled by policy. Verify this matches the customer baseline."
}
else {
    Add-Check "Microsoft Store" "RemoveWindowsStore" "Microsoft Store Policy" "Pass" "Info" "Not configured or 0" "Not disabled by policy" "Microsoft Store is not blocked by policy."
}

try {
    $StorePackage = Get-AppxPackage -Name "Microsoft.WindowsStore" -ErrorAction Stop
    Add-Check "Microsoft Store" "Microsoft.WindowsStore" "Microsoft Store Package" "Pass" "Info" "Present for current user" "Present" "Microsoft Store package is present for the current user."
}
catch {
    Add-Check "Microsoft Store" "Microsoft.WindowsStore" "Microsoft Store Package" "Fail" "High" "Present for current user" "Missing" "Microsoft Store package is missing for the current user."
}

# -------------------------------------------------------------------------
# 6. Edge, WebView2, and Winget checks
# -------------------------------------------------------------------------

$EdgePaths = @(
    "C:\Program Files (x86)\Microsoft\Edge\Application",
    "C:\Program Files\Microsoft\Edge\Application"
)

$WebViewPaths = @(
    "C:\Program Files (x86)\Microsoft\EdgeWebView\Application",
    "C:\Program Files\Microsoft\EdgeWebView\Application"
)

if (Test-PathAny -Paths $EdgePaths) {
    Add-Check "Application Integrity" "MicrosoftEdgeFolder" "Microsoft Edge Application Folder" "Pass" "Info" "Present" "Present" "Microsoft Edge application folder was found."
}
else {
    Add-Check "Application Integrity" "MicrosoftEdgeFolder" "Microsoft Edge Application Folder" "Fail" "High" "Present" "Missing" "Microsoft Edge application folder was not found."
}

if (Test-PathAny -Paths $WebViewPaths) {
    Add-Check "Application Integrity" "WebView2Folder" "Microsoft Edge WebView2 Runtime Folder" "Pass" "Info" "Present" "Present" "WebView2 Runtime folder was found."
}
else {
    Add-Check "Application Integrity" "WebView2Folder" "Microsoft Edge WebView2 Runtime Folder" "Fail" "High" "Present" "Missing" "WebView2 Runtime folder was not found."
}

if (Test-EdgeUpdateClient -ProductName "Edge") {
    Add-Check "Application Integrity" "EdgeUpdateClient" "Edge Update Registry Client" "Pass" "Info" "Present" "Present" "Edge Update registry client was found."
}
else {
    Add-Check "Application Integrity" "EdgeUpdateClient" "Edge Update Registry Client" "Warning" "Medium" "Present" "Missing" "Edge Update registry client was not found. This may indicate a broken or partially removed Edge installation."
}

if (Test-EdgeUpdateClient -ProductName "WebView") {
    Add-Check "Application Integrity" "WebView2UpdateClient" "WebView2 Update Registry Client" "Pass" "Info" "Present" "Present" "WebView2 Update registry client was found."
}
else {
    Add-Check "Application Integrity" "WebView2UpdateClient" "WebView2 Update Registry Client" "Warning" "Medium" "Present" "Missing" "WebView2 Update registry client was not found. This may indicate a broken or partially removed WebView2 installation."
}

try {
    $WingetCommand = Get-Command winget.exe -ErrorAction Stop
    Add-Check "Application Integrity" "Winget" "Windows Package Manager" "Pass" "Info" "Present" $WingetCommand.Source "Winget executable was found."
}
catch {
    Add-Check "Application Integrity" "Winget" "Windows Package Manager" "Warning" "Medium" "Present" "Missing" "Winget was not found for the current user context."
}

# -------------------------------------------------------------------------
# 7. SmartScreen checks
# -------------------------------------------------------------------------

$ExplorerSmartScreen = Get-RegValue -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" -Name "SmartScreenEnabled"
$PolicySmartScreen = Get-RegValue -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Name "EnableSmartScreen"
$EdgeSmartScreen = Get-RegValue -Path "HKLM:\SOFTWARE\Policies\Microsoft\Edge" -Name "SmartScreenEnabled"

if ($ExplorerSmartScreen -eq "Off") {
    Add-Check "SmartScreen" "ExplorerSmartScreenEnabled" "Windows SmartScreen" "Fail" "High" "Warn or RequireAdmin" $ExplorerSmartScreen "Windows SmartScreen is disabled."
}
elseif ($null -eq $ExplorerSmartScreen) {
    Add-Check "SmartScreen" "ExplorerSmartScreenEnabled" "Windows SmartScreen" "Info" "Info" "Warn or RequireAdmin" "Not configured" "SmartScreen registry value was not found."
}
else {
    Add-Check "SmartScreen" "ExplorerSmartScreenEnabled" "Windows SmartScreen" "Pass" "Info" "Warn or RequireAdmin" $ExplorerSmartScreen "Windows SmartScreen is not disabled."
}

if ($PolicySmartScreen -eq 0) {
    Add-Check "SmartScreen" "EnableSmartScreen" "SmartScreen Policy" "Fail" "High" "Not configured or 1" $PolicySmartScreen "SmartScreen is disabled by policy."
}
elseif ($null -eq $PolicySmartScreen) {
    Add-Check "SmartScreen" "EnableSmartScreen" "SmartScreen Policy" "Pass" "Info" "Not configured or 1" "Not configured" "SmartScreen policy is not configured."
}
else {
    Add-Check "SmartScreen" "EnableSmartScreen" "SmartScreen Policy" "Pass" "Info" "Not configured or 1" $PolicySmartScreen "SmartScreen policy is not configured to disable protection."
}

if ($EdgeSmartScreen -eq 0) {
    Add-Check "SmartScreen" "EdgeSmartScreenEnabled" "Microsoft Edge SmartScreen" "Fail" "High" "Not configured or 1" $EdgeSmartScreen "Microsoft Edge SmartScreen is disabled by policy."
}
elseif ($null -eq $EdgeSmartScreen) {
    Add-Check "SmartScreen" "EdgeSmartScreenEnabled" "Microsoft Edge SmartScreen" "Pass" "Info" "Not configured or 1" "Not configured" "Microsoft Edge SmartScreen policy is not configured."
}
else {
    Add-Check "SmartScreen" "EdgeSmartScreenEnabled" "Microsoft Edge SmartScreen" "Pass" "Info" "Not configured or 1" $EdgeSmartScreen "Microsoft Edge SmartScreen policy is not configured to disable protection."
}

# -------------------------------------------------------------------------
# 8. Firewall profile checks
# -------------------------------------------------------------------------

try {
    $FirewallProfiles = Get-NetFirewallProfile -ErrorAction Stop

    foreach ($Profile in $FirewallProfiles) {
        if ($Profile.Enabled -eq $true) {
            Add-Check "Firewall" $Profile.Name "Windows Firewall $($Profile.Name) Profile" "Pass" "Info" "Enabled" "Enabled" "Firewall profile is enabled."
        }
        else {
            Add-Check "Firewall" $Profile.Name "Windows Firewall $($Profile.Name) Profile" "Fail" "High" "Enabled" "Disabled" "Firewall profile is disabled."
        }
    }
}
catch {
    Add-Check "Firewall" "Get-NetFirewallProfile" "Windows Firewall Profiles" "Warning" "Medium" "Readable firewall profile status" "Unable to query" "Could not query Windows Firewall profile state."
}

# -------------------------------------------------------------------------
# 9. UAC, VBS, Credential Guard, Memory Integrity, LSASS protection
# -------------------------------------------------------------------------

$EnableLUA = Get-RegValue -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableLUA"

if ($EnableLUA -eq 0) {
    Add-Check "Security Features" "EnableLUA" "User Account Control" "Fail" "High" "Enabled" "Disabled" "UAC is disabled."
}
elseif ($EnableLUA -eq 1) {
    Add-Check "Security Features" "EnableLUA" "User Account Control" "Pass" "Info" "Enabled" "Enabled" "UAC is enabled."
}
else {
    Add-Check "Security Features" "EnableLUA" "User Account Control" "Info" "Info" "Enabled" "Not configured or unknown" "Could not determine UAC state from registry."
}

$EnableVBS = Get-RegValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard" -Name "EnableVirtualizationBasedSecurity"
$RequirePlatformSecurityFeatures = Get-RegValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard" -Name "RequirePlatformSecurityFeatures"
$LsaCfgFlags = Get-RegValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "LsaCfgFlags"
$HvciEnabled = Get-RegValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity" -Name "Enabled"
$RunAsPPL = Get-RegValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "RunAsPPL"

if ($EnableVBS -eq 0) {
    Add-Check "Security Features" "EnableVirtualizationBasedSecurity" "Virtualization Based Security" "Warning" "Medium" "Enabled where required" "Disabled" "VBS is explicitly disabled."
}
elseif ($EnableVBS -eq 1) {
    Add-Check "Security Features" "EnableVirtualizationBasedSecurity" "Virtualization Based Security" "Pass" "Info" "Enabled where required" "Enabled" "VBS is enabled."
}
else {
    Add-Check "Security Features" "EnableVirtualizationBasedSecurity" "Virtualization Based Security" "Info" "Info" "Enabled where required" "Not configured" "VBS is not explicitly configured."
}

if ($LsaCfgFlags -eq 0) {
    Add-Check "Security Features" "LsaCfgFlags" "Credential Guard" "Warning" "Medium" "Enabled where required" "Disabled" "Credential Guard appears to be explicitly disabled."
}
elseif ($LsaCfgFlags -eq 1 -or $LsaCfgFlags -eq 2) {
    Add-Check "Security Features" "LsaCfgFlags" "Credential Guard" "Pass" "Info" "Enabled where required" $LsaCfgFlags "Credential Guard appears to be enabled or configured."
}
else {
    Add-Check "Security Features" "LsaCfgFlags" "Credential Guard" "Info" "Info" "Enabled where required" "Not configured" "Credential Guard is not explicitly configured."
}

if ($HvciEnabled -eq 0) {
    Add-Check "Security Features" "HVCI" "Memory Integrity" "Warning" "Medium" "Enabled where required" "Disabled" "Memory Integrity is explicitly disabled."
}
elseif ($HvciEnabled -eq 1) {
    Add-Check "Security Features" "HVCI" "Memory Integrity" "Pass" "Info" "Enabled where required" "Enabled" "Memory Integrity is enabled."
}
else {
    Add-Check "Security Features" "HVCI" "Memory Integrity" "Info" "Info" "Enabled where required" "Not configured" "Memory Integrity is not explicitly configured."
}

if ($RunAsPPL -eq 1 -or $RunAsPPL -eq 2) {
    Add-Check "Security Features" "RunAsPPL" "LSASS Protection" "Pass" "Info" "Enabled where required" $RunAsPPL "LSASS protection appears to be enabled."
}
elseif ($RunAsPPL -eq 0) {
    Add-Check "Security Features" "RunAsPPL" "LSASS Protection" "Warning" "Medium" "Enabled where required" "Disabled" "LSASS protection is explicitly disabled."
}
else {
    Add-Check "Security Features" "RunAsPPL" "LSASS Protection" "Info" "Info" "Enabled where required" "Not configured" "LSASS protection is not explicitly configured."
}

if ($RequirePlatformSecurityFeatures -eq 0) {
    Add-Check "Security Features" "RequirePlatformSecurityFeatures" "Platform Security Features" "Warning" "Low" "Configured according to baseline" "Not required" "Platform security requirements are explicitly relaxed."
}
elseif ($null -eq $RequirePlatformSecurityFeatures) {
    Add-Check "Security Features" "RequirePlatformSecurityFeatures" "Platform Security Features" "Info" "Info" "Configured according to baseline" "Not configured" "Platform security requirements are not explicitly configured."
}
else {
    Add-Check "Security Features" "RequirePlatformSecurityFeatures" "Platform Security Features" "Pass" "Info" "Configured according to baseline" $RequirePlatformSecurityFeatures "Platform security feature requirements are configured."
}

# -------------------------------------------------------------------------
# 10. Critical scheduled task checks
# -------------------------------------------------------------------------

$CriticalTaskPaths = @(
    "\Microsoft\Windows\WindowsUpdate\",
    "\Microsoft\Windows\UpdateOrchestrator\",
    "\Microsoft\Windows\Application Experience\",
    "\Microsoft\Windows\InstallService\",
    "\Microsoft\Windows\PushToInstall\",
    "\Microsoft\Windows\Windows Defender\",
    "\Microsoft\Windows\ExploitGuard\",
    "\Microsoft\Windows\Device Information\",
    "\Microsoft\Windows\Shell\",
    "\Microsoft\Windows\Servicing\"
)

try {
    $ScheduledTasks = Get-ScheduledTask -ErrorAction Stop

    foreach ($CriticalPath in $CriticalTaskPaths) {
        $TasksInPath = $ScheduledTasks | Where-Object {
            $_.TaskPath.StartsWith($CriticalPath, [System.StringComparison]::OrdinalIgnoreCase)
        }

        $DisabledTasksInPath = $TasksInPath | Where-Object {
            $_.State -eq "Disabled"
        }

        if ($DisabledTasksInPath.Count -eq 0) {
            Add-Check `
                -Category "Scheduled Tasks" `
                -Component $CriticalPath `
                -DisplayName $CriticalPath `
                -State "Pass" `
                -Severity "Info" `
                -Expected "No disabled critical tasks" `
                -CurrentValue "No disabled tasks found" `
                -Details "No disabled scheduled tasks were found in this critical path."
        }
        else {
            foreach ($Task in $DisabledTasksInPath) {
                $TaskFullName = "$($Task.TaskPath)$($Task.TaskName)"

                if ($TaskFullName -in $IgnoreDisabledTasks) {
                    continue
                }

                Add-Check `
                    -Category "Scheduled Tasks" `
                    -Component $TaskFullName `
                    -DisplayName $Task.TaskName `
                    -State "Warning" `
                    -Severity "Medium" `
                    -Expected "Enabled unless intentionally disabled" `
                    -CurrentValue "Disabled" `
                    -Details "Critical Microsoft scheduled task is disabled."
            }
        }
    }
}
catch {
    Add-Check `
        -Category "Scheduled Tasks" `
        -Component "Get-ScheduledTask" `
        -DisplayName "Scheduled Task Query" `
        -State "Warning" `
        -Severity "Low" `
        -Expected "Readable scheduled tasks" `
        -CurrentValue "Unable to query" `
        -Details "Could not query scheduled tasks."
}

# -------------------------------------------------------------------------
# 11. RDP and NLA hardening checks
# -------------------------------------------------------------------------

$RdpTcpPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"
$RdpServerPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server"

$UserAuthentication = Get-RegValue -Path $RdpTcpPath -Name "UserAuthentication"
$fDenyTSConnections = Get-RegValue -Path $RdpServerPath -Name "fDenyTSConnections"

if ($UserAuthentication -eq 0) {
    Add-Check "Remote Desktop" "UserAuthentication" "Remote Desktop Network Level Authentication" "Fail" "High" "Enabled" "Disabled" "Network Level Authentication is disabled for RDP."
}
elseif ($UserAuthentication -eq 1) {
    Add-Check "Remote Desktop" "UserAuthentication" "Remote Desktop Network Level Authentication" "Pass" "Info" "Enabled" "Enabled" "Network Level Authentication is enabled for RDP."
}
else {
    Add-Check "Remote Desktop" "UserAuthentication" "Remote Desktop Network Level Authentication" "Info" "Info" "Enabled" "Not configured or unknown" "Could not determine the NLA state."
}

if ($fDenyTSConnections -eq 0) {
    Add-Check "Remote Desktop" "fDenyTSConnections" "Remote Desktop Access" "Warning" "Low" "Disabled unless explicitly required" "Enabled" "Remote Desktop is enabled. Verify this is intentional."
}
elseif ($fDenyTSConnections -eq 1) {
    Add-Check "Remote Desktop" "fDenyTSConnections" "Remote Desktop Access" "Pass" "Info" "Disabled unless explicitly required" "Disabled" "Remote Desktop is disabled."
}
else {
    Add-Check "Remote Desktop" "fDenyTSConnections" "Remote Desktop Access" "Info" "Info" "Disabled unless explicitly required" "Not configured or unknown" "Could not determine Remote Desktop access state."
}

# -------------------------------------------------------------------------
# 12. HTML report generation
# -------------------------------------------------------------------------

$ReportPath = Get-ReportPath

$DeviceName = $env:COMPUTERNAME
$UserName = "$env:USERDOMAIN\$env:USERNAME"
$GeneratedAt = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

$PassCount = ($Checks | Where-Object { $_.State -eq "Pass" }).Count
$FailCount = ($Checks | Where-Object { $_.State -eq "Fail" }).Count
$WarningCount = ($Checks | Where-Object { $_.State -eq "Warning" }).Count
$InfoCount = ($Checks | Where-Object { $_.State -eq "Info" }).Count
$TotalCount = $Checks.Count

$HighCount = ($Checks | Where-Object { $_.Severity -eq "High" -and $_.State -eq "Fail" }).Count
$MediumCount = ($Checks | Where-Object { $_.Severity -eq "Medium" -and $_.State -in @("Fail","Warning") }).Count
$LowCount = ($Checks | Where-Object { $_.Severity -eq "Low" -and $_.State -in @("Fail","Warning") }).Count

$SeverityOrder = @{
    High   = 1
    Medium = 2
    Low    = 3
    Info   = 4
}

$StateOrder = @{
    Fail    = 1
    Warning = 2
    Info    = 3
    Pass    = 4
}

$SortedChecks = $Checks | Sort-Object `
    @{ Expression = { $StateOrder[$_.State] } },
    @{ Expression = { $SeverityOrder[$_.Severity] } },
    Category,
    DisplayName

$Categories = $SortedChecks | Select-Object -ExpandProperty Category -Unique

$Css = @"
<style>
body {
    font-family: Segoe UI, Arial, sans-serif;
    background: #f5f7fb;
    color: #1f1f1f;
    margin: 0;
    padding: 0;
}

.header {
    background: linear-gradient(135deg, #005a9e, #0078d4);
    color: white;
    padding: 28px 36px;
}

.header h1 {
    margin: 0;
    font-size: 28px;
    font-weight: 600;
}

.header .subtitle {
    margin-top: 8px;
    font-size: 14px;
    opacity: 0.9;
}

.container {
    padding: 28px 36px;
}

.summary-grid {
    display: grid;
    grid-template-columns: repeat(5, minmax(140px, 1fr));
    gap: 16px;
    margin-bottom: 26px;
}

.card {
    background: white;
    border-radius: 12px;
    padding: 18px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.08);
    border-left: 6px solid #0078d4;
}

.card-title {
    font-size: 13px;
    color: #555;
    margin-bottom: 8px;
}

.card-value {
    font-size: 28px;
    font-weight: 700;
}

.card.pass {
    border-left-color: #107c10;
}

.card.fail {
    border-left-color: #d13438;
}

.card.warning {
    border-left-color: #ff8c00;
}

.card.info {
    border-left-color: #0078d4;
}

.section {
    background: white;
    border-radius: 12px;
    margin-bottom: 20px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.08);
    overflow: hidden;
}

.section h2 {
    background: #f0f4f8;
    margin: 0;
    padding: 16px 20px;
    font-size: 18px;
    border-bottom: 1px solid #d7dde5;
}

table {
    border-collapse: collapse;
    width: 100%;
    font-size: 13px;
}

th {
    background: #fafafa;
    color: #333;
    text-align: left;
    padding: 10px;
    border-bottom: 1px solid #d7dde5;
}

td {
    padding: 10px;
    border-bottom: 1px solid #eceff3;
    vertical-align: top;
}

tr:hover {
    background: #f9fbfd;
}

.badge {
    display: inline-block;
    padding: 4px 9px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
}

.state-pass {
    background: #dff6dd;
    color: #107c10;
}

.state-fail {
    background: #fde7e9;
    color: #d13438;
}

.state-warning {
    background: #fff4ce;
    color: #9d5d00;
}

.state-info {
    background: #e5f1fb;
    color: #005a9e;
}

.severity-high {
    color: #d13438;
    font-weight: 700;
}

.severity-medium {
    color: #9d5d00;
    font-weight: 700;
}

.severity-low {
    color: #605e5c;
    font-weight: 700;
}

.severity-info {
    color: #005a9e;
    font-weight: 700;
}

.footer {
    color: #666;
    font-size: 12px;
    margin-top: 24px;
}

.notice {
    background: #fff4ce;
    border-left: 6px solid #ffb900;
    padding: 14px 18px;
    border-radius: 10px;
    margin-bottom: 22px;
}

@media print {
    body {
        background: white;
    }

    .card,
    .section {
        box-shadow: none;
        border: 1px solid #ddd;
    }
}
</style>
"@

$HtmlBuilder = New-Object System.Text.StringBuilder

[void]$HtmlBuilder.AppendLine("<!DOCTYPE html>")
[void]$HtmlBuilder.AppendLine("<html>")
[void]$HtmlBuilder.AppendLine("<head>")
[void]$HtmlBuilder.AppendLine("<meta charset='UTF-8'>")
[void]$HtmlBuilder.AppendLine("<title>Windows Optimization Health Report</title>")
[void]$HtmlBuilder.AppendLine($Css)
[void]$HtmlBuilder.AppendLine("</head>")
[void]$HtmlBuilder.AppendLine("<body>")

[void]$HtmlBuilder.AppendLine("<div class='header'>")
[void]$HtmlBuilder.AppendLine("<h1>Windows Optimization Health Report</h1>")
[void]$HtmlBuilder.AppendLine("<div class='subtitle'>Device: $(ConvertTo-HtmlEncoded $DeviceName) | User: $(ConvertTo-HtmlEncoded $UserName) | Generated: $(ConvertTo-HtmlEncoded $GeneratedAt)</div>")
[void]$HtmlBuilder.AppendLine("</div>")

[void]$HtmlBuilder.AppendLine("<div class='container'>")

[void]$HtmlBuilder.AppendLine("<div class='notice'>")
[void]$HtmlBuilder.AppendLine("<strong>Purpose:</strong> This report checks for common unsupported Windows optimization, debloater, privacy, or gaming tweak changes. Review warnings against the customer baseline before remediation.")
[void]$HtmlBuilder.AppendLine("</div>")

[void]$HtmlBuilder.AppendLine("<div class='summary-grid'>")
[void]$HtmlBuilder.AppendLine("<div class='card info'><div class='card-title'>Total Checks</div><div class='card-value'>$TotalCount</div></div>")
[void]$HtmlBuilder.AppendLine("<div class='card pass'><div class='card-title'>Passed</div><div class='card-value'>$PassCount</div></div>")
[void]$HtmlBuilder.AppendLine("<div class='card warning'><div class='card-title'>Warnings</div><div class='card-value'>$WarningCount</div></div>")
[void]$HtmlBuilder.AppendLine("<div class='card fail'><div class='card-title'>Failed</div><div class='card-value'>$FailCount</div></div>")
[void]$HtmlBuilder.AppendLine("<div class='card fail'><div class='card-title'>High Severity Failures</div><div class='card-value'>$HighCount</div></div>")
[void]$HtmlBuilder.AppendLine("</div>")

[void]$HtmlBuilder.AppendLine("<div class='section'>")
[void]$HtmlBuilder.AppendLine("<h2>Severity Summary</h2>")
[void]$HtmlBuilder.AppendLine("<table>")
[void]$HtmlBuilder.AppendLine("<tr><th>Severity</th><th>Problem Count</th></tr>")
[void]$HtmlBuilder.AppendLine("<tr><td class='severity-high'>High</td><td>$HighCount</td></tr>")
[void]$HtmlBuilder.AppendLine("<tr><td class='severity-medium'>Medium</td><td>$MediumCount</td></tr>")
[void]$HtmlBuilder.AppendLine("<tr><td class='severity-low'>Low</td><td>$LowCount</td></tr>")
[void]$HtmlBuilder.AppendLine("</table>")
[void]$HtmlBuilder.AppendLine("</div>")

foreach ($Category in $Categories) {
    $CategoryChecks = $SortedChecks | Where-Object { $_.Category -eq $Category }

    [void]$HtmlBuilder.AppendLine("<div class='section'>")
    [void]$HtmlBuilder.AppendLine("<h2>$(ConvertTo-HtmlEncoded $Category)</h2>")
    [void]$HtmlBuilder.AppendLine("<table>")
    [void]$HtmlBuilder.AppendLine("<tr>")
    [void]$HtmlBuilder.AppendLine("<th>State</th>")
    [void]$HtmlBuilder.AppendLine("<th>Severity</th>")
    [void]$HtmlBuilder.AppendLine("<th>Component</th>")
    [void]$HtmlBuilder.AppendLine("<th>Display name</th>")
    [void]$HtmlBuilder.AppendLine("<th>Expected</th>")
    [void]$HtmlBuilder.AppendLine("<th>Current value</th>")
    [void]$HtmlBuilder.AppendLine("<th>Details</th>")
    [void]$HtmlBuilder.AppendLine("</tr>")

    foreach ($Check in $CategoryChecks) {
        $StateClass = Get-StateCssClass -State $Check.State
        $SeverityClass = Get-SeverityCssClass -Severity $Check.Severity

        [void]$HtmlBuilder.AppendLine("<tr>")
        [void]$HtmlBuilder.AppendLine("<td><span class='badge $StateClass'>$(ConvertTo-HtmlEncoded $Check.State)</span></td>")
        [void]$HtmlBuilder.AppendLine("<td class='$SeverityClass'>$(ConvertTo-HtmlEncoded $Check.Severity)</td>")
        [void]$HtmlBuilder.AppendLine("<td>$(ConvertTo-HtmlEncoded $Check.Component)</td>")
        [void]$HtmlBuilder.AppendLine("<td>$(ConvertTo-HtmlEncoded $Check.DisplayName)</td>")
        [void]$HtmlBuilder.AppendLine("<td>$(ConvertTo-HtmlEncoded $Check.Expected)</td>")
        [void]$HtmlBuilder.AppendLine("<td>$(ConvertTo-HtmlEncoded $Check.CurrentValue)</td>")
        [void]$HtmlBuilder.AppendLine("<td>$(ConvertTo-HtmlEncoded $Check.Details)</td>")
        [void]$HtmlBuilder.AppendLine("</tr>")
    }

    [void]$HtmlBuilder.AppendLine("</table>")
    [void]$HtmlBuilder.AppendLine("</div>")
}

[void]$HtmlBuilder.AppendLine("<div class='footer'>")
[void]$HtmlBuilder.AppendLine("Report path: $(ConvertTo-HtmlEncoded $ReportPath)")
[void]$HtmlBuilder.AppendLine("</div>")

[void]$HtmlBuilder.AppendLine("</div>")
[void]$HtmlBuilder.AppendLine("</body>")
[void]$HtmlBuilder.AppendLine("</html>")

$HtmlBuilder.ToString() | Out-File -FilePath $ReportPath -Encoding utf8 -Force

# -------------------------------------------------------------------------
# 13. Console output and Intune detection result
# -------------------------------------------------------------------------

Write-Host ""
Write-Host "Windows Optimization Health Report created:" -ForegroundColor Cyan
Write-Host $ReportPath
Write-Host ""

Write-Host "Summary:"
Write-Host "Total checks: $TotalCount"
Write-Host "Passed: $PassCount"
Write-Host "Warnings: $WarningCount"
Write-Host "Failed: $FailCount"
Write-Host "High severity failures: $HighCount"
Write-Host ""

$BlockingIssues = $Checks | Where-Object {
    $_.State -eq "Fail" -and
    $_.Severity -in $FailOnSeverity
}

if ($BlockingIssues.Count -gt 0) {
    Write-Host "Blocking issues found:" -ForegroundColor Red

    $BlockingIssues |
        Sort-Object Category, DisplayName |
        Format-Table Category, DisplayName, Severity, CurrentValue, Expected -AutoSize

    exit 1
}

Write-Host "No blocking issues found." -ForegroundColor Green
exit 0

Share this post: