Skip to content

Instantly share code, notes, and snippets.

@christiangda
Created May 21, 2025 10:22
Show Gist options
  • Save christiangda/ed6b94734292425eb549c7946889c015 to your computer and use it in GitHub Desktop.
Save christiangda/ed6b94734292425eb549c7946889c015 to your computer and use it in GitHub Desktop.
Powershell script to check my external IP periodically
<#
.SYNOPSIS
Checks and logs the external IP address at a specified interval.
.DESCRIPTION
This script periodically fetches the public IP address from a specified web service
and logs it to a file and the console. The check period, IP endpoint, and log file
can be customized via parameters.
.PARAMETER PeriodSeconds
The interval in seconds at which to check the IP address. Must be a positive integer.
Default is 60 seconds.
.PARAMETER Endpoint
The URL of the service to use for checking the IP address (e.g., "ifconfig.me", "ipinfo.io/ip").
Default is "ifconfig.me".
.PARAMETER LogFile
The path to the log file where IP address checks will be recorded.
Default is "external_ip.log" in the script's directory.
.PARAMETER Help
Displays this help message.
.EXAMPLE
.\Get-ExternalIpPeriodically.ps1
Runs with default settings: checks every 60 seconds using ifconfig.me, logs to external_ip.log.
.EXAMPLE
.\Get-ExternalIpPeriodically.ps1 -PeriodSeconds 30
Checks the IP every 30 seconds.
.EXAMPLE
.\Get-ExternalIpPeriodically.ps1 -PeriodSeconds 120 -Endpoint "ipinfo.io/ip"
Checks every 2 minutes using the ipinfo.io/ip service.
.EXAMPLE
.\Get-ExternalIpPeriodically.ps1 -LogFile "C:\Logs\MyPublicIP.txt" -PeriodSeconds 300
Checks every 5 minutes and logs to C:\Logs\MyPublicIP.txt.
.EXAMPLE
.\Get-ExternalIpPeriodically.ps1 -Help
Displays the help information.
.NOTES
Author: Gemini
Version: 1.0
To stop the script, press Ctrl+C.
Ensure your PowerShell execution policy allows running scripts.
You might need to run: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false, HelpMessage="Check period in seconds (e.g., 30 for 30 seconds). Default: 60")]
[ValidateRange(1, [int]::MaxValue)] # Ensures it's a positive integer
[int]$PeriodSeconds = 60,
[Parameter(Mandatory=$false, HelpMessage="IP check endpoint (e.g., 'ipinfo.io/ip', 'api.ipify.org'). Default: 'ifconfig.me'")]
[string]$Endpoint = "ifconfig.me",
[Parameter(Mandatory=$false, HelpMessage="Path to the log file. Default: 'external_ip.log' in script directory")]
[string]$LogFile = (Join-Path $PSScriptRoot "external_ip.log"),
[Parameter(Mandatory=$false, HelpMessage="Display this help message.")]
[switch]$Help
)
# --- Function to display usage (using Get-Help) ---
if ($Help) {
Get-Help $MyInvocation.MyCommand.Definition -Full
exit 0
}
# --- Function to get the external IP address ---
function Get-ExternalIp {
param(
[string]$CurrentEndpoint,
[string]$CurrentLogFile,
[int]$CurrentPeriodSeconds
)
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$ExternalIp = $null
$LogMessage = ""
try {
# Add "http://" or "https://" if not present, common for simple endpoints like "ifconfig.me"
$Uri = $CurrentEndpoint
if (-not ($Uri.StartsWith("http://") -or $Uri.StartsWith("https://"))) {
$Uri = "http://" + $Uri # Default to http, some services might require https
}
# Invoke-RestMethod is often better for APIs as it tries to parse the result
# Using -UseBasicParsing to avoid issues with IE first launch configuration
# Setting a timeout for the web request
Write-Verbose "Attempting to fetch IP from $Uri"
$ExternalIp = Invoke-RestMethod -Uri $Uri -TimeoutSec 10 -UseBasicParsing
}
catch {
$ErrorMessage = $_.Exception.Message
$LogMessage = "$Timestamp - Error: Could not retrieve IP from $CurrentEndpoint. Details: $ErrorMessage (Period: ${CurrentPeriodSeconds}s)"
Write-Warning $LogMessage
$LogMessage | Add-Content -Path $CurrentLogFile
return # Exit function on error
}
if (-not [string]::IsNullOrWhiteSpace($ExternalIp)) {
# Basic validation for an IP address format (can be improved for stricter IPv4/IPv6 checks)
# This regex matches common IPv4 and IPv6 patterns.
$IpPattern = '^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$|^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4})$'
if ($ExternalIp -match $IpPattern) {
$LogMessage = "$Timestamp - External IP: $ExternalIp (Endpoint: $CurrentEndpoint, Period: ${CurrentPeriodSeconds}s)"
Write-Host $LogMessage -ForegroundColor Green
} else {
$LogMessage = "$Timestamp - Warning: Received non-IP response from $CurrentEndpoint: '$ExternalIp' (Period: ${CurrentPeriodSeconds}s)"
Write-Warning $LogMessage
}
} else {
$LogMessage = "$Timestamp - Warning: Received empty response from $CurrentEndpoint. (Period: ${CurrentPeriodSeconds}s)"
Write-Warning $LogMessage
}
# Log to file
if (-not [string]::IsNullOrWhiteSpace($LogMessage)) {
try {
$LogMessage | Add-Content -Path $CurrentLogFile -ErrorAction Stop
}
catch {
Write-Error "Failed to write to log file $CurrentLogFile. Error: $($_.Exception.Message)"
}
}
}
# --- Main loop ---
Write-Host "Starting IP check..." -ForegroundColor Cyan
Write-Host "Check Period: $($PeriodSeconds) seconds" -ForegroundColor Cyan
Write-Host "IP Endpoint: $Endpoint" -ForegroundColor Cyan
Write-Host "Log File: $LogFile" -ForegroundColor Cyan
Write-Host "Press Ctrl+C to stop." -ForegroundColor Yellow
# Create log file directory if it doesn't exist
$LogDirectory = Split-Path -Path $LogFile -Parent
if (-not (Test-Path $LogDirectory)) {
try {
New-Item -ItemType Directory -Path $LogDirectory -Force -ErrorAction Stop | Out-Null
Write-Verbose "Created log directory: $LogDirectory"
}
catch {
Write-Error "Could not create log directory: $LogDirectory. Error: $($_.Exception.Message)"
Write-Error "Please create the directory manually or choose a different log file path."
exit 1
}
}
# Trap Ctrl+C for graceful exit
trap {
Write-Host "Script interrupted. Exiting." -ForegroundColor Yellow
break # Breaks out of the loop
}
while ($true) {
Get-ExternalIp -CurrentEndpoint $Endpoint -CurrentLogFile $LogFile -CurrentPeriodSeconds $PeriodSeconds
Start-Sleep -Seconds $PeriodSeconds
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment