Tests/Test-CertificateAuthentication.ps1

# Test Certificate-Based Authentication
# This script tests certificate authentication and validates the global variables are set correctly

param(
    [parameter(Mandatory = $true)]
    [string]$TenantID,
    
    [parameter(Mandatory = $true)]
    [string]$ClientID,
    
    [parameter(Mandatory = $true)]
    [string]$CertificateThumbprint
)

Write-Host "`n=== Certificate Authentication Test ===" -ForegroundColor Cyan

# Import the module
$ModulePath = Join-Path -Path $PSScriptRoot -ChildPath "..\IntuneWin32App.psd1"
Import-Module $ModulePath -Force -Verbose:$false
Write-Host "[OK] Module imported" -ForegroundColor Green

# Get the certificate
Write-Host "`nStep 1: Loading certificate..." -ForegroundColor Yellow
$Certificate = Get-ChildItem -Path "Cert:\CurrentUser\My\$CertificateThumbprint" -ErrorAction SilentlyContinue

if ($null -eq $Certificate) {
    Write-Host "[FAIL] Certificate not found with thumbprint: $CertificateThumbprint" -ForegroundColor Red
    Write-Host "Available certificates:" -ForegroundColor Yellow
    Get-ChildItem -Path "Cert:\CurrentUser\My" | Select-Object Subject, Thumbprint, NotAfter | Format-Table -AutoSize
    exit 1
}

Write-Host "[OK] Certificate found" -ForegroundColor Green
Write-Host " Subject: $($Certificate.Subject)" -ForegroundColor Gray
Write-Host " Thumbprint: $($Certificate.Thumbprint)" -ForegroundColor Gray
Write-Host " Valid Until: $($Certificate.NotAfter)" -ForegroundColor Gray

# Verify certificate has private key
if (-not $Certificate.HasPrivateKey) {
    Write-Host "[FAIL] Certificate does not have a private key" -ForegroundColor Red
    exit 1
}
Write-Host "[OK] Certificate has private key" -ForegroundColor Green

# Clear any existing global variables
Write-Host "`nStep 2: Clearing existing authentication..." -ForegroundColor Yellow
Remove-Variable -Name "AccessToken" -Scope Global -ErrorAction SilentlyContinue
Remove-Variable -Name "AuthenticationHeader" -Scope Global -ErrorAction SilentlyContinue
Remove-Variable -Name "AccessTokenTenantID" -Scope Global -ErrorAction SilentlyContinue
Write-Host "[OK] Global variables cleared" -ForegroundColor Green

# Connect using certificate
Write-Host "`nStep 3: Connecting with certificate..." -ForegroundColor Yellow
try {
    $Result = Connect-MSIntuneGraph -TenantID $TenantID -ClientID $ClientID -ClientCert $Certificate -Verbose
    Write-Host "[OK] Connect-MSIntuneGraph completed" -ForegroundColor Green
}
catch {
    Write-Host "[FAIL] Connection failed: $($_.Exception.Message)" -ForegroundColor Red
    exit 1
}

# Validate global variables
Write-Host "`nStep 4: Validating global variables..." -ForegroundColor Yellow

# Check $Global:AccessToken
if ($null -eq $Global:AccessToken) {
    Write-Host "[FAIL] Global:AccessToken is null" -ForegroundColor Red
    exit 1
}
Write-Host "[OK] Global:AccessToken exists" -ForegroundColor Green

# Check AccessToken property
if ([string]::IsNullOrEmpty($Global:AccessToken.AccessToken)) {
    Write-Host "[FAIL] Global:AccessToken.AccessToken is empty" -ForegroundColor Red
    exit 1
}
Write-Host "[OK] Global:AccessToken.AccessToken exists" -ForegroundColor Green
Write-Host " Token (first 50 chars): $($Global:AccessToken.AccessToken.Substring(0, 50))..." -ForegroundColor Gray

# Check ExpiresOn property
if ($Global:AccessToken.PSObject.Properties["ExpiresOn"]) {
    Write-Host "[OK] Global:AccessToken.ExpiresOn exists" -ForegroundColor Green
    Write-Host " Expires: $($Global:AccessToken.ExpiresOn)" -ForegroundColor Gray
}
else {
    Write-Host "[WARN] Global:AccessToken.ExpiresOn is missing" -ForegroundColor Yellow
}

# Check RefreshToken property (should NOT exist for certificate auth)
if ($Global:AccessToken.PSObject.Properties["RefreshToken"]) {
    Write-Host "[INFO] Global:AccessToken.RefreshToken exists (unexpected for cert auth)" -ForegroundColor Yellow
}
else {
    Write-Host "[OK] Global:AccessToken.RefreshToken not present (expected for cert auth)" -ForegroundColor Green
}

# Check $Global:AuthenticationHeader
if ($null -eq $Global:AuthenticationHeader) {
    Write-Host "[FAIL] Global:AuthenticationHeader is null" -ForegroundColor Red
    exit 1
}
Write-Host "[OK] Global:AuthenticationHeader exists" -ForegroundColor Green

# Check Authorization header
if ($Global:AuthenticationHeader.ContainsKey("Authorization")) {
    Write-Host "[OK] Authorization header exists" -ForegroundColor Green
    $AuthHeader = $Global:AuthenticationHeader["Authorization"]
    if ($AuthHeader -match "^Bearer ") {
        Write-Host "[OK] Authorization header has Bearer token" -ForegroundColor Green
    }
    else {
        Write-Host "[FAIL] Authorization header does not start with 'Bearer '" -ForegroundColor Red
    }
}
else {
    Write-Host "[FAIL] Authorization header missing" -ForegroundColor Red
    exit 1
}

# Check $Global:AccessTokenTenantID
if ($null -eq $Global:AccessTokenTenantID) {
    Write-Host "[WARN] Global:AccessTokenTenantID is null" -ForegroundColor Yellow
}
else {
    Write-Host "[OK] Global:AccessTokenTenantID exists: $Global:AccessTokenTenantID" -ForegroundColor Green
}

# Test Graph API call
Write-Host "`nStep 5: Testing Graph API call..." -ForegroundColor Yellow
try {
    $Apps = Get-IntuneWin32App -Verbose
    if ($null -ne $Apps) {
        Write-Host "[OK] Successfully retrieved Win32 apps" -ForegroundColor Green
        Write-Host " Total apps found: $(($Apps | Measure-Object).Count)" -ForegroundColor Gray
    }
    else {
        Write-Host "[INFO] No Win32 apps found in tenant (this is OK if tenant is empty)" -ForegroundColor Yellow
    }
}
catch {
    Write-Host "[FAIL] Graph API call failed: $($_.Exception.Message)" -ForegroundColor Red
    Write-Host "`nDiagnostic Information:" -ForegroundColor Yellow
    Write-Host " Check that the Entra ID app has APPLICATION permissions (not delegated):" -ForegroundColor Gray
    Write-Host " - DeviceManagementApps.ReadWrite.All (Application)" -ForegroundColor Gray
    Write-Host " - DeviceManagementConfiguration.ReadWrite.All (Application)" -ForegroundColor Gray
    Write-Host " - DeviceManagementRBAC.Read.All (Application)" -ForegroundColor Gray
    Write-Host " - Group.Read.All (Application)" -ForegroundColor Gray
    Write-Host " Ensure admin consent has been granted" -ForegroundColor Gray
    Write-Host " Certificate must be uploaded to the app registration" -ForegroundColor Gray
    exit 1
}

Write-Host "`n=== All Tests Passed ===" -ForegroundColor Green
Write-Host "Certificate authentication is working correctly" -ForegroundColor Green