@echo off
setlocal EnableExtensions

title Driver Unblock
set "DU_SELF=%~f0"

:: Relaunch as Administrator if needed
net session >nul 2>&1
if %errorlevel% neq 0 (
    cls
    echo ============================================================
    echo   Driver Unblock
    echo ============================================================
    echo.
    echo Administrator permission is required.
    echo.
    echo A Windows UAC prompt should appear now.
    echo Click YES to continue.
    echo.
    powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process -FilePath $env:DU_SELF -Verb RunAs"
    exit /b
)

:: Run embedded PowerShell payload from this same CMD file
powershell -NoProfile -ExecutionPolicy Bypass -Command "$ErrorActionPreference='Stop'; $raw = Get-Content -Raw -LiteralPath $env:DU_SELF; $m = [regex]::Match($raw, '(?ms)^# POWERSHELL_PAYLOAD_BEGIN\s*(.*?)^# POWERSHELL_PAYLOAD_END'); if (-not $m.Success) { throw 'Embedded PowerShell payload not found.' }; $script = [scriptblock]::Create($m.Groups[1].Value); & $script"

exit /b %errorlevel%

# POWERSHELL_PAYLOAD_BEGIN

$ErrorActionPreference = "Stop"

$script:SelfPath = $env:DU_SELF
$script:BaseDir = Split-Path -Parent $script:SelfPath
$script:LastResult = $null
$script:LogFile = $null

$script:PolicyFiles = @(
    [pscustomobject]@{
        Name = "Windows Driver Policy - Enforce"
        Guid = "8F9CB695-5D48-48D6-A329-7202B44607E3"
        File = "{8F9CB695-5D48-48D6-A329-7202B44607E3}.cip"
    },
    [pscustomobject]@{
        Name = "Windows Driver Policy - Audit/Evaluation"
        Guid = "784C4414-79F4-4C32-A6A5-F0FB42A51D0D"
        File = "{784C4414-79F4-4C32-A6A5-F0FB42A51D0D}.cip"
    }
)

function New-LogFile {
    $stamp = Get-Date -Format "yyyyMMdd-HHmmss"
    return Join-Path $script:BaseDir "Driver-Unblock-$stamp.log"
}

function Header {
    param([string]$Text)

    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host "  $Text" -ForegroundColor White
    Write-Host "============================================================" -ForegroundColor Cyan
}

function Line {
    Write-Host "------------------------------------------------------------" -ForegroundColor DarkGray
}

function Good {
    param([string]$Text)
    Write-Host "[OK] $Text" -ForegroundColor Green
}

function Warn {
    param([string]$Text)
    Write-Host "[!] $Text" -ForegroundColor Yellow
}

function Bad {
    param([string]$Text)
    Write-Host "[X] $Text" -ForegroundColor Red
}

function Info {
    param([string]$Text)
    Write-Host "[i] $Text" -ForegroundColor Cyan
}

function Pause-User {
    Write-Host ""
    Read-Host "Press Enter to continue" | Out-Null
}

function New-Result {
    param([string]$Mode)

    return @{
        Mode = $Mode
        ExitCode = 0
        Error = $null
        FoundCount = 0
        DeletedCount = 0
        CitoolActive = $false
        SecureBoot = $null
        SecureBootBlocked = $false
        VerifyClean = $false
    }
}

function Assert-Admin {
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($identity)

    if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        throw "Run this tool as Administrator."
    }
}

function Get-SecureBootState {
    try {
        return Confirm-SecureBootUEFI
    }
    catch {
        return $null
    }
}

function Show-BitLockerStatus {
    Info "Checking BitLocker / device encryption status..."

    try {
        $volume = Get-BitLockerVolume -MountPoint $env:SystemDrive -ErrorAction Stop

        Write-Host "    Drive: $($volume.MountPoint)"
        Write-Host "    ProtectionStatus: $($volume.ProtectionStatus)"
        Write-Host "    VolumeStatus: $($volume.VolumeStatus)"
        Write-Host "    EncryptionPercentage: $($volume.EncryptionPercentage)%"

        if ($volume.ProtectionStatus -eq "On") {
            Warn "BitLocker protection appears to be ON. Have your recovery key ready before changing Secure Boot."
        }
    }
    catch {
        Warn "Get-BitLockerVolume failed or is unavailable. Falling back to manage-bde."
        try {
            & manage-bde.exe -status $env:SystemDrive
        }
        catch {
            Warn "Could not read BitLocker status. You can manually check with: manage-bde -status"
        }
    }
}

