-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGet-Whois.ps1
More file actions
420 lines (357 loc) · 14.4 KB
/
Copy pathGet-Whois.ps1
File metadata and controls
420 lines (357 loc) · 14.4 KB
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
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
function Get-Whois
{
<#
.SYNOPSIS
Performs WHOIS lookups for domain names and IP addresses.
.DESCRIPTION
Queries WHOIS servers to retrieve registration information for domain names and IP addresses.
Supports multiple TLDs and provides detailed registration information including registrar,
creation date, expiration date, nameservers, and contact information.
Uses direct TCP connections to WHOIS servers for cross-platform compatibility without
requiring external tools or platform-specific commands.
Compatible with PowerShell Desktop 5.1+ on Windows, macOS, and Linux.
.PARAMETER Domain
The domain name or IP address to query.
Accepts pipeline input for bulk WHOIS lookups.
Examples: 'bing.com', 'github.com', '8.8.8.8'
.PARAMETER Server
Specify a custom WHOIS server to query.
If not specified, the function automatically determines the appropriate WHOIS server
based on the domain TLD.
Example: 'whois.verisign-grs.com'
.PARAMETER Port
The port to connect to on the WHOIS server.
Default is 43 (standard WHOIS port).
.PARAMETER Timeout
Connection timeout in seconds.
Default is 15 seconds. Valid range: 5-60 seconds.
.PARAMETER Raw
Return the raw WHOIS response without parsing.
Useful for debugging or when you need the complete unprocessed output.
.EXAMPLE
PS > Get-Whois -Domain 'bing.com'
Domain : bing.com
WhoisServer : whois.markmonitor.com
Registrar : MarkMonitor, Inc.
CreationDate : 9/15/1997 12:00:00 AM
UpdatedDate : 8/2/2024 12:00:00 AM
ExpirationDate : 9/13/2028 12:00:00 AM
Status : {clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited), clientTransferProhibited
(https://www.icann.org/epp#clientTransferProhibited), clientDeleteProhibited
(https://www.icann.org/epp#clientDeleteProhibited), serverUpdateProhibited
(https://www.icann.org/epp#serverUpdateProhibited)…}
NameServers : {ns1.bing.com, ns3.bing.com, ns4.bing.com, ns2.bing.com}
...
...
Performs a WHOIS lookup for bing.com and returns parsed registration information.
.EXAMPLE
PS > Get-Whois -Domain 'github.com' -Raw
Returns the raw WHOIS response for github.com without parsing.
.EXAMPLE
PS > @('bing.com', 'github.com', 'microsoft.com') | Get-Whois
Performs WHOIS lookups for multiple domains using pipeline input.
.EXAMPLE
PS > Get-Whois -Domain '8.8.8.8'
Performs a WHOIS lookup for an IP address.
.EXAMPLE
PS > Get-Whois -Domain 'example.com' -Server 'whois.verisign-grs.com'
Queries a specific WHOIS server for domain information.
.EXAMPLE
PS > Get-Whois -Domain 'google.co.uk'
Performs a WHOIS lookup for a country-code TLD domain.
.EXAMPLE
PS > 'api.example.com','cdn.example.com' | Get-Whois | Select-Object Domain,ExpirationDate | Sort-Object ExpirationDate
Audits multiple domains from automation to ensure registrations won't lapse before renewing TLS certificates.
.OUTPUTS
System.Management.Automation.PSCustomObject
Returns an object with Domain, Registrar, CreationDate, ExpirationDate, NameServers, and RawResponse properties.
When -Raw is specified, returns the raw string response.
.LINK
https://www.iana.org/whois
.NOTES
WHOIS Server Selection:
- Automatically selects appropriate server based on TLD
- Falls back to IANA WHOIS for unknown TLDs
- Supports referrals to authoritative WHOIS servers
Common WHOIS Servers:
- .com/.net: whois.verisign-grs.com
- .org: whois.pir.org
- .info: whois.afilias.net
- IP addresses: whois.arin.net (and regional registries)
Note: Some domains may be privacy-protected and show limited information.
Rate limiting may apply for bulk queries.
Author: Jon LaBelle
License: MIT
.LINK
https://github.com/jonlabelle/pwsh-profile/blob/main/Functions/NetworkAndDns/Get-Whois.ps1
Source: https://github.com/jonlabelle/pwsh-profile/blob/main/Functions/NetworkAndDns/Get-Whois.ps1
#>
[CmdletBinding()]
[OutputType([System.Management.Automation.PSCustomObject])]
[OutputType([System.String])]
param(
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)]
[ValidateNotNullOrEmpty()]
[Alias('Name', 'DomainName', 'IPAddress')]
[String]$Domain,
[Parameter()]
[String]$Server,
[Parameter()]
[ValidateRange(1, 65535)]
[Int32]$Port = 43,
[Parameter()]
[ValidateRange(5, 60)]
[Int32]$Timeout = 15,
[Parameter()]
[Switch]$Raw
)
begin
{
Write-Verbose 'Initializing WHOIS query'
# Common WHOIS servers for popular TLDs
$whoisServers = @{
'com' = 'whois.verisign-grs.com'
'net' = 'whois.verisign-grs.com'
'org' = 'whois.pir.org'
'info' = 'whois.afilias.net'
'biz' = 'whois.biz'
'us' = 'whois.nic.us'
'uk' = 'whois.nic.uk'
'co.uk' = 'whois.nic.uk'
'ca' = 'whois.cira.ca'
'au' = 'whois.auda.org.au'
'de' = 'whois.denic.de'
'jp' = 'whois.jprs.jp'
'fr' = 'whois.afnic.fr'
'it' = 'whois.nic.it'
'nl' = 'whois.domain-registry.nl'
'eu' = 'whois.eu'
'ru' = 'whois.tcinet.ru'
'cn' = 'whois.cnnic.cn'
'br' = 'whois.registro.br'
'in' = 'whois.registry.in'
'mx' = 'whois.mx'
'se' = 'whois.iis.se'
'no' = 'whois.norid.no'
'ch' = 'whois.nic.ch'
'at' = 'whois.nic.at'
'dk' = 'whois.dk-hostmaster.dk'
'tv' = 'whois.nic.tv'
'io' = 'whois.nic.io'
'co' = 'whois.nic.co'
'me' = 'whois.nic.me'
'be' = 'whois.dns.be'
'nz' = 'whois.srs.net.nz'
'ai' = 'whois.nic.ai'
'dev' = 'whois.nic.google'
'app' = 'whois.nic.google'
}
# Default WHOIS server for IP addresses and unknown TLDs
$defaultWhoisServer = 'whois.iana.org'
}
process
{
$domainToQuery = $Domain.Trim().ToLower()
Write-Verbose "Performing WHOIS lookup for: $domainToQuery"
try
{
# Determine WHOIS server if not specified
if (-not $Server)
{
# Check if it's an IP address
try
{
[void][System.Net.IPAddress]::Parse($domainToQuery)
Write-Verbose 'Detected IP address, using ARIN WHOIS server'
$whoisServer = 'whois.arin.net'
}
catch
{
# Extract TLD from domain
$parts = $domainToQuery.Split('.')
if ($parts.Count -ge 2)
{
# Try country-code TLD first (e.g., co.uk)
$tld = "$($parts[-2]).$($parts[-1])"
if ($whoisServers.ContainsKey($tld))
{
$whoisServer = $whoisServers[$tld]
Write-Verbose "Using WHOIS server for .$tld : $whoisServer"
}
else
{
# Try single TLD
$tld = $parts[-1]
if ($whoisServers.ContainsKey($tld))
{
$whoisServer = $whoisServers[$tld]
Write-Verbose "Using WHOIS server for .$tld : $whoisServer"
}
else
{
Write-Verbose "No specific WHOIS server found for .$tld, using IANA"
$whoisServer = $defaultWhoisServer
}
}
}
else
{
Write-Verbose 'Invalid domain format, using default WHOIS server'
$whoisServer = $defaultWhoisServer
}
}
}
else
{
$whoisServer = $Server
Write-Verbose "Using specified WHOIS server: $whoisServer"
}
# Connect to WHOIS server
Write-Verbose "Connecting to $whoisServer on port $Port"
$tcpClient = New-Object System.Net.Sockets.TcpClient
$connectTask = $tcpClient.ConnectAsync($whoisServer, $Port)
$timeoutMs = $Timeout * 1000
if (-not $connectTask.Wait($timeoutMs))
{
$tcpClient.Close()
throw "Connection to WHOIS server '$whoisServer' timed out after $Timeout seconds"
}
if (-not $tcpClient.Connected)
{
throw "Failed to connect to WHOIS server '$whoisServer'"
}
Write-Verbose 'Connected to WHOIS server, sending query'
# Send query
$stream = $tcpClient.GetStream()
$stream.ReadTimeout = $timeoutMs
$stream.WriteTimeout = $timeoutMs
$query = "$domainToQuery`r`n"
$queryBytes = [System.Text.Encoding]::ASCII.GetBytes($query)
$stream.Write($queryBytes, 0, $queryBytes.Length)
$stream.Flush()
Write-Verbose 'Query sent, reading response'
# Read response
$reader = New-Object System.IO.StreamReader($stream, [System.Text.Encoding]::ASCII)
$response = $reader.ReadToEnd()
# Cleanup
$reader.Close()
$stream.Close()
$tcpClient.Close()
Write-Verbose "Received response ($($response.Length) bytes)"
# Check for referral to another WHOIS server
if ($response -match 'Registrar WHOIS Server:\s*(.+?)(\r|\n)' -or
$response -match 'whois:\s*(.+?)(\r|\n)' -or
$response -match 'refer:\s*(.+?)(\r|\n)')
{
$referralServer = $matches[1].Trim()
if ($referralServer -and $referralServer -ne $whoisServer -and -not $Server)
{
Write-Verbose "Following referral to authoritative WHOIS server: $referralServer"
# Recursive call to referred server
return Get-Whois -Domain $domainToQuery -Server $referralServer -Port $Port -Timeout $Timeout -Raw:$Raw
}
}
# Return raw response if requested
if ($Raw)
{
Write-Output $response
return
}
# Parse response
Write-Verbose 'Parsing WHOIS response'
$result = [PSCustomObject]@{
Domain = $domainToQuery
WhoisServer = $whoisServer
Registrar = $null
CreationDate = $null
UpdatedDate = $null
ExpirationDate = $null
Status = @()
NameServers = @()
DNSSEC = $null
RawResponse = $response
}
# Extract registrar
if ($response -match '(?:Registrar|Organization):\s*(.+?)(\r|\n)')
{
$result.Registrar = $matches[1].Trim()
}
# Extract dates (various formats)
if ($response -match 'Creation Date:\s*(.+?)(\r|\n|T)')
{
$dateStr = $matches[1].Trim()
try
{
$result.CreationDate = [DateTime]::Parse($dateStr)
}
catch
{
Write-Verbose "Could not parse creation date: $dateStr"
}
}
if ($response -match 'Updated Date:\s*(.+?)(\r|\n|T)')
{
$dateStr = $matches[1].Trim()
try
{
$result.UpdatedDate = [DateTime]::Parse($dateStr)
}
catch
{
Write-Verbose "Could not parse updated date: $dateStr"
}
}
if ($response -match 'Registry Expiry Date:\s*(.+?)(\r|\n|T)' -or
$response -match 'Expiration Date:\s*(.+?)(\r|\n|T)')
{
$dateStr = $matches[1].Trim()
try
{
$result.ExpirationDate = [DateTime]::Parse($dateStr)
}
catch
{
Write-Verbose "Could not parse expiration date: $dateStr"
}
}
# Extract domain status
$statusMatches = [regex]::Matches($response, 'Domain Status:\s*(.+?)(\r|\n)')
foreach ($match in $statusMatches)
{
$status = $match.Groups[1].Value.Trim()
if ($status -and $status -notin $result.Status)
{
$result.Status += $status
}
}
# Extract nameservers
$nsMatches = [regex]::Matches($response, 'Name Server:\s*(.+?)(\r|\n)')
foreach ($match in $nsMatches)
{
$ns = $match.Groups[1].Value.Trim().ToLower()
if ($ns -and $ns -notin $result.NameServers)
{
$result.NameServers += $ns
}
}
# Extract DNSSEC
if ($response -match 'DNSSEC:\s*(.+?)(\r|\n)')
{
$result.DNSSEC = $matches[1].Trim()
}
Write-Output $result
}
catch [System.Net.Sockets.SocketException]
{
Write-Error "Network error during WHOIS lookup for '$domainToQuery': $($_.Exception.Message)"
}
catch
{
Write-Error "WHOIS lookup failed for '$domainToQuery': $($_.Exception.Message)"
}
}
end
{
Write-Verbose 'WHOIS query completed'
}
}