Tests/Test-Win32AppLifecycle.ps1
|
# IntuneWin32App Module - Comprehensive Function Test Suite # This script tests ALL public functions in the module through a complete lifecycle # DO NOT RUN IN PRODUCTION - THESE ARE TEST SCRIPTS ONLY # NOTE: This script has been replaced by Test-ComprehensiveFunctionality.ps1 # which provides complete testing of all 38 public functions. Write-Host "=== DEPRECATED ===" -ForegroundColor Yellow Write-Host "This test script has been replaced by Test-ComprehensiveFunctionality.ps1" -ForegroundColor Yellow Write-Host "The new script tests ALL 38 public functions through a complete lifecycle workflow." -ForegroundColor Yellow Write-Host "" Write-Host "Running the new comprehensive test..." -ForegroundColor Cyan Write-Host "" # Run the new comprehensive test $NewTestPath = Join-Path $PSScriptRoot "Test-ComprehensiveFunctionality.ps1" if (Test-Path $NewTestPath) { & $NewTestPath exit $LASTEXITCODE } else { Write-Error "Test-ComprehensiveFunctionality.ps1 not found" exit 1 } # Verify MSI files exist if (Test-Path $TestConfig.SourceFolder) { $InitialMSI = Join-Path $TestConfig.SourceFolder $TestConfig.SetupFile $UpdatedMSI = Join-Path $TestConfig.SourceFolder $TestConfig.UpdatedSetupFile if (-not (Test-Path $InitialMSI)) { Write-Warning "Initial setup file not found: $($InitialMSI)" } if (-not (Test-Path $UpdatedMSI)) { Write-Warning "Updated setup file not found: $($UpdatedMSI)" } Write-Host "Using setup files:" -ForegroundColor Cyan Write-Host " Initial: $($TestConfig.SetupFile)" -ForegroundColor Gray Write-Host " Updated: $($TestConfig.UpdatedSetupFile)" -ForegroundColor Gray } else { Write-Warning "Source folder not found: $($TestConfig.SourceFolder)" } # Test Results Tracking $TestResults = @{ Passed = 0 Failed = 0 Details = @() } function Write-TestResult { param( [string]$TestName, [bool]$Passed, [string]$Details = "" ) if ($Passed) { $TestResults.Passed++ $Status = "PASSED" $Color = "Green" } else { $TestResults.Failed++ $Status = "FAILED" $Color = "Red" } $Result = @{ TestName = $TestName Status = $Status Details = $Details Timestamp = Get-Date } $TestResults.Details += $Result Write-Host "[$Status] $TestName" -ForegroundColor $Color if ($Details) { Write-Host " -> $Details" -ForegroundColor Gray } } #endregion Write-Host "=== Win32 App Lifecycle Tests ===" -ForegroundColor Cyan Write-Host "Testing: Package, Add, Update, Remove workflow" -ForegroundColor Yellow Write-Host "" #region Prerequisites Write-Host "Checking prerequisites..." -ForegroundColor Yellow # Module Import try { # Remove module if already loaded to ensure fresh import if (Get-Module IntuneWin32App) { Remove-Module IntuneWin32App -Force } # Import from local path to ensure we get the latest changes $ModulePath = Split-Path $PSScriptRoot -Parent Import-Module (Join-Path $ModulePath "IntuneWin32App.psd1") -Force -Verbose:$false Write-TestResult -TestName "Module Import" -Passed $true } catch { Write-TestResult -TestName "Module Import" -Passed $false -Details $_.Exception.Message exit 1 } # File Prerequisites $PrereqTests = @( @{ Path = $TestConfig.SourceFolder; Name = "Source Folder" } ) # Test both setup files $PrereqTests += @{ Path = Join-Path $TestConfig.SourceFolder $TestConfig.SetupFile; Name = "Initial Setup File" } $PrereqTests += @{ Path = Join-Path $TestConfig.SourceFolder $TestConfig.UpdatedSetupFile; Name = "Updated Setup File" } $PrereqTests += @{ Path = $TestConfig.OutputFolder; Name = "Output Folder" } # Icon is optional - only test if path is configured if ($TestConfig.IconPath) { $PrereqTests += @{ Path = $TestConfig.IconPath; Name = "Icon File" } } foreach ($PrereqTest in $PrereqTests) { if (Test-Path $PrereqTest.Path) { Write-TestResult -TestName "Prerequisite: $($PrereqTest.Name)" -Passed $true } else { Write-TestResult -TestName "Prerequisite: $($PrereqTest.Name)" -Passed $false -Details "Path not found: $($PrereqTest.Path)" exit 1 } } #endregion #region Authentication Write-Host "\n=== Authentication ===" -ForegroundColor Cyan try { Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Yellow $AuthResult = Connect-MSIntuneGraph -TenantID $TestConfig.TenantID -ClientID $TestConfig.ClientID -Interactive if ($AuthResult -and $Global:AuthenticationHeader) { Write-TestResult -TestName "Graph Authentication" -Passed $true -Details "Token acquired successfully" # Display token information for diagnostics if ($Global:AccessToken) { Write-Host "Token Scopes: $($Global:AccessToken.Scopes -join ', ')" -ForegroundColor Cyan Write-Host "Token Expires: $($Global:AccessToken.ExpiresOn)" -ForegroundColor Cyan # Store initial token for refresh testing $InitialAccessToken = $Global:AccessToken.AccessToken $InitialExpiresOn = $Global:AccessToken.ExpiresOn # Check if refresh token is available if ($Global:AccessToken.PSObject.Properties["RefreshToken"] -and -not [string]::IsNullOrEmpty($Global:AccessToken.RefreshToken)) { Write-Host "Refresh Token: Available (stored for silent renewal)" -ForegroundColor Cyan $RefreshTokenAvailable = $true } else { Write-Host "Refresh Token: Not available" -ForegroundColor Yellow $RefreshTokenAvailable = $false } } # Validate token $TokenValid = Test-AccessToken if ($TokenValid) { Write-TestResult -TestName "Access Token Validation" -Passed $true # Decode and display token claims for diagnostics try { Write-Host "`nDecoding Access Token..." -ForegroundColor Yellow $TokenParts = $Global:AccessToken.AccessToken.Split('.') $TokenPayload = $TokenParts[1] # Add padding if needed for Base64 decoding while ($TokenPayload.Length % 4) { $TokenPayload += '=' } $DecodedBytes = [System.Convert]::FromBase64String($TokenPayload) $DecodedToken = [System.Text.Encoding]::UTF8.GetString($DecodedBytes) | ConvertFrom-Json Write-Host "Token Claims:" -ForegroundColor Cyan Write-Host " User (upn): $($DecodedToken.upn)" -ForegroundColor Gray Write-Host " App ID (appid): $($DecodedToken.appid)" -ForegroundColor Gray Write-Host " Audience (aud): $($DecodedToken.aud)" -ForegroundColor Gray Write-Host " Issuer (iss): $($DecodedToken.iss)" -ForegroundColor Gray Write-Host " Scopes (scp): $($DecodedToken.scp)" -ForegroundColor Gray Write-Host " Roles: $($DecodedToken.roles -join ', ')" -ForegroundColor Gray Write-Host " Token Version (ver): $($DecodedToken.ver)" -ForegroundColor Gray Write-Host " Expires (exp): $(([System.DateTimeOffset]::FromUnixTimeSeconds($DecodedToken.exp)).LocalDateTime)" -ForegroundColor Gray } catch { Write-Warning "Failed to decode token: $_" } # Test token refresh if refresh token is available if ($RefreshTokenAvailable) { Write-Host "`nTesting Token Refresh..." -ForegroundColor Yellow try { # Use -Refresh parameter to trigger silent token refresh Write-Host "Attempting silent token refresh with -Refresh parameter..." -ForegroundColor Gray $RefreshResult = Connect-MSIntuneGraph -TenantID $TestConfig.TenantID -ClientID $TestConfig.ClientID -Refresh if ($RefreshResult -and $Global:AccessToken.AccessToken -ne $InitialAccessToken) { Write-TestResult -TestName "Token Refresh (Silent)" -Passed $true -Details "New token obtained via refresh token" Write-Host " New Token Expires: $($Global:AccessToken.ExpiresOn)" -ForegroundColor Cyan # Validate the refreshed token $RefreshedTokenValid = Test-AccessToken if ($RefreshedTokenValid) { Write-TestResult -TestName "Refreshed Token Validation" -Passed $true } else { Write-TestResult -TestName "Refreshed Token Validation" -Passed $false -Details "Refreshed token is invalid" exit 1 } } elseif ($RefreshResult -and $Global:AccessToken.AccessToken -eq $InitialAccessToken) { Write-TestResult -TestName "Token Refresh (Silent)" -Passed $true -Details "Token still valid, refresh not needed" } else { Write-TestResult -TestName "Token Refresh (Silent)" -Passed $false -Details "Refresh failed" } } catch { Write-TestResult -TestName "Token Refresh (Silent)" -Passed $false -Details $_.Exception.Message } } else { Write-Host "Skipping token refresh test - no refresh token available" -ForegroundColor Yellow } } else { Write-TestResult -TestName "Access Token Validation" -Passed $false -Details "Token is invalid or expired" exit 1 } } else { Write-TestResult -TestName "Graph Authentication" -Passed $false -Details "Authentication failed - no token or header created" Write-Host "AuthResult: $($AuthResult -ne $null)" -ForegroundColor Yellow Write-Host "Global:AuthenticationHeader: $($Global:AuthenticationHeader -ne $null)" -ForegroundColor Yellow exit 1 } } catch { Write-TestResult -TestName "Graph Authentication" -Passed $false -Details $_.Exception.Message exit 1 } #endregion #region Phase 1: Package Creation Write-Host "`n=== Phase 1: Package Creation ===" -ForegroundColor Cyan try { Write-Host "Creating Win32 app package..." -ForegroundColor Yellow $PackageResult = New-IntuneWin32AppPackage -SourceFolder $TestConfig.SourceFolder -SetupFile $TestConfig.SetupFile -OutputFolder $TestConfig.OutputFolder -Force -InformationAction SilentlyContinue if ($PackageResult -and (Test-Path $PackageResult.Path)) { $TestConfig.PackagePath = $PackageResult.Path Write-TestResult -TestName "Package Creation" -Passed $true -Details "Package: $($PackageResult.Name)" } else { Write-TestResult -TestName "Package Creation" -Passed $false -Details "Package creation failed" exit 1 } } catch { Write-TestResult -TestName "Package Creation" -Passed $false -Details $_.Exception.Message exit 1 } # Extract package metadata try { $PackageMetadata = Get-IntuneWin32AppMetaData -FilePath $TestConfig.PackagePath if ($PackageMetadata) { Write-TestResult -TestName "Package Metadata Extraction" -Passed $true -Details "App: $($PackageMetadata.ApplicationInfo.Name)" } else { Write-TestResult -TestName "Package Metadata Extraction" -Passed $false exit 1 } } catch { Write-TestResult -TestName "Package Metadata Extraction" -Passed $false -Details $_.Exception.Message exit 1 } #endregion #region Phase 2: App Creation Write-Host "`n=== Phase 2: App Creation ===" -ForegroundColor Cyan # Verify token is still valid (automatic refresh should happen if needed) Write-Host "Verifying token status before app creation..." -ForegroundColor Yellow $TokenValid = Test-AccessToken if ($TokenValid) { Write-Host "Token Status: Valid" -ForegroundColor Green } else { Write-Host "Token Status: Expired or near expiration - automatic refresh will occur" -ForegroundColor Yellow } # Create app components try { # Icon $Icon = New-IntuneWin32AppIcon -FilePath $TestConfig.IconPath Write-TestResult -TestName "Icon Creation" -Passed ($Icon -ne $null) -Details "Icon data prepared" # Detection Rule $DetectionRule = New-IntuneWin32AppDetectionRuleMSI -ProductCode $PackageMetadata.ApplicationInfo.MsiInfo.MsiProductCode -ProductVersionOperator "greaterThanOrEqual" -ProductVersion $PackageMetadata.ApplicationInfo.MsiInfo.MsiProductVersion Write-TestResult -TestName "Detection Rule Creation" -Passed ($DetectionRule -ne $null) -Details "MSI detection rule" # Requirement Rule (with ARM64 support) $RequirementRule = New-IntuneWin32AppRequirementRule -Architecture "AllWithARM64" -MinimumSupportedWindowsRelease "W10_22H2" Write-TestResult -TestName "Requirement Rule Creation" -Passed ($RequirementRule -ne $null) -Details "All architectures supported" # Return Code $ReturnCode = New-IntuneWin32AppReturnCode -ReturnCode 1337 -Type "retry" Write-TestResult -TestName "Return Code Creation" -Passed ($ReturnCode -ne $null) -Details "Custom return code: 1337" } catch { Write-TestResult -TestName "App Components Creation" -Passed $false -Details $_.Exception.Message exit 1 } # Test Graph API connectivity before creating app try { Write-Host "Testing Graph API connectivity..." -ForegroundColor Yellow $TestQuery = Get-IntuneWin32App -DisplayName "NonExistentAppForTesting12345" -ErrorAction SilentlyContinue Write-TestResult -TestName "Graph API Connectivity" -Passed $true -Details "Successfully queried Graph API" } catch { Write-TestResult -TestName "Graph API Connectivity" -Passed $false -Details $_.Exception.Message Write-Host "ERROR: Cannot connect to Graph API. Please verify:" -ForegroundColor Red Write-Host " 1. App registration has 'DeviceManagementApps.ReadWrite.All' permission" -ForegroundColor Yellow Write-Host " 2. Admin consent has been granted" -ForegroundColor Yellow Write-Host " 3. Token is not expired (check Test-AccessToken output above)" -ForegroundColor Yellow exit 1 } # Create the app try { Write-Host "Creating Win32 app in Intune..." -ForegroundColor Yellow $CreatedApp = Add-IntuneWin32App -FilePath $TestConfig.PackagePath -DisplayName $TestConfig.TestAppDisplayName -Description $TestConfig.TestAppDescription -Publisher $TestConfig.TestAppPublisher -AppVersion $TestConfig.TestAppVersion -InstallExperience "system" -RestartBehavior "suppress" -DetectionRule $DetectionRule -RequirementRule $RequirementRule -Icon $Icon -ReturnCode $ReturnCode -Verbose if ($CreatedApp -and $CreatedApp.id) { $TestConfig.CreatedAppID = $CreatedApp.id Write-TestResult -TestName "App Creation" -Passed $true -Details "App ID: $($CreatedApp.id)" } else { Write-TestResult -TestName "App Creation" -Passed $false -Details "No app returned" exit 1 } } catch { Write-TestResult -TestName "App Creation" -Passed $false -Details $_.Exception.Message exit 1 } # Verify app creation try { Start-Sleep -Seconds 10 # Allow time for app to be processed $RetrievedApp = Get-IntuneWin32App -ID $TestConfig.CreatedAppID if ($RetrievedApp -and $RetrievedApp.displayName -eq $TestConfig.TestAppDisplayName) { Write-TestResult -TestName "App Verification" -Passed $true -Details "App successfully created and retrieved" } else { Write-TestResult -TestName "App Verification" -Passed $false -Details "Could not retrieve created app" } } catch { Write-TestResult -TestName "App Verification" -Passed $false -Details $_.Exception.Message } #endregion #region Phase 3: App Update Write-Host "`n=== Phase 3: App Update ===" -ForegroundColor Cyan # Verify token is still valid (automatic refresh should happen if needed) Write-Host "Verifying token status before app update..." -ForegroundColor Yellow $TokenValid = Test-AccessToken if ($TokenValid) { Write-Host "Token Status: Valid" -ForegroundColor Green } else { Write-Host "Token Status: Expired or near expiration - automatic refresh will occur" -ForegroundColor Yellow } # Create updated package with different MSI file try { Write-Host "Creating updated package with $($TestConfig.UpdatedSetupFile)..." -ForegroundColor Yellow $UpdatedPackageResult = New-IntuneWin32AppPackage -SourceFolder $TestConfig.SourceFolder -SetupFile $TestConfig.UpdatedSetupFile -OutputFolder $TestConfig.OutputFolder -Force -InformationAction SilentlyContinue if ($UpdatedPackageResult -and (Test-Path $UpdatedPackageResult.Path)) { $TestConfig.UpdatedPackagePath = $UpdatedPackageResult.Path Write-TestResult -TestName "Updated Package Creation" -Passed $true -Details "Updated package: $($TestConfig.UpdatedSetupFile)" } else { Write-TestResult -TestName "Updated Package Creation" -Passed $false -Details "Updated package creation failed" } } catch { Write-TestResult -TestName "Updated Package Creation" -Passed $false -Details $_.Exception.Message } # Update app properties if ($TestConfig.CreatedAppID) { try { Write-Host "Updating app properties..." -ForegroundColor Yellow # Update app metadata $UpdateResult = Set-IntuneWin32App -ID $TestConfig.CreatedAppID -AppVersion $TestConfig.UpdatedVersion -Description $TestConfig.UpdatedDescription -Verbose if ($UpdateResult -ne $null) { Write-TestResult -TestName "App Properties Update" -Passed $true -Details "Version and description updated" # Verify update Start-Sleep -Seconds 5 $UpdatedApp = Get-IntuneWin32App -ID $TestConfig.CreatedAppID if ($UpdatedApp.description -eq $TestConfig.UpdatedDescription) { Write-TestResult -TestName "App Update Verification" -Passed $true -Details "Updates applied successfully" } else { Write-TestResult -TestName "App Update Verification" -Passed $false -Details "Updates not reflected (Expected: '$($TestConfig.UpdatedDescription)', Got: '$($UpdatedApp.description)')" } } else { Write-TestResult -TestName "App Properties Update" -Passed $false -Details "Update operation returned null" } } catch { Write-TestResult -TestName "App Properties Update" -Passed $false -Details $_.Exception.Message } } # Update package content if ($TestConfig.CreatedAppID -and $TestConfig.UpdatedPackagePath) { # Only attempt content update if we have a different package file if ($TestConfig.UpdatedPackagePath -ne $TestConfig.PackagePath) { try { Write-Host "Updating package content..." -ForegroundColor Yellow $ContentUpdateResult = Update-IntuneWin32AppPackageFile -ID $TestConfig.CreatedAppID -FilePath $TestConfig.UpdatedPackagePath -Verbose if ($ContentUpdateResult) { Write-TestResult -TestName "Package Content Update" -Passed $true -Details "Package content updated" } else { Write-TestResult -TestName "Package Content Update" -Passed $false -Details "Content update returned null" } } catch { Write-TestResult -TestName "Package Content Update" -Passed $false -Details $_.Exception.Message } } else { Write-TestResult -TestName "Package Content Update" -Passed $true -Details "Skipped - same package file (cannot update with identical content)" } } #endregion #region Phase 4: Assignment Testing Write-Host "`n=== Phase 4: Assignment Testing ===" -ForegroundColor Cyan # Verify token is still valid (automatic refresh should happen if needed) Write-Host "Verifying token status before assignment testing..." -ForegroundColor Yellow $TokenValid = Test-AccessToken if ($TokenValid) { Write-Host "Token Status: Valid" -ForegroundColor Green } else { Write-Host "Token Status: Expired or near expiration - automatic refresh will occur" -ForegroundColor Yellow } if ($TestConfig.CreatedAppID) { # Test different assignment types try { # All Users - Available Write-Host "Creating All Users assignment..." -ForegroundColor Yellow $AllUsersAssignment = Add-IntuneWin32AppAssignmentAllUsers -ID $TestConfig.CreatedAppID -Intent "available" -Notification "showAll" Write-TestResult -TestName "All Users Assignment" -Passed ($AllUsersAssignment -ne $null) -Details "Available intent" Start-Sleep -Seconds 3 # All Devices - Required Write-Host "Creating All Devices assignment..." -ForegroundColor Yellow $AllDevicesAssignment = Add-IntuneWin32AppAssignmentAllDevices -ID $TestConfig.CreatedAppID -Intent "required" -Notification "showReboot" Write-TestResult -TestName "All Devices Assignment" -Passed ($AllDevicesAssignment -ne $null) -Details "Required intent" # Wait for Graph API to propagate assignments Write-Host "Waiting for assignments to propagate in Graph API..." -ForegroundColor Yellow Start-Sleep -Seconds 10 # Verify assignments with retry logic $MaxRetries = 3 $RetryCount = 0 $Assignments = $null while ($RetryCount -lt $MaxRetries) { $Assignments = Get-IntuneWin32AppAssignment -ID $TestConfig.CreatedAppID if ($Assignments -and $Assignments.Count -ge 2) { break } $RetryCount++ if ($RetryCount -lt $MaxRetries) { Write-Host "Assignment count: $($Assignments.Count), retrying in 5 seconds... (Attempt $($RetryCount + 1)/$($MaxRetries))" -ForegroundColor Yellow Start-Sleep -Seconds 5 } } Write-TestResult -TestName "Assignment Verification" -Passed ($Assignments.Count -ge 2) -Details "Found $($Assignments.Count) assignment(s) after $($RetryCount + 1) attempt(s)" } catch { Write-TestResult -TestName "Assignment Testing" -Passed $false -Details $_.Exception.Message } } #endregion #region Phase 5: Cleanup (Removal) Write-Host "`n=== Phase 5: Cleanup and Removal ===" -ForegroundColor Cyan # Verify token is still valid (automatic refresh should happen if needed) Write-Host "Verifying token status before cleanup..." -ForegroundColor Yellow $TokenValid = Test-AccessToken if ($TokenValid) { Write-Host "Token Status: Valid" -ForegroundColor Green } else { Write-Host "Token Status: Expired or near expiration - automatic refresh will occur" -ForegroundColor Yellow } if ($TestConfig.CreatedAppID) { try { # Remove assignments first Write-Host "Removing assignments..." -ForegroundColor Yellow Remove-IntuneWin32AppAssignmentAllUsers -ID $TestConfig.CreatedAppID -Verbose Start-Sleep -Seconds 2 Remove-IntuneWin32AppAssignmentAllDevices -ID $TestConfig.CreatedAppID -Verbose Write-TestResult -TestName "Assignment Removal" -Passed $true -Details "All assignments removed" Start-Sleep -Seconds 5 # Remove the app Write-Host "Removing test app..." -ForegroundColor Yellow Remove-IntuneWin32App -ID $TestConfig.CreatedAppID -Verbose Write-TestResult -TestName "App Removal" -Passed $true -Details "App deletion initiated" # Verify removal Start-Sleep -Seconds 10 try { $RemovedApp = Get-IntuneWin32App -ID $TestConfig.CreatedAppID -ErrorAction Stop if ($RemovedApp -eq $null) { Write-TestResult -TestName "App Removal Verification" -Passed $true -Details "App successfully removed" } else { Write-TestResult -TestName "App Removal Verification" -Passed $false -Details "App still exists" } } catch { # If we get an error querying for the app, it likely means it was removed Write-TestResult -TestName "App Removal Verification" -Passed $true -Details "App successfully removed (not found in tenant)" } } catch { Write-TestResult -TestName "App Removal" -Passed $false -Details $_.Exception.Message } } # Clean up package files $PackageFiles = @($TestConfig.PackagePath, $TestConfig.UpdatedPackagePath) | Where-Object { $_ -and (Test-Path $_) } foreach ($PackageFile in $PackageFiles) { try { Remove-Item -Path $PackageFile -Force -ErrorAction Stop Write-TestResult -TestName "Package Cleanup" -Passed (-not(Test-Path $PackageFile)) -Details "Removed: $(Split-Path $PackageFile -Leaf)" } catch { Write-TestResult -TestName "Package Cleanup" -Passed $false -Details "Failed to remove: $(Split-Path $PackageFile -Leaf) - $($_.Exception.Message)" } } #endregion #region Results Summary Write-Host "`n=== Lifecycle Test Summary ===" -ForegroundColor Cyan $TotalTests = $TestResults.Passed + $TestResults.Failed $SuccessRate = if ($TotalTests -gt 0) { [math]::Round(($TestResults.Passed / $TotalTests) * 100, 2) } else { 0 } Write-Host "Phases Completed:" -ForegroundColor White Write-Host " [OK] Authentication with Token Refresh Support" -ForegroundColor Green Write-Host " [OK] Package Creation and Metadata" -ForegroundColor Green Write-Host " [OK] App Creation with Components" -ForegroundColor Green Write-Host " [OK] App Updates (Properties and Content)" -ForegroundColor Green Write-Host " [OK] Assignment Management" -ForegroundColor Green Write-Host " [OK] Cleanup and Removal" -ForegroundColor Green Write-Host "" Write-Host "Test Results:" -ForegroundColor White Write-Host " Passed: $($TestResults.Passed)" -ForegroundColor Green Write-Host " Failed: $($TestResults.Failed)" -ForegroundColor Red Write-Host " Success Rate: $SuccessRate%" -ForegroundColor $( if($SuccessRate -gt 90) { "Green" } elseif($SuccessRate -gt 70) { "Yellow" } else { "Red" } ) # Export detailed results $DetailedResults = @{ TestSuite = "Win32 App Lifecycle" Summary = @{ Passed = $TestResults.Passed Failed = $TestResults.Failed SuccessRate = $SuccessRate Timestamp = Get-Date } TestConfig = $TestConfig Details = $TestResults.Details } $ResultsPath = Join-Path $TestConfig.OutputFolder "Win32AppLifecycle_TestResults_$(Get-Date -Format "yyyyMMdd_HHmmss").json" try { $DetailedResults | ConvertTo-Json -Depth 10 | Out-File -FilePath $ResultsPath -Encoding UTF8 Write-Host "`nDetailed results: $ResultsPath" -ForegroundColor Cyan } catch { Write-Warning "Could not export detailed results: $_" } if ($TestResults.Failed -gt 0) { Write-Host "`nFailed Tests:" -ForegroundColor Red $TestResults.Details | Where-Object { $_.Status -eq "FAILED" } | ForEach-Object { Write-Host " - $($_.TestName): $($_.Details)" -ForegroundColor Red } exit 1 } else { Write-Host "`n[SUCCESS] Complete lifecycle validation successful!" -ForegroundColor Green exit 0 } #endregion |