function Get-FreeDriveLetter {
    foreach ($letter in @("S", "T", "U", "V", "W", "X", "Y", "Z")) {
        $root = "$letter`:\"
        if (-not (Test-Path $root)) {
            return "$letter`:"
        }
    }

    throw "No free drive letter found from S: to Z: for mounting the EFI System Partition."
}

function Mount-EfiPartition {
    $drive = Get-FreeDriveLetter

    Info "Mounting EFI System Partition to $drive ..."
    & mountvol.exe $drive /s | Out-Host

    if ($LASTEXITCODE -ne 0) {
        throw "mountvol failed while mounting EFI System Partition to $drive."
    }

    $root = "$drive\"

    if (-not (Test-Path $root)) {
        throw "EFI mount point $root is not accessible after mountvol."
    }

    return @{
        Drive = $drive
        Root = $root
    }
}

function Dismount-EfiPartition {
    param([string]$Drive)

    if ($Drive) {
        Info "Dismounting EFI System Partition from $Drive ..."
        & mountvol.exe $Drive /d | Out-Host
    }
}

function Check-CiToolPolicyStatus {
    $active = $false

    Info "Checking active policies with citool..."

    $ciTool = Get-Command "citool.exe" -ErrorAction SilentlyContinue
    if (-not $ciTool) {
        Warn "citool.exe was not found. File checks will still run."
        return $false
    }

    try {
        $jsonRaw = (& citool.exe -lp -json 2>$null) | Out-String
        $json = $jsonRaw | ConvertFrom-Json

        foreach ($policy in $script:PolicyFiles) {
            $match = $json.Policies | Where-Object {
                $_.PolicyID -ieq $policy.Guid
            }

            if ($match) {
                $active = $true
                Warn "$($policy.Name) is currently listed by citool. PolicyID: $($policy.Guid)"
                Write-Host "    IsEnforced:   $($match.IsEnforced)"
                Write-Host "    IsAuthorized: $($match.IsAuthorized)"
            }
            else {
                Good "$($policy.Name) is not listed by citool."
            }
        }
    }
    catch {
        Warn "Could not parse citool JSON output. Falling back to text check."

        $raw = (& citool.exe -lp 2>$null) | Out-String

        foreach ($policy in $script:PolicyFiles) {
            if ($raw -match [regex]::Escape($policy.Guid)) {
                $active = $true
                Warn "$($policy.Name) appears in citool output. PolicyID: $($policy.Guid)"
            }
            else {
                Good "$($policy.Name) is not listed by citool."
            }
        }
    }

    return $active
}

function Remove-PolicyFile {
    param(
        [Parameter(Mandatory)]
        [string]$Path,

        [Parameter(Mandatory)]
        [string]$LocationName,

        [Parameter(Mandatory)]
        [hashtable]$Result,

        [switch]$NeedsOwnership,

        [switch]$Apply
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        Good "Not present in $LocationName`: $Path"
        return
    }

    $Result.FoundCount++
    Warn "Found in $LocationName`: $Path"

    if (-not $Apply) {
        Write-Host "    Dry run only. No file was deleted."
        return
    }

    if ($NeedsOwnership) {
        Info "Taking ownership and granting Administrators full control..."
        & takeown.exe /f $Path | Out-Host
        & icacls.exe $Path /grant "*S-1-5-32-544:F" | Out-Host
    }

    Info "Deleting: $Path"
    Remove-Item -LiteralPath $Path -Force

    if (Test-Path -LiteralPath $Path) {
        throw "Delete failed or file still exists: $Path"
    }

    $Result.DeletedCount++
    Good "Deleted: $Path"
}

