-
Notifications
You must be signed in to change notification settings - Fork 38
/
AdvancedConnectivityPolicyTests.ps1
359 lines (317 loc) · 14.8 KB
/
AdvancedConnectivityPolicyTests.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
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)
}