Public/Invoke-GSAClientConnectivityCheck.ps1
|
# # Function: Invoke-GSAClientConnectivityCheck # Public function for the GSA client diagnostics toolkit. # function Invoke-GSAClientConnectivityCheck { <# .SYNOPSIS Runs all GSA Client connectivity, proxy, health probe, and mTLS checks. .DESCRIPTION Executes the full diagnostic suite: 1. GSA Service status 2. Device Entra join/registration status 3. GSA Primary Refresh Token status 4. GSA Forwarding Profile registry contents 5. GSA Forwarding Profile timestamp/freshness 6. Basic internet connectivity 7. Proxy detection (transparent/authenticating proxy via HTTP headers/407 response) 8. GSA Secure DNS status 9. GSA IPv6 status 10. DNS resolution for each FQDN 11. Tenant Internet DNS Resolution detection 12. Entra ID connectivity 13. TLS connectivity to each FQDN 14. mTLS connectivity to each FQDN 15. DiagnosticUri connectivity 16. GSA synthetic routes 17. GSA private DNS resolver 18. GSA event log .PARAMETER LogLevel Verbosity of logging output. Valid values: ERROR, WARNING, INFO, DEBUG, SUCCESS. .PARAMETER BasePath Directory for the log file. Defaults to the current working directory. .PARAMETER LogFileName Name of the log file. Defaults to GSAClientDiagnosticsToolkit.log. .EXAMPLE Invoke-GSAClientConnectivityCheck -LogLevel DEBUG .EXAMPLE Invoke-GSAClientConnectivityCheck -LogLevel ERROR -BasePath C:\Logs #> [CmdletBinding()] param ( [ValidateSet("ERROR", "WARNING", "INFO", "DEBUG", "SUCCESS")] [string]$LogLevel = "INFO", [string]$BasePath = (Get-Location), [string]$LogFileName = "GSAClientDiagnosticsToolkit.log" ) # Initialize module-level logging state $script:LogLevel = $LogLevel try { if (-Not (Test-Path $BasePath)) { New-Item -ItemType Directory -Path $BasePath -Force | Out-Null } } catch { Write-Log -Message "Failed to create directory at path: $BasePath. Error: $($_.Exception.Message)" -Level "ERROR" throw } # Resolve to an absolute path so the log location does not depend on the current working directory $BasePath = (Resolve-Path -Path $BasePath).ProviderPath $script:LogFilePath = Join-Path -Path $BasePath -ChildPath $LogFileName # Initialize the test result counters and storage. $testsPassed = 0 $testsFailed = 0 $testsWithWarnings = 0 $testResults = @{} # Log the start of the connectivity check. Write-Log "========= GSA Client Connectivity Checker v. $script:ModuleVer Started =========" Write-Log "Log file : $script:LogFilePath" Write-Log "Device Name : $env:COMPUTERNAME" Write-Log "User Account: $(Get-GSACurrentUserUPN)" # Retrieve the GSA endpoints from the registry. $gsaEndpoints = Get-GSAEndpoints -RegistryValueName "ForwardingProfile" if (-Not $gsaEndpoints) { return } # Extract the main endpoint addresses and diagnostic URIs from the retrieved GSA endpoints. $gsaMainEndpointAddrs = $gsaEndpoints.MainEndpoints $DiagnosticUris = $gsaEndpoints.DiagnosticUris # Define the set of connectivity tests to be executed by main function. $tests = [ordered]@{ "GSA Service Status" = { Test-GSAServiceStatus } "Device Entra Status" = { Test-DeviceEntraStatus } "GSA Primary Refresh Token" = { Test-GSAPrimaryRefreshToken } "GSA Forwarding Profile Registry" = { Test-GSAForwardingProfileRegistry } "GSA Forwarding Profile Timestamp" = { Test-GSAForwardingProfileTimestamp -PassThru } "Basic Internet connectivity" = { Test-InternetConnectivity } "Proxy Detection" = { Test-ProxyDetection -PassThru } "GSA Secure DNS Status" = { Test-GSASecureDnsStatus } "GSA IPv6 Status" = { Test-GSAIPv6Status -PassThru } "DNS Resolution" = { param($param1) Test-DnsResolution -fqdnList $param1 } "Tenant Internet DNS Resolution" = { Test-GSATenantInternetDnsResolution } "Entra ID Connectivity" = { Test-EntraIDConnectivity } "TLS Connectivity" = { param($param1) Test-TLSConnection -fqdnList $param1 } "mTLS Connectivity" = { param($param1) Test-mTLSConnectivity -fqdnList $param1 -PassThru } "Diagnostics Connectivity" = { param($param1) Test-GSADiagnosticUriConnectivity -DiagnosticUris $param1 } "GSA Synthetic Routes" = { Test-GSASyntheticRoutes -PassThru } "GSA Private DNS Resolver" = { Test-GSAPrivateDnsResolver } "GSA Event Log" = { Test-GSAEventLog -PassThru } } # Define the parameters for the connectivity tests that require them. $testParams = [ordered]@{ "DNS Resolution" = @{ param1 = $gsaMainEndpointAddrs } "TLS Connectivity" = @{ param1 = $gsaMainEndpointAddrs } "mTLS Connectivity" = @{ param1 = $gsaMainEndpointAddrs } "Diagnostics Connectivity" = @{ param1 = $DiagnosticUris } } # Execute each connectivity test in sequence, passing the required parameters if applicable. foreach ($testName in $tests.Keys) { Write-Log -Message "===== Executing: $testName =========" -Level "INFO" $scriptBlock = $tests[$testName] $params = $testParams[$testName] # Initialize the test result variable for the current test. $script:_testResult = $null $result = if ($params) { & $scriptBlock @params } else { & $scriptBlock } if ($null -eq $result -and $null -ne $script:_testResult) { $result = $script:_testResult } # If a test function leaked extra pipeline output, extract the PSCustomObject if ($result -is [array]) { $result = $result | Where-Object { $_ -is [PSCustomObject] } | Select-Object -Last 1 } $testResults[$testName] = $result # View the results type output if ($result -is [PSCustomObject]) { if ($result.Warnings -gt 0) { Write-Log "===== $testName : WARNINGS =========" "WARNING" $testsWithWarnings++ } if ($result.Passed -eq $true) { Write-Log "===== $testName : PASSED =========" "SUCCESS" $testsPassed++ } elseif ($result.Passed -eq $false) { Write-Log "===== $testName : FAILED =========" "ERROR" $testsFailed++ } } else { if ($result -eq $true) { Write-Log "===== $testName : PASSED =========" "SUCCESS" $testsPassed++ } elseif ($result -eq $false) { Write-Log "===== $testName : FAILED =========" "ERROR" $testsFailed++ } } } # Log the completion of the connectivity check. Write-Log "========= GSA Client Connectivity Check Completed =========" "INFO" # Prepare the summary table for the test results. $summaryTable = @() foreach ($testName in $testResults.Keys) { $result = if ($testResults[$testName] -is [PSCustomObject]) { if ($testResults[$testName].Passed -eq $true) { "PASSED" } else { "FAILED" } } else { if ($testResults[$testName] -eq $true) { "PASSED" } else { "FAILED" } } $warnings = if ($testResults[$testName] -is [PSCustomObject] -and $testResults[$testName].Warnings) { $testResults[$testName].Warnings } else { 0 } $summaryTable += [PSCustomObject]@{ TestName = $testName Result = $result Warnings = $warnings } } Write-Log "Test Results Summary:" "INFO" $nameWidth = [Math]::Max((($summaryTable.TestName | Measure-Object -Property Length -Maximum).Maximum), "Test Name".Length) $resultWidth = [Math]::Max(6, "Result".Length) $warnWidth = [Math]::Max(8, "Warnings".Length) # ASCII-only borders/icons - Windows PowerShell 5.1 reads .ps1 files using the system codepage # without a UTF-8 BOM, so box-drawing/emoji characters can get mangled on save/load. $topBorder = "+---+-$('-' * $nameWidth)-+-$('-' * $resultWidth)-+-$('-' * $warnWidth)-+" $midBorder = "+---+-$('-' * $nameWidth)-+-$('-' * $resultWidth)-+-$('-' * $warnWidth)-+" $bottomBorder = "+---+-$('-' * $nameWidth)-+-$('-' * $resultWidth)-+-$('-' * $warnWidth)-+" $rowFormat = "| {0} | {1,-$nameWidth} | {2,-$resultWidth} | {3,$warnWidth} |" Write-Log $topBorder "INFO" -NoPrefix -Color DarkGray Write-Log ($rowFormat -f " ", "Test Name", "Result", "Warnings") "INFO" -NoPrefix -Color White Write-Log $midBorder "INFO" -NoPrefix -Color DarkGray # Iterate through each row in the summary table and log the test results with appropriate icons and colors. foreach ($row in $summaryTable) { $icon = if ($row.Result -eq 'FAILED') { 'X' } elseif ($row.Warnings -gt 0) { '!' } else { '*' } $rowColor = if ($row.Result -eq 'FAILED') { 'Red' } elseif ($row.Warnings -gt 0) { 'Yellow' } else { 'Green' } Write-Log ($rowFormat -f $icon, $row.TestName, $row.Result, $row.Warnings) "INFO" -NoPrefix -Color $rowColor } Write-Log $bottomBorder "INFO" -NoPrefix -Color DarkGray Write-Log "Summary: $testsPassed tests passed, $testsFailed tests failed, $testsWithWarnings tests with warnings." "INFO" # Provide a textual summary of the overall test results. if ($testsFailed -eq 0 -and $testsWithWarnings -eq 0) { Write-Log "All tests passed successfully!" "SUCCESS" } elseif ($testsFailed -eq 0) { Write-Log "All tests passed, but some tests generated warnings. Please review the logs for details." "WARNING" } else { Write-Log "Some tests failed. Please review the logs for details." "ERROR" } } |