function Invoke-DriverUnblock {
    param([switch]$Apply)

    $result = New-Result -Mode $(if ($Apply) { "Apply removal" } else { "Check only" })
    $script:LastResult = $result

    Assert-Admin

    Write-Host ""
    Header "Driver Unblock"
    Write-Host ""

    $secureBoot = Get-SecureBootState
    $result.SecureBoot = $secureBoot

    if ($secureBoot -eq $true) {
        Warn "Secure Boot is ON."
        Warn "Secure Boot should be disabled before removing these signed CI policy files."

        if ($Apply) {
            Bad "Stopping because Apply was selected while Secure Boot is ON."
            $result.ExitCode = 2
            $result.SecureBootBlocked = $true
            return
        }
    }
    elseif ($secureBoot -eq $false) {
        Good "Secure Boot is OFF."
    }
    else {
        Warn "Secure Boot state could not be confirmed."
    }

    Show-BitLockerStatus
    Write-Host ""

    $result.CitoolActive = Check-CiToolPolicyStatus
    Write-Host ""

    $system32PolicyDir = Join-Path $env:windir "System32\CodeIntegrity\CiPolicies\Active"

    if (Test-Path -LiteralPath $system32PolicyDir) {
        Info "Checking Windows policy directory:"
        Write-Host "    $system32PolicyDir"

        foreach ($policy in $script:PolicyFiles) {
            $path = Join-Path $system32PolicyDir $policy.File
            Remove-PolicyFile -Path $path -LocationName "System32 CodeIntegrity" -NeedsOwnership -Apply:$Apply -Result $result
        }
    }
    else {
        Warn "System32 policy directory not found: $system32PolicyDir"
    }

    Write-Host ""

    $efiMount = $null

    try {
        $efiMount = Mount-EfiPartition
        $efiPolicyDir = Join-Path $efiMount.Root "EFI\Microsoft\Boot\CiPolicies\Active"

        if (Test-Path -LiteralPath $efiPolicyDir) {
            Info "Checking EFI policy directory:"
            Write-Host "    $efiPolicyDir"

            foreach ($policy in $script:PolicyFiles) {
                $path = Join-Path $efiPolicyDir $policy.File
                Remove-PolicyFile -Path $path -LocationName "EFI System Partition" -Apply:$Apply -Result $result
            }
        }
        else {
            Warn "EFI policy directory not found: $efiPolicyDir"
        }
    }
    finally {
        if ($efiMount) {
            Dismount-EfiPartition -Drive $efiMount.Drive
        }
    }

    Write-Host ""

    if ($Apply) {
        Good "Removal pass completed."
        Warn "Reboot is mandatory. The policy can remain loaded until the next boot."
    }
    else {
        Good "Check completed. No files were deleted."
    }
}

function Invoke-Verify {
    $result = New-Result -Mode "Verify after reboot"
    $script:LastResult = $result

    Write-Host ""
    Header "Driver Unblock - Verify"
    Write-Host ""

    $ciTool = Get-Command "citool.exe" -ErrorAction SilentlyContinue
    if (-not $ciTool) {
        Bad "citool.exe was not found."
        $result.ExitCode = 1
        $result.Error = "citool.exe was not found."
        return
    }

    Info 'Running: citool -lp'
    Write-Host ""

    $raw = (& citool.exe -lp 2>&1) | Out-String
    Write-Host $raw

    $found = $false

    foreach ($policy in $script:PolicyFiles) {
        if ($raw -match [regex]::Escape($policy.Guid)) {
            $found = $true
            Warn "$($policy.Name) is still visible in citool output."
        }
    }

    if ($found) {
        $result.VerifyClean = $false
        $result.CitoolActive = $true
        $result.ExitCode = 3
    }
    else {
        $result.VerifyClean = $true
        $result.CitoolActive = $false
        $result.ExitCode = 0
    }
}

function Run-LoggedAction {
    param(
        [string]$Mode,
        [scriptblock]$Action
    )

    $script:LogFile = New-LogFile
    $script:LastResult = $null

    Clear-Host
    Header "Driver Unblock - Developer Log"
    Write-Host ""
    Write-Host "Mode:"
    Write-Host "  $Mode"
    Write-Host ""
    Write-Host "Log file:"
    Write-Host "  $script:LogFile"
    Write-Host ""
    Line
    Write-Host "  Developer output starts here" -ForegroundColor Magenta
    Line
    Write-Host ""

    try {
        Start-Transcript -Path $script:LogFile -Force | Out-Null

        try {
            & $Action
        }
        catch {
            if (-not $script:LastResult) {
                $script:LastResult = New-Result -Mode $Mode
            }

            $script:LastResult.ExitCode = 1
            $script:LastResult.Error = $_.Exception.Message

            Bad $_.Exception.Message
        }
    }
    finally {
        try {
            Stop-Transcript | Out-Null
        }
        catch {
        }
    }

    Write-Host ""
    Line
    Write-Host "  Developer output ends here" -ForegroundColor Magenta
    Line

    return $script:LastResult
}

