-
Notifications
You must be signed in to change notification settings - Fork 0
/
PublicIPAddress.psm1
355 lines (298 loc) · 19.9 KB
/
PublicIPAddress.psm1
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
Function Save-PublicIPAddress
{
<#
.SYNOPSIS
Get public IPv4 or IPv6 address and save the IP-address to a file.
.DESCRIPTION
Public IP-address will be saved into IPv4.txt or IPv6.txt file in the given path, depending on whether IPv6 switch-parameter is used.
The given path is checked for existence of IPv4.txt/IPv6.txt and if the file exists, IP-address will be read from the file and checked against current public IP-address of specified type.
Existing file will then be updated should IP-address been changed. If no file exists, then a new file will be created.
API of whatismyipaddress.com will be used to query for current public IP-address of specified type. Please note that queries should not be run more frequently than once per five minutes.
.PARAMETER Path
Specifies directory path where IPv4.txt or IPv6.txt should be written to.
.PARAMETER IPv6
Queries for IPv6 address instead of IPv4. IPv4 is the default.
.PARAMETER ScheduledTask
When this switch is specified, a scheduled task to run Save-PublicIPAddress function every 15 minutes will be created. The scheduled task will run under SYSTEM account and thus will not be visible to regular user accounts.
.PARAMETER ScheduledTask
By default this function does not generate output. By specifying this switch, the function will output current public IP-address.
.EXAMPLE
Save-PublicIPAddress -Path C:\Users\User\Dropbox
Queries for current public IPv4-address and saves the IP-address to IPv4.txt in C:\Users\User\Dropbox.
.EXAMPLE
Save-PublicIPAddress -Path C:\Users\User\Dropbox -IPv6
Queries for current public IPv6-address and saves the IP-address to IPv6.txt in C:\Users\User\Dropbox.
.EXAMPLE
Save-PublicIPAddress -Path C:\Users\User\Dropbox -ScheduledTask
Creates a scheduled task to run "Save-PublicIPAddress -Path C:\Users\User\Dropbox" every 15 minutes.
.EXAMPLE
Save-PublicIPAddress -Path C:\Users\User\Dropbox -IPv6 -ScheduledTask
Creates a scheduled task to run "Save-PublicIPAddress -IPv6 -Path C:\Users\User\Dropbox" every 15 minutes.
#>
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact = 'Low', DefaultParameterSetName = 'Default')]
Param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[ValidateScript({ Test-DirectoryPath -Path $_ })]
[string]
$Path,
[switch]
$IPv6,
[Parameter(ParameterSetName = 'ScheduledTask')]
[switch]
$ScheduledTask,
[Parameter(ParameterSetName = 'PassThru')]
[switch]
$PassThru
)
If ($ScheduledTask)
{
If ((Test-Administrator) -eq $false)
{
Write-Error -Message "PowerShell must be run as Administrator in order to create a new scheduled task." -Category PermissionDenied -ErrorAction Stop
}
New-SavePublicIPAddressScheduledTask -Path $Path -IPv6:$IPv6
}
Else
{
$FileIPAddress = Get-FileIPAddress -Path $Path -IPv6:$IPv6
$PublicIPAddress = Get-PublicIPAddress -IPv6:$IPv6
If (($PublicIPAddress) -and ($FileIPAddress -ne $PublicIPAddress))
{
Set-FileIPAddress -Path $Path -IPAddress $PublicIPAddress -IPv6:$IPv6
}
If ($PassThru)
{
$PublicIPAddress
}
}
}
Function Test-DirectoryPath
{
<#
.SYNOPSIS
Test whether given Path is a valid directory path and that the directory exists.
#>
Param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[string]
$Path
)
If (-not (Test-Path -Path FileSystem::$Path -PathType Container))
{
throw "`"$Path`" is not a valid directory path, or the directory does not exist."
}
$true
}
Function Test-Administrator
{
<#
.SYNOPSIS
Test whether current PowerShell instance is running with Administrator privileges.
#>
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")
}
Function Get-FileIPAddress
{
<#
.SYNOPSIS
Get IP-address from existing IPv4.txt/IPv6.txt.
#>
Param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[string]
$Path,
[switch]
$IPv6
)
If ($IPv6)
{
$FilePath = Join-Path -Path $Path -ChildPath 'IPv6.txt'
$None = '::'
}
Else
{
$FilePath = Join-Path -Path $Path -ChildPath 'IPv4.txt'
$None = '0.0.0.0'
}
If (Test-Path FileSystem::$FilePath -PathType Leaf)
{
Get-Content FileSystem::$FilePath
}
Else
{
$None
}
}
Function Set-FileIPAddress
{
<#
.SYNOPSIS
Write new IP-address to IPv4.txt/IPv6.txt in the given path.
#>
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact = 'Low')]
Param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[string]
$Path,
[Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[string]
$IPAddress,
[switch]
$IPv6
)
If ($IPv6)
{
$FilePath = Join-Path -Path $Path -ChildPath 'IPv6.txt'
}
Else
{
$FilePath = Join-Path -Path $Path -ChildPath 'IPv4.txt'
}
$IPAddress | Out-File -FilePath FileSystem::$FilePath -Encoding utf8
}
Function Get-PublicIPAddress
{
<#
.SYNOPSIS
Get public IPv4 or IPv6 address.
.DESCRIPTION
API of whatismyipaddress.com will be used to query for current public IP-address of specified type.
.PARAMETER IPv6
Queries for IPv6 address instead of IPv4. IPv4 is the default.
.EXAMPLE
Get-PublicIPAddress
Returns current public IPv4-address.
.EXAMPLE
Get-PublicIPAddress -IPv6
Returns current public IPv6-address.
#>
Param (
[switch]
$IPv6
)
If ($IPv6)
{
$Uri = 'ipv6bot.whatismyipaddress.com'
}
Else
{
$Uri = 'ipv4bot.whatismyipaddress.com'
}
Invoke-WebRequest -Uri $Uri -UseBasicParsing -DisableKeepAlive | Select-Object -ExpandProperty Content
}
Function New-SavePublicIPAddressScheduledTask
{
<#
.SYNOPSIS
Create a scheduled task to run Save-PublicIPAddress function every 15 minutes.
#>
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact = 'Low')]
Param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[string]
$Path,
[switch]
$IPv6
)
$xmlPath = New-ScheduledTaskXml -Path $Path -IPv6:$IPv6
If ($IPv6)
{
$TaskName = 'SavePublicIPv6Address'
}
Else
{
$TaskName = 'SavePublicIPv4Address'
}
If ($PSCmdlet.ShouldProcess("$TaskName", "Create and run scheduled task"))
{
If (Test-Path -Path FileSystem::$xmlPath)
{
schtasks /CREATE /TN $TaskName /XML "$xmlPath" /F
schtasks /RUN /TN $TaskName
}
}
If (Test-Path -Path FileSystem::$xmlPath)
{
Remove-Item -Path FileSystem::$xmlPath -Force
}
}
Function New-ScheduledTaskXml
{
<#
.SYNOPSIS
Create an xml file that contains the information required to create a scheduled task. For use by schtasks.exe.
#>
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact = 'Low')]
Param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[string]
$Path,
[switch]
$IPv6
)
$xml = '<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Author>Juho Lehto</Author>
<Description>A scheduled task to periodically run Save-PublicIPAddress PowerShell function.</Description>
</RegistrationInfo>
<Triggers>
<TimeTrigger>
<Repetition>
<Interval>PT15M</Interval>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>1990-01-01T00:00:00</StartBoundary>
<Enabled>true</Enabled>
</TimeTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<RunLevel>LeastPrivilege</RunLevel>
<GroupId>NT AUTHORITY\SYSTEM</GroupId>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>true</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT10M</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>powershell.exe</Command>
<Arguments>-windowstyle hidden -noprofile -command "Save-PublicIPAddress -Path ''DIRPATH''"</Arguments>
</Exec>
</Actions>
</Task>'
$xmlPath = Join-Path -Path $env:TEMP -ChildPath 'SavePublicIPAddress.xml'
$Minute = ((Get-Date).Minute).ToString('00')
$Second = ((Get-Date).Second).ToString('00')
$xml = $xml -creplace 'T00:00:00', "T00:$($Minute):$($Second)" -creplace 'DIRPATH', $Path
If ($IPv6)
{
$xml = $xml -creplace '-Path', '-IPv6 -Path'
}
$xml | Out-File -FilePath FileSystem::$xmlPath -Encoding unicode
$xmlPath
}