SQL-Connectivity-Checker/AdvancedConnectivityPolicyT...

359 строки
15 KiB
PowerShell

using namespace System
using namespace System.Net
using namespace System.net.Sockets
using namespace System.Collections.Generic
using namespace System.Diagnostics
# PowerShell Container Image Support Start
if (!$(Get-Command 'Test-NetConnection' -errorAction SilentlyContinue)) {
function Test-NetConnection {
param(
[Parameter(Position = 0, Mandatory = $true)] $HostName,
[Parameter(Mandatory = $true)] $Port
);
process {
$client = [TcpClient]::new()
try {
$client.Connect($HostName, $Port)
$result = @{TcpTestSucceeded = $true; InterfaceAlias = 'Unsupported' }
}
catch {
$result = @{TcpTestSucceeded = $false; InterfaceAlias = 'Unsupported' }
}
$client.Dispose()
return $result
}
}
}
if (!$(Get-Command 'Resolve-DnsName' -errorAction SilentlyContinue)) {
function Resolve-DnsName {
param(
[Parameter(Position = 0)] $Name,
[Parameter()] $Server,
[switch] $CacheOnly,
[switch] $DnsOnly,
[switch] $NoHostsFile
);
process {
# ToDo: Add support
Write-Host "WARNING: Current environment doesn't support multiple DNS sources."
return @{ IPAddress = [Dns]::GetHostAddresses($Name).IPAddressToString };
}
}
}
if (!$(Get-Command 'Get-NetAdapter' -errorAction SilentlyContinue)) {
function Get-NetAdapter {
param(
[Parameter(Position = 0, Mandatory = $true)] $HostName,
[Parameter(Mandatory = $true)] $Port
);
process {
Write-Host 'Unsupported'
}
}
}
# PowerShell Container Image Support End
function PrintAverageConnectionTime($addressList, $port) {
Write-Host 'Printing average connection times for 5 connection attempts:' -ForegroundColor Green
$stopwatch = [StopWatch]::new()
foreach ($ipAddress in $addressList) {
[double]$sum = 0
[int]$numFailed = 0
[int]$numSuccessful = 0
for ($i = 0; $i -lt 5; $i++) {
$client = [TcpClient]::new()
try {
$stopwatch.Restart()
$client.Connect($ipAddress, $port)
$stopwatch.Stop()
$sum += $stopwatch.ElapsedMilliseconds
$numSuccessful++
}
catch {
$numFailed++
}
$client.Dispose()
}
$avg = 0
if ($numSuccessful -ne 0) {
$avg = $sum / $numSuccessful
}
Write-Host ' IP Address:'$ipAddress' Port:'$port
Write-Host ' Successful connections:'$numSuccessful
Write-Host ' Failed connections:'$numFailed
Write-Host ' Average response time:'$avg' ms'
}
}
function PrintDNSResults($dnsResult, [string] $dnsSource) {
if ($dnsResult) {
Write-Host ' Found DNS record in' $dnsSource '(IP Address:'$dnsResult.IPAddress')'
}
else {
Write-Host ' Could not find DNS record in' $dnsSource
}
}
function ValidateDNS([String] $Server) {
Try {
Write-Host 'Validating DNS record for' $Server -ForegroundColor Green
if (!$(Get-Command 'Resolve-DnsName' -errorAction SilentlyContinue)) {
Write-Host " WARNING: Current environment doesn't support multiple DNS sources."
Write-Host ' DNS resolution:' ([Dns]::GetHostAddresses($Name).IPAddressToString)
}
else {
Try {
$DNSfromHosts = Resolve-DnsName -Name $Server -CacheOnly -ErrorAction SilentlyContinue
PrintDNSResults $DNSfromHosts 'hosts file'
}
Catch {
Write-Host "Error at ValidateDNS from hosts file" -Foreground Red
Write-Host $_.Exception.Message -ForegroundColor Red
TrackWarningAnonymously 'Error at ValidateDNS from hosts file'
}
Try {
$DNSfromCache = Resolve-DnsName -Name $Server -NoHostsFile -CacheOnly -ErrorAction SilentlyContinue
PrintDNSResults $DNSfromCache 'cache'
}
Catch {
Write-Host "Error at ValidateDNS from cache" -Foreground Red
Write-Host $_.Exception.Message -ForegroundColor Red
TrackWarningAnonymously 'Error at ValidateDNS from cache'
}
Try {
$DNSfromCustomerServer = Resolve-DnsName -Name $Server -DnsOnly -ErrorAction SilentlyContinue
PrintDNSResults $DNSfromCustomerServer 'DNS server'
}
Catch {
Write-Host "Error at ValidateDNS from DNS server" -Foreground Red
Write-Host $_.Exception.Message -ForegroundColor Red
TrackWarningAnonymously 'Error at ValidateDNS from DNS server'
}
Try {
$DNSfromOpenDNS = Resolve-DnsName -Name $Server -DnsOnly -Server 208.67.222.222 -ErrorAction SilentlyContinue
PrintDNSResults $DNSfromOpenDNS 'Open DNS'
}
Catch {
Write-Host "Error at ValidateDNS from Open DNS" -Foreground Red
Write-Host $_.Exception.Message -ForegroundColor Red
TrackWarningAnonymously 'Error at ValidateDNS from Open DNS'
}
}
}
Catch {
Write-Host "Error at ValidateDNS" -Foreground Red
Write-Host $_.Exception.Message -ForegroundColor Red
}
}
function TrackWarningAnonymously ([String] $warningCode) {
Try {
if ($SendAnonymousUsageData) {
$body = New-Object PSObject `
| Add-Member -PassThru NoteProperty name 'Microsoft.ApplicationInsights.Event' `
| Add-Member -PassThru NoteProperty time $([System.dateTime]::UtcNow.ToString('o')) `
| Add-Member -PassThru NoteProperty iKey "a75c333b-14cb-4906-aab1-036b31f0ce8a" `
| Add-Member -PassThru NoteProperty tags (New-Object PSObject | Add-Member -PassThru NoteProperty 'ai.user.id' $AnonymousRunId) `
| Add-Member -PassThru NoteProperty data (New-Object PSObject `
| Add-Member -PassThru NoteProperty baseType 'EventData' `
| Add-Member -PassThru NoteProperty baseData (New-Object PSObject `
| Add-Member -PassThru NoteProperty ver 2 `
| Add-Member -PassThru NoteProperty name $warningCode));
$body = $body | ConvertTo-JSON -depth 5;
Invoke-WebRequest -Uri 'https://dc.services.visualstudio.com/v2/track' -Method 'POST' -UseBasicParsing -body $body > $null
}
}
Catch {
Write-Host 'TrackWarningAnonymously exception:'
Write-Host $_.Exception.Message -ForegroundColor Red
}
}
$parameters = $args[0]
$Server = $parameters['Server']
$Port = $parameters['Port']
$AuthenticationType = $parameters['AuthenticationType']
$AuthenticationLibrary = $parameters['AuthenticationLibrary']
$UserAssignedIdentityClientId = $parameters['UserAssignedIdentityClientId']
$User = $parameters['User']
$Password = $parameters['Password']
$Database = $parameters['Database']
$EncryptionProtocol = $parameters['EncryptionProtocol']
$RepositoryBranch = $parameters['RepositoryBranch']
$Local = $parameters['Local']
$LocalPath = $parameters['LocalPath']
$SendAnonymousUsageData = $parameters['SendAnonymousUsageData']
$AnonymousRunId = $parameters['AnonymousRunId']
$logsFolderName = $parameters['logsFolderName']
$outFolderName = $parameters['outFolderName']
$ConnectionAttempts = 1
if ($null -ne $parameters['ConnectionAttempts']) {
$ConnectionAttempts = $parameters['ConnectionAttempts']
}
$DelayBetweenConnections = 1
if ($null -ne $parameters['DelayBetweenConnections']) {
$DelayBetweenConnections = $parameters['DelayBetweenConnections']
}
if ([string]::IsNullOrEmpty($env:TEMP)) {
$env:TEMP = '/tmp';
}
try {
Set-Location -Path $env:TEMP
Set-Location $logsFolderName
Set-Location $outFolderName
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
$TDSClientPath = Join-Path ((Get-Location).Path) "TDSClient.dll"
$MicrosoftIdentityClientDll = Join-Path ((Get-Location).Path) "Microsoft.Identity.Client.dll"
$IdentityModelAbstractions = Join-Path ((Get-Location).Path) "Microsoft.IdentityModel.Abstractions.dll"
$ActiveDirectoryDll = Join-Path ((Get-Location).Path) "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
if ($Local) {
Copy-Item -Path $($LocalPath + '\netstandard2.0\TDSClient.dll') -Destination $TDSClientPath
Copy-Item -Path $($LocalPath + '\netstandard2.0\Microsoft.Identity.Client.dll') -Destination $MicrosoftIdentityClientDll
Copy-Item -Path $($LocalPath + '\netstandard2.0\Microsoft.IdentityModel.Abstractions.dll') -Destination $IdentityModelAbstractions
Copy-Item -Path $($LocalPath + '\netstandard2.0\Microsoft.IdentityModel.Clients.ActiveDirectory.dll') -Destination $ActiveDirectoryDll
}
else {
Invoke-WebRequest -Uri $('https://github.com/Azure/SQL-Connectivity-Checker/raw/' + $RepositoryBranch + '/netstandard2.0/TDSClient.dll') -OutFile $TDSClientPath -UseBasicParsing
Invoke-WebRequest -Uri $('https://github.com/Azure/SQL-Connectivity-Checker/raw/' + $RepositoryBranch + '/netstandard2.0/Microsoft.Identity.Client.dll') -OutFile $MicrosoftIdentityClientDll -UseBasicParsing
Invoke-WebRequest -Uri $('https://github.com/Azure/SQL-Connectivity-Checker/raw/' + $RepositoryBranch + '/netstandard2.0/Microsoft.IdentityModel.Abstractions.dll') -OutFile $IdentityModelAbstractions -UseBasicParsing
Invoke-WebRequest -Uri $('https://github.com/Azure/SQL-Connectivity-Checker/raw/' + $RepositoryBranch + '/netstandard2.0/Microsoft.IdentityModel.Clients.ActiveDirectory.dll') -OutFile $ActiveDirectoryDll -UseBasicParsing
}
$assembly = [System.IO.File]::ReadAllBytes($TDSClientPath)
$assembly2 = [System.IO.File]::ReadAllBytes($MicrosoftIdentityClientDll)
$assembly3 = [System.IO.File]::ReadAllBytes($IdentityModelAbstractions)
$assembly4 = [System.IO.File]::ReadAllBytes($ActiveDirectoryDll)
[System.Reflection.Assembly]::Load($assembly) | Out-Null
[System.Reflection.Assembly]::Load($assembly2) | Out-Null
[System.Reflection.Assembly]::Load($assembly3) | Out-Null
[System.Reflection.Assembly]::Load($assembly4) | Out-Null
$fullLogPath = Join-Path ((Get-Location).Path) 'AdvancedTests_FullLog.txt'
$logPath = Join-Path ((Get-Location).Path) 'AdvancedTests_LastRunLog.txt'
$summaryLogPath = Join-Path ((Get-Location).Path) 'AdvancedTests_SummaryLog.txt'
$summaryLog = [System.IO.File]::CreateText($summaryLogPath)
[TDSClient.TDS.Utilities.LoggingUtilities]::SetSummaryLog($summaryLog)
try {
switch ($EncryptionProtocol) {
'Tls 1.0' {
$encryption = [System.Security.Authentication.SslProtocols]::Tls
break
}
'Tls 1.1' {
$encryption = [System.Security.Authentication.SslProtocols]::Tls11
break
}
'Tls 1.2' {
$encryption = [System.Security.Authentication.SslProtocols]::Tls12
break
}
# Not supported
#'Tls 1.3' {
# $encryption = [System.Security.Authentication.SslProtocols]::Tls13
# break
#}
default {
# Allow the operating system to choose the best protocol to use
$encryption = [System.Security.Authentication.SslProtocols]::Tls12 -bor [System.Security.Authentication.SslProtocols]::Tls11 -bor [System.Security.Authentication.SslProtocols]::Default
}
}
$tdsClient = [TDSClient.TDS.Client.TDSSQLTestClient]::new($Server, $Port, $AuthenticationType, $User, $Password, $Database, $encryption, $AuthenticationLibrary, $UserAssignedIdentityClientId)
for ($i = 1; $i -le $ConnectionAttempts; ++$i) {
$log = [System.IO.File]::CreateText($logPath)
[TDSClient.TDS.Utilities.LoggingUtilities]::SetVerboseLog($log)
$result = $tdsClient.Connect().GetAwaiter().GetResult()
Write-Host
$tdsClient.Disconnect()
$log.Close()
[TDSClient.TDS.Utilities.LoggingUtilities]::ClearVerboseLog()
$result = $([System.IO.File]::ReadAllText($logPath))
Write-Host $result
Add-Content -Path $fullLogPath -Value $result
# if ($i -lt $ConnectionAttempts) {
# Write-Host ('Waiting ' + $DelayBetweenConnections + ' second(s)...')
# Start-Sleep -Seconds $DelayBetweenConnections
# }
}
TrackWarningAnonymously ('Advanced|TDSClient|ConnectAndDisconnect')
}
catch {
[TDSClient.TDS.Utilities.LoggingUtilities]::WriteLog('Failure: ' + $_.Exception.InnerException.Message)
TrackWarningAnonymously ('Advanced|TDSClient|Exception|' + $_.Exception.InnerException.Message)
}
finally {
$log.Close()
[TDSClient.TDS.Utilities.LoggingUtilities]::ClearVerboseLog()
$summaryLog.Close()
[TDSClient.TDS.Utilities.LoggingUtilities]::ClearSummaryLog()
Remove-Item $TDSClientPath -Force
}
$result = $([System.IO.File]::ReadAllText($logPath))
$match = [Regex]::Match($result, "Routing to: (.*)\.")
if ($match.Success) {
$array = $match.Groups[1].Value -split ':'
$server = $array[0]
$port = $array[1]
Write-Host 'Redirect connectivity policy has been detected, running additional tests:' -ForegroundColor Green
TrackWarningAnonymously 'Advanced|Redirect|Detected'
ValidateDNS $server
try {
$dnsResult = [System.Net.DNS]::GetHostEntry($server)
}
catch {
$msg = ' ERROR: Name resolution (DNS) of ' + $server + ' failed'
Write-Host $msg -Foreground Red
$Advanced_DNSResolutionFailed = ' Please make sure the name ' + $server + ' can be resolved (DNS)
Failure to resolve specific domain names is usually a client-side networking issue that you will need to pursue with your local network administrator.'
Write-Host $Advanced_DNSResolutionFailed -Foreground Red
TrackWarningAnonymously 'Advanced|Redirect|DNSResolutionFailedForRedirect'
return
}
$resolvedAddress = $dnsResult.AddressList[0].IPAddressToString
Write-Host
PrintAverageConnectionTime $resolvedAddress $port
}
else {
Write-Host ' Proxy connection policy detected!' -ForegroundColor Green
TrackWarningAnonymously 'Advanced|Proxy|Detected'
}
}
catch {
Write-Host 'Running advanced connectivity policy tests failed!' -ForegroundColor Red
Write-Host $_.Exception
TrackWarningAnonymously ('Advanced|Exception|' + $_.Exception.Message)
}