function Show-SummaryCheck {
    param([hashtable]$Result)

    Write-Host ""
    Header "Simple Result"

    if ($Result.Error) {
        Bad "The check did not finish successfully."
        Write-Host ""
        Write-Host "Reason:"
        Write-Host "  $($Result.Error)"
        return
    }

    if ($Result.FoundCount -gt 0) {
        Warn "Target Windows Driver Policy file found."
        Write-Host ""
        Write-Host "What this means:"
        Write-Host "  Your system still has a driver-blocking policy file."
        Write-Host ""
        Write-Host "Next step:"
        Write-Host "  You can continue directly with removal from the next screen."
        return
    }

    if ($Result.CitoolActive) {
        Warn "citool still shows a target policy as active."
        Write-Host ""
        Write-Host "But the script did not find the matching file."
        Write-Host ""
        Write-Host "Next step:"
        Write-Host "  Reboot once, then run Verify after reboot."
        return
    }

    Good "No target policy files were found."
    Write-Host ""
    Write-Host "What this means:"
    Write-Host "  The Driver Policy files are probably already removed."
    Write-Host ""
    Write-Host "Next step:"
    Write-Host "  Reboot if you recently removed them, then run Verify after reboot."
}

function Show-SummaryApply {
    param([hashtable]$Result)

    Write-Host ""
    Header "Simple Result"

    if ($Result.SecureBootBlocked) {
        Bad "Removal was stopped because Secure Boot is ON."
        Write-Host ""
        Write-Host "Next step:"
        Write-Host "  Disable Secure Boot in UEFI, then run Apply removal again."
        return
    }

    if ($Result.Error) {
        Bad "Removal did not finish successfully."
        Write-Host ""
        Write-Host "Reason:"
        Write-Host "  $($Result.Error)"
        return
    }

    if ($Result.DeletedCount -gt 0) {
        Good "Removal completed."
        Write-Host ""
        Warn "IMPORTANT: You must reboot now."
        Write-Host ""
        Write-Host "After reboot:"
        Write-Host "  1. Run this tool again"
        Write-Host "  2. Choose Verify after reboot"
        Write-Host "  3. If verification is clean, reconnect your device"
        Write-Host "  4. Re-enable Secure Boot if you disabled it"
        return
    }

    Warn "No target files were deleted."
    Write-Host ""
    Write-Host "What this usually means:"
    Write-Host "  They were already missing, or there was nothing to remove."
    Write-Host ""
    Write-Host "Next step:"
    Write-Host "  Reboot once, then choose Verify after reboot."
}

function Show-SummaryVerify {
    param([hashtable]$Result)

    Write-Host ""
    Header "Simple Result"

    if ($Result.Error) {
        Bad "Verification failed."
        Write-Host ""
        Write-Host "Reason:"
        Write-Host "  $($Result.Error)"
        return
    }

    if ($Result.VerifyClean) {
        Good "Clean."
        Write-Host ""
        Write-Host "What this means:"
        Write-Host "  The target Windows Driver Policy GUIDs were NOT found by citool."
        Write-Host ""
        Write-Host "Next step:"
        Write-Host "  Reconnect your blocked device/driver."
        Write-Host ""
        Write-Host "If it works:"
        Write-Host "  Re-enable Secure Boot in UEFI if you disabled it."
        return
    }

    Bad "The target policy still appears active."
    Write-Host ""
    Write-Host "What this means:"
    Write-Host "  Windows still sees one of the Driver Policy GUIDs."
    Write-Host ""
    Write-Host "Next step:"
    Write-Host "  If you have not rebooted yet, reboot now."
    Write-Host "  If you already rebooted, run Check only again."
}

function Apply-Flow {
    Clear-Host
    Header "Driver Unblock - Apply Removal"
    Write-Host ""
    Warn "WARNING"
    Write-Host ""
    Write-Host "This will delete ONLY these target Windows Driver Policy files if found:"
    Write-Host ""
    Write-Host "  8F9CB695-5D48-48D6-A329-7202B44607E3" -ForegroundColor Yellow
    Write-Host "  784C4414-79F4-4C32-A6A5-F0FB42A51D0D" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "Secure Boot should be OFF before doing this."
    Write-Host "If BitLocker is ON, you should have your recovery key ready."
    Write-Host ""

    $answer = Read-Host "Continue with removal? [Y/N]"

    if ($answer -notmatch "^[Yy]$") {
        return
    }

    $result = Run-LoggedAction -Mode "Apply removal" -Action {
        Invoke-DriverUnblock -Apply
    }

    Show-SummaryApply -Result $result
}

function Check-Flow {
    $result = Run-LoggedAction -Mode "Check only" -Action {
        Invoke-DriverUnblock
    }

    Show-SummaryCheck -Result $result

    $canApply = $false
    if ($result -and $result.FoundCount -gt 0 -and -not $result.Error) {
        $canApply = $true
    }

    Complete-EndScreen -CanApply:$canApply
}

function Verify-Flow {
    $result = Run-LoggedAction -Mode "Verify after reboot" -Action {
        Invoke-Verify
    }

    Show-SummaryVerify -Result $result
    Complete-EndScreen -CanApply:$false
}

function Complete-EndScreen {
    param([switch]$CanApply)

    while ($true) {
        Write-Host ""
        Header "Done"
        Write-Host ""
        Write-Host "Log saved here:"
        Write-Host "  $script:LogFile"
        Write-Host ""
        Line

        if ($CanApply) {
            Write-Host "  [A] Continue with removal" -ForegroundColor Yellow
            Write-Host "  [L] Open this folder"
            Write-Host "  [Q] Quit"
            Line
            Write-Host ""

            $choice = Read-Host "Select option"

            switch -Regex ($choice) {
                "^[Aa]$" {
                    Apply-Flow
                    $CanApply = $false
                    continue
                }
                "^[Ll]$" {
                    Start-Process $script:BaseDir
                    continue
                }
                "^[Qq]$" {
                    exit
                }
                default {
                    Warn "Invalid option."
                    continue
                }
            }
        }
        else {
            Write-Host "  [M] Back to menu"
            Write-Host "  [L] Open this folder"
            Write-Host "  [Q] Quit"
            Line
            Write-Host ""

            $choice = Read-Host "Select option"

            switch -Regex ($choice) {
                "^[Mm]$" {
                    return
                }
                "^[Ll]$" {
                    Start-Process $script:BaseDir
                    continue
                }
                "^[Qq]$" {
                    exit
                }
                default {
                    Warn "Invalid option."
                    continue
                }
            }
        }
    }
}

function Show-Menu {
    while ($true) {
        Clear-Host
        Header "Driver Unblock"
        Write-Host ""
        Write-Host "This tool checks/removes ONLY these Windows Driver Policy files:"
        Write-Host ""
        Write-Host "  8F9CB695-5D48-48D6-A329-7202B44607E3" -ForegroundColor Yellow
        Write-Host "  784C4414-79F4-4C32-A6A5-F0FB42A51D0D" -ForegroundColor Yellow
        Write-Host ""
        Good "It does NOT touch other .cip policy files."
        Write-Host ""
        Write-Host "Recommended order:" -ForegroundColor Cyan
        Write-Host ""
        Write-Host "  1. Check only"
        Write-Host "  2. If files are found, apply removal"
        Write-Host "  3. Reboot Windows"
        Write-Host "  4. Verify after reboot"
        Write-Host "  5. Re-enable Secure Boot if you disabled it"
        Write-Host ""
        Line
        Write-Host "  [1] Check only - safe, no changes"
        Write-Host "  [2] Apply removal - deletes only target policy files"
        Write-Host "  [3] Verify after reboot"
        Write-Host "  [4] Open this folder"
        Write-Host "  [Q] Quit"
        Line
        Write-Host ""

        $choice = Read-Host "Select option"

        switch -Regex ($choice) {
            "^1$" {
                Check-Flow
            }
            "^2$" {
                Apply-Flow
                Complete-EndScreen -CanApply:$false
            }
            "^3$" {
                Verify-Flow
            }
            "^4$" {
                Start-Process $script:BaseDir
            }
            "^[Qq]$" {
                exit
            }
            default {
                Warn "Invalid option."
                Start-Sleep -Seconds 1
            }
        }
    }
}

try {
    Show-Menu
}
catch {
    Write-Host ""
    Bad $_.Exception.Message
    Pause-User
}

# POWERSHELL_PAYLOAD_END