- PowerShell 100%
| assets | ||
| log | ||
| src | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| LICENSE | ||
| README.en-US.md | ||
| README.md | ||
Table of Contents
- Overview
- Features
- Prerequisites
- Installation and Usage
- Remote Execution (irm/iex)
- Parameters
- Configuration via .env
- Generated Logs
- Machine Identification
- Examples
- Contributing
Overview
WiMoni is a PowerShell script that continuously monitors internet connection quality using exclusively native Windows resources — no external dependencies to install and no Administrator privileges required.
At each configurable cycle (default: 10 minutes), the script measures ICMP latency, DNS resolution, TCP connectivity, and HTTP download speed, writing structured results to log files with a unique machine identifier — ideal for comparing connections across different computers.
Features
- ICMP latency measurement (native ping) with min/max/avg/jitter statistics and packet loss
- Timed DNS resolution
- Timed TCP handshake (port 443)
- HTTP download speed with throughput calculation in Mbps and KB/s
- Two separate log files: detailed DEBUG and clean RESULTS
- Unique composite machine ID (SHA-256 hash of ComputerName + MachineGuid + BIOS Serial + MAC Address)
- Flexible configuration via
.envfile - Compatible with Windows PowerShell 5.1 and PowerShell 7+
- Remote execution via
irm | iexwithout installation
Prerequisites
- Windows 10 / Windows Server 2016 or later
- Windows PowerShell 5.1+ or PowerShell 7+
- Internet access (for ping targets and download test URLs)
- Does not require Administrator privileges
Installation and Usage
Option 1 — Clone the repository
git clone https://forge.itamarcampos.com.br/itamcampos/wimoni.git
cd wimoni\src
.\WiMoni.ps1
Option 2 — Direct download
Download WiMoni.ps1 and run it:
.\WiMoni.ps1
Note: When running a script downloaded from the internet, Windows may require the execution policy to allow local scripts. Run the following command once if needed:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Remote Execution (irm/iex)
Execute the script directly from the internet without cloning the repository:
Simple execution
irm https://forge.itamarcampos.com.br/itamcampos/wimoni/raw/branch/main/src/WinMoni.ps1 | iex
Using the system proxy:
irm https://forge.itamarcampos.com.br/itamcampos/wimoni/raw/branch/main/src/WinMoni.ps1 -Proxy ([System.Net.WebRequest]::GetSystemWebProxy().GetProxy("https://forge.itamarcampos.com.br")) -ProxyUseDefaultCredentials | iex
Specifying proxy address, port, username and password manually:
irm https://forge.itamarcampos.com.br/itamcampos/wimoni/raw/branch/main/src/WinMoni.ps1 -Proxy "http://proxy.company.com:8080" -ProxyCredential (New-Object PSCredential("username", (ConvertTo-SecureString "password" -AsPlainText -Force))) | iex
Execution with parameters
& ([scriptblock]::Create((irm https://forge.itamarcampos.com.br/itamcampos/wimoni/raw/branch/main/src/WinMoni.ps1))) -Verbose -Cycles 3 -IntervalMinutes 1
Using the system proxy:
& ([scriptblock]::Create((irm https://forge.itamarcampos.com.br/itamcampos/wimoni/raw/branch/main/src/WinMoni.ps1 -Proxy ([System.Net.WebRequest]::GetSystemWebProxy().GetProxy("https://forge.itamarcampos.com.br")) -ProxyUseDefaultCredentials))) -Verbose -Cycles 3 -IntervalMinutes 1
Specifying proxy address, port, username and password manually:
& ([scriptblock]::Create((irm https://forge.itamarcampos.com.br/itamcampos/wimoni/raw/branch/main/src/WinMoni.ps1 -Proxy "http://proxy.company.com:8080" -ProxyCredential (New-Object PSCredential("username", (ConvertTo-SecureString "password" -AsPlainText -Force)))))) -Verbose -Cycles 3 -IntervalMinutes 1
Security notice: Always verify the content of scripts before executing them via
iex. Inspect the source code athttps://forge.itamarcampos.com.br/itamcampos/wimoni.
Credentials notice: Avoid writing passwords as plain text directly in the terminal in shared environments. Prefer storing credentials with
Get-Credentialand reusing them:$cred = Get-Credential # opens a secure prompt for username and password irm <url> -Proxy "http://proxy.company.com:8080" -ProxyCredential $cred | iex
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
-Verbose |
Switch | — | Enables detailed console output |
-SkipPause |
Switch | — | Suppresses the interactive pause on exit |
-Cycles |
Int | 0 |
Number of measurement cycles. 0 = infinite |
-IntervalMinutes |
Int | 10 |
Interval between measurements in minutes (1–1440) |
Configuration via .env
Create a .env file in the project root to override the default values:
# Ping targets (hostname or IP)
PING_TARGET_1=8.8.8.8
PING_TARGET_2=1.1.1.1
# Number of pings per target per cycle
PING_COUNT=8
# URLs for download speed testing
DOWNLOAD_TEST_URL_1=https://speed.cloudflare.com/__down?bytes=500000
DOWNLOAD_TEST_URL_2=https://proof.ovh.net/files/1Mb.dat
# Quality thresholds (in milliseconds)
THRESHOLD_EXCELLENT_MS=30
THRESHOLD_GOOD_MS=80
THRESHOLD_FAIR_MS=150
# Packet loss threshold (%)
THRESHOLD_LOSS_PCT=5
# Execution control (overridden by explicit command-line parameters)
CYCLES=0
INTERVAL_MINUTES=10
The .env file is optional. If it does not exist, the script uses the built-in default values.
Generated Logs
Logs are written to the TesteVelocidade\ directory inside the current user's Desktop ($env:USERPROFILE\Desktop\TesteVelocidade), or to a custom path defined by the -LogDir parameter.
| File | Description |
|---|---|
debug_YYYY-MM-DD_HH-mm-ss.log |
Detailed record of all internal operations |
resultado_analise_YYYY-MM-DD_HH-mm-ss.log |
Formatted results from each measurement cycle |
Each cycle writes the following to the results log:
- ICMP Latency (Ping): average, minimum, maximum, jitter, and packet loss percentage per target, with a quality rating
- DNS Resolution: resolution time for each monitored host
- TCP Connectivity (port 443): connection establishment time per host
- HTTP Download Speed: throughput in Mbps and KB/s per test URL
- Cycle summary: cycle number, machine name and unique ID, overall status, and duration
======================================================================
CYCLE #1 — 2025-01-15 10:00:00
======================================================================
>> LATENCY (ICMP Ping)
HOST: 8.8.8.8 Status: OK Avg: 12.50 ms Min: 11.00 ms Max: 15.00 ms Jitter: 1.25 ms Loss: 0.0% Quality: ✅ EXCELLENT
>> DNS RESOLUTION
HOST: 8.8.8.8 DNS: 3.45 ms
>> TCP CONNECTIVITY (port 443)
HOST: 8.8.8.8 TCP: 18.72 ms
>> DOWNLOAD SPEED (HTTP)
[speed.cloudflare.com] 45.231 Mbps (5654.1 KB/s) — 500000 bytes in 0.088s
>> SUMMARY: Cycle #1 | Machine: MYPC (A1B2C3D4E5F6G7H8) | Overall Status: OK | Duration: 4.3s
Machine Identification
Each run records a unique composite machine ID generated from:
ComputerNameMachineGuid(Windows registry)BiosSerialMACAddress(first network adapter with an active IP)
The ID is a SHA-256 hash truncated to 16 characters (e.g., A1B2C3D4E5F6G7H8), allowing logs from different computers to be identified and compared without exposing full sensitive data.
Examples
Default run — infinite cycles every 10 minutes, silent output:
.\WiMoni.ps1
Verbose mode with 5 cycles every 1 minute — useful for quick testing:
.\WiMoni.ps1 -Verbose -Cycles 5 -IntervalMinutes 1
Background execution — writes logs without a visible window:
Start-Process powershell -ArgumentList "-NonInteractive -File .\WiMoni.ps1 -SkipPause" -WindowStyle Hidden
Scheduled via Task Scheduler — starts with Windows login:
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NonInteractive -File C:\wimoni\src\WiMoni.ps1 -SkipPause"
$trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName "WiMoni" -Action $action -Trigger $trigger -RunLevel Limited
Contributing
Suggestions and improvements are welcome. Open an issue or submit a pull request.