Private/AzStackHci.Network.Helpers.ps1
|
# //////////////////////////////////////////////////////////////////////////// # Test if proxy is enabled and return boolean function Get-Proxy { <# .SYNOPSIS Check if proxy is enabled and return boolean and proxy server uri #> begin { # Write-Debug "Get-Proxy: Beginning proxy detection process" } process { $line1, $line2, $line3, $JsonLines = netsh winhttp show advproxy $ProxyInformation = $JsonLines | ConvertFrom-Json -ErrorAction SilentlyContinue # Return True/False and the Proxy server uri as a PSObject $ProxyReturnVariable = New-Object PsObject -Property @{ # True/False Enabled = [bool]$ProxyInformation.Proxy # Proxy server URI Server = $ProxyInformation.Proxy # Proxy bypass list # ProxyBypass = $proxy.Bypass } # Check if the Proxy is enabled and if the proxy server is set if($ProxyReturnVariable.Enabled) { if(-not($ProxyReturnVariable.Server)){ # In case the proxy server is not set from netsh winhttp show advproxy output $proxyUri = [Uri]$null $ProxyTest = [System.Net.WebRequest]::GetSystemWebProxy() $ProxyTest.Credentials = [System.Net.CredentialCache]::DefaultCredentials # use a known URL to test the proxy server, but http, in case of Arc Gateway, to prevent "localhost" from being returned # This is a known URL that should be accessible from any network $TestUrl = [System.Uri]::new("http://oneocsp.microsoft.com") # Test the proxy server using a known URL $proxyUri = $ProxyTest.GetProxy($TestUrl) if($proxyUri -eq $TestUrl) { # Proxy is not required, so do not use it $ProxyReturnVariable.Enabled = $false Write-HostAzS "`t`nNo proxy server detected, using direct connection...`n" -ForegroundColor Green } else { # Proxy is required, so use it $ProxyReturnVariable.Server = $proxyUri } } # Check if the proxy server string has a semi-colon which can be used for Arc Gateway if($ProxyReturnVariable.Server -match ";"){ # In case the proxy server is set from netsh winhttp show advproxy output [array]$ProxyStrings = $ProxyReturnVariable.Server.ToString().Split(";") } if($ProxyStrings){ # Check if the proxy server string has a semi-colon which can be used for Arc Gateway # Multiple proxy servers detected Write-HostAzS "`n`tArc Gateway scenario detected (possible), as multiple proxy servers detected ('netsh winhttp show advproxy')..." ForEach($ProxyServer in $ProxyStrings){ # Trim the proxy server string $ProxyServer = $ProxyServer.Trim() if($ProxyServer -like "http=*"){ # HTTP proxy server (should be customer proxy server) # Check if the proxy server is set from netsh winhttp show advproxy output Write-HostAzS "`tHTTP Proxy server detected, using proxy: $($ProxyServer)" -ForegroundColor Green } elseif($ProxyServer -like "https=*"){ # HTTPS proxy server (might be Arc Gateway Agent, "localhost") # Check if the proxy server is set from netsh winhttp show advproxy output Write-HostAzS "`tHTTPS Proxy server detected, using proxy: $($ProxyServer)" -ForegroundColor Green } else { # Other proxy server detected # Check if the proxy server is set from netsh winhttp show advproxy output Write-HostAzS "`tProxy server detected, using proxy: $($ProxyServer)" -ForegroundColor Green } } # End ForEach Write-HostAzS "" } else { # Single proxy detected Write-HostAzS "`t`nProxy server detected, using proxy: $($ProxyReturnVariable.Server)`n" -ForegroundColor Green } } else { # Proxy is NOT enabled # No proxy server detected, so use direct connection Write-HostAzS "`t`nNo proxy server detected, using direct connection...`n" -ForegroundColor Green } } # End of process block end { # Write-Debug "Get-Proxy: Proxy detection process completed" # Return the ProxyReturnVariable object Return $ProxyReturnVariable } } # End Function Get-Proxy # //////////////////////////////////////////////////////////////////////////// # This function retrieves the SSL certificate chain from a remote HTTPS endpoint # It uses the System.Net.Http.HttpClient class to make the request and capture the certificate chain function Get-SslCertificateChain { <# .SYNOPSIS Retrieve remote ssl certificate & chain from https endpoint for Desktop and Core .NOTES Credit: https://github.com/markekraus #> [CmdletBinding()] param ( [system.uri] $url, [Parameter()] [bool] $AllowAutoRedirect, [Parameter()] [string] $Proxy ) begin { # Write-Debug "Get-SslCertificateChain: Beginning SSL certificate chain retrieval for '$url'" } process { try { $cs = @' using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Security; using System.Security.Cryptography.X509Certificates; namespace CertificateCapture { public class Utility { public static Func<HttpRequestMessage,X509Certificate2,X509Chain,SslPolicyErrors,Boolean> ValidationCallback = (message, cert, chain, errors) => { CapturedCertificates.Clear(); var newCert = new X509Certificate2(cert); var newChain = new X509Chain(); newChain.Build(newCert); CapturedCertificates.Add(new CapturedCertificate(){ Certificate = newCert, CertificateChain = newChain, PolicyErrors = errors, URI = message.RequestUri }); return true; }; public static List<CapturedCertificate> CapturedCertificates = new List<CapturedCertificate>(); } public class CapturedCertificate { public X509Certificate2 Certificate { get; set; } public X509Chain CertificateChain { get; set; } public SslPolicyErrors PolicyErrors { get; set; } public Uri URI { get; set; } } } '@ try { if (-not ('CertificateCapture.Utility' -as [type])) { if ($PSEdition -ne 'Core') { Add-Type -AssemblyName System.Net.Http Add-Type $cs -ReferencedAssemblies System.Net.Http } else { Add-Type $cs } } } catch { if ($_.Exception.Message -notmatch 'Definition of new types is not supported in this language mode') { throw "Language mode does not allow this test Error: $_" } } # Reset variables, in case cached. Remove-Variable Certs, Handler, Client, Request -ErrorAction SilentlyContinue # Create a new list to hold captured certificates. $Certs = [CertificateCapture.Utility]::CapturedCertificates # Clear any previously captured certificates. $Certs.Clear() # Create the HttpClientHandler. $Handler = [System.Net.Http.HttpClientHandler]::new() # This is important to capture the certificate chain of the first endpoint, not redirected endpoints. if($AllowAutoRedirect -eq $false) { # Set the handler to not allow auto redirects # https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.allowautoredirect $Handler.AllowAutoRedirect = $false } if ($Proxy) { $Handler.Proxy = New-Object System.Net.WebProxy($proxy) } # Set the ServerCertificateCustomValidationCallback to our custom callback. $Handler.ServerCertificateCustomValidationCallback = [CertificateCapture.Utility]::ValidationCallback # Create the HttpClient with the handler $Client = [System.Net.Http.HttpClient]::new($Handler) # Set a timeout to 15 seconds (reduced from 60s to limit impact of unresponsive backend pool servers): $Client.Timeout = 150000000 try { # Setup the request to the URL. $Request = $Client.GetAsync($url) # Wait for the request to complete calling the Result method. $Null = $Request.Result # Check if the request is completed and that certificates were captured. if(($Request.IsCompleted) -and $Certs){ # Return the captured certificate chain Write-Debug "Successfully obtained SSL certificate chain from endpoint: '$url'" return $Certs.CertificateChain } else { # Return null if no certificates were captured. Write-Debug "Failed to obtain SSL certificate chain from endpoint: '$url'" return $null } } finally { # Dispose IDisposable resources to prevent socket/handle leaks if ($Request) { $Request.Dispose() } if ($Client) { $Client.Dispose() } if ($Handler) { $Handler.Dispose() } } } catch { throw $_ } } # End of process block end { # Write-Debug "Get-SslCertificateChain: SSL certificate chain retrieval completed" } } # End Function Get-SslCertificateChain |