Initial public release: netswitch v1.0.0
This commit is contained in:
commit
cce5204c25
4 changed files with 224 additions and 0 deletions
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Build output / staging
|
||||
*.exe
|
||||
portable-v*/
|
||||
|
||||
# Local backup of release archives
|
||||
releases/
|
||||
|
||||
# Editor / OS junk
|
||||
.vscode/
|
||||
.idea/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 engelgardt
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
48
README.md
Normal file
48
README.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# netswitch
|
||||
|
||||
[](https://github.com/Engelgardt23/netswitch/releases/latest)
|
||||
[](LICENSE)
|
||||
|
||||
A tiny portable tool to flip a Windows network adapter between a **static IP** and **DHCP** with a few keystrokes.
|
||||
|
||||
Built for the recurring engineer chore of "give my laptop NIC 10.10.10.1 so I can talk to a server's BMC" and "now put it back on DHCP so I can have internet again."
|
||||
|
||||
> **Made by engelgardt.**
|
||||
|
||||
---
|
||||
|
||||
## Download
|
||||
|
||||
Grab the latest release: [**releases page**](https://github.com/Engelgardt23/netswitch/releases/latest).
|
||||
The asset is `netswitch-portable-vX.Y.Z.zip` (~30 KB).
|
||||
|
||||
## Run
|
||||
|
||||
1. Unzip anywhere.
|
||||
2. Double-click `netswitch.exe`.
|
||||
3. Accept the UAC prompt (admin is needed for `netsh interface ipv4 set address`).
|
||||
4. Pick the network adapter from the list.
|
||||
5. Choose mode:
|
||||
- **Static**: enter IP (default `10.10.10.1`), mask (default `255.255.255.0`), gateway (optional).
|
||||
- **DHCP**: just confirms — the NIC reverts to DHCP for both IP and DNS.
|
||||
|
||||
## What it filters
|
||||
|
||||
Only real, wired physical adapters appear in the picker. Wireless, VPN, virtual, Hyper-V, VMware, VirtualBox, TAP/TUN, WireGuard, OpenVPN, Tailscale, ZeroTier, Bluetooth, Loopback, WAN Miniport — all skipped.
|
||||
|
||||
## Update check
|
||||
|
||||
On every launch the tool calls GitHub's `/releases/latest` (3-second timeout). If a newer version is available, it prints a yellow notice and offers to open the download page in your browser. If you're offline, it stays silent.
|
||||
|
||||
## Build from source
|
||||
|
||||
The script is a single `netswitch.ps1`. To rebuild the bundled `.exe`:
|
||||
|
||||
```
|
||||
Install-Module ps2exe -Scope CurrentUser
|
||||
Invoke-ps2exe -inputFile netswitch.ps1 -outputFile netswitch.exe -requireAdmin -title "netswitch" -version 1.0.0.0
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](LICENSE).
|
||||
143
netswitch.ps1
Normal file
143
netswitch.ps1
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# netswitch v1.0.0 - quick NIC IP / DHCP toggle
|
||||
# made by engelgardt
|
||||
|
||||
$NetswitchVersion = '1.0.0'
|
||||
$GithubRepo = 'Engelgardt23/netswitch'
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# --- Self-elevate if not admin (no-op when launched from the ps2exe build which already requests admin) ---
|
||||
$me = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
if (-not $me.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
if ($PSCommandPath) {
|
||||
Start-Process -FilePath 'powershell.exe' `
|
||||
-ArgumentList @('-NoProfile','-ExecutionPolicy','Bypass','-File',"`"$PSCommandPath`"") `
|
||||
-Verb RunAs
|
||||
} else {
|
||||
Start-Process -FilePath ([System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName) -Verb RunAs
|
||||
}
|
||||
exit
|
||||
}
|
||||
|
||||
# --- Banner ---
|
||||
Write-Host ""
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host " netswitch v$NetswitchVersion - NIC IP/DHCP toggle" -ForegroundColor Cyan
|
||||
Write-Host " made by engelgardt" -ForegroundColor DarkCyan
|
||||
Write-Host "==============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# --- Update check ---
|
||||
function Test-NetswitchUpdate {
|
||||
try {
|
||||
$url = "https://api.github.com/repos/$GithubRepo/releases/latest"
|
||||
$r = Invoke-RestMethod -Uri $url -TimeoutSec 3 -Headers @{ 'User-Agent' = "netswitch/$NetswitchVersion" }
|
||||
$latest = ($r.tag_name -as [string]) -replace '^v',''
|
||||
if (-not $latest) { return }
|
||||
$toTuple = { param($s)
|
||||
$parts = ($s -split '\.') | ForEach-Object {
|
||||
$n = 0; [void][int]::TryParse($_, [ref]$n); $n
|
||||
}
|
||||
while ($parts.Count -lt 3) { $parts += 0 }
|
||||
,$parts[0..2]
|
||||
}
|
||||
$L = & $toTuple $latest
|
||||
$C = & $toTuple $NetswitchVersion
|
||||
$isNewer = $false
|
||||
for ($i = 0; $i -lt 3; $i++) {
|
||||
if ($L[$i] -gt $C[$i]) { $isNewer = $true; break }
|
||||
if ($L[$i] -lt $C[$i]) { break }
|
||||
}
|
||||
if ($isNewer) {
|
||||
Write-Host "Update available: v$NetswitchVersion -> $($r.tag_name)" -ForegroundColor Yellow
|
||||
$ans = Read-Host "Open the download page in your browser? [Y/n]"
|
||||
if ($ans -notmatch '^(n|N|no|NO)$') {
|
||||
Start-Process $r.html_url
|
||||
}
|
||||
Write-Host ""
|
||||
}
|
||||
} catch {
|
||||
# silent on offline / API errors
|
||||
}
|
||||
}
|
||||
Test-NetswitchUpdate
|
||||
|
||||
# --- Pick adapter (physical wired only) ---
|
||||
$skipDescriptionPattern = 'VPN|Virtual|AnyConnect|TAP-|TUN-|Bluetooth|Loopback|WAN Miniport|Hyper-V|VMware|VirtualBox|WireGuard|OpenVPN|Tailscale|ZeroTier'
|
||||
$skipMediaTypes = @('Native 802.11', 'Wireless WAN')
|
||||
|
||||
$adapters = @(Get-NetAdapter | Where-Object {
|
||||
$_.Status -notin @('Disabled','Not Present') -and
|
||||
-not $_.Virtual -and
|
||||
$_.MediaType -notin $skipMediaTypes -and
|
||||
$_.InterfaceDescription -notmatch $skipDescriptionPattern -and
|
||||
$_.Name -notmatch $skipDescriptionPattern
|
||||
} | Sort-Object ifIndex)
|
||||
|
||||
if ($adapters.Count -eq 0) {
|
||||
Write-Host "No physical wired adapters found." -ForegroundColor Red
|
||||
Read-Host "Press Enter to exit"; exit 1
|
||||
}
|
||||
|
||||
Write-Host "Available adapters:"
|
||||
for ($i = 0; $i -lt $adapters.Count; $i++) {
|
||||
$a = $adapters[$i]
|
||||
$ips = (Get-NetIPAddress -InterfaceIndex $a.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.PrefixOrigin -ne 'WellKnown' }).IPAddress -join ', '
|
||||
Write-Host (" {0}) [{1,-12}] {2} ({3}) {4}" -f ($i + 1), $a.Status, $a.Name, $a.InterfaceDescription, $ips)
|
||||
}
|
||||
|
||||
do {
|
||||
$sel = (Read-Host "Select adapter number").Trim()
|
||||
$valid = ($sel -match '^\d+$') -and ([int]$sel -ge 1) -and ([int]$sel -le $adapters.Count)
|
||||
if (-not $valid) { Write-Host "Invalid selection." -ForegroundColor Red }
|
||||
} while (-not $valid)
|
||||
$nic = $adapters[[int]$sel - 1]
|
||||
Write-Host ""
|
||||
Write-Host "Selected: $($nic.Name)" -ForegroundColor Green
|
||||
|
||||
# --- Mode ---
|
||||
Write-Host ""
|
||||
Write-Host "Mode:"
|
||||
Write-Host " 1) Static IP"
|
||||
Write-Host " 2) DHCP"
|
||||
$modeChoice = Read-Host "Choice [1]"
|
||||
if ([string]::IsNullOrWhiteSpace($modeChoice)) { $modeChoice = '1' }
|
||||
|
||||
if ($modeChoice.Trim() -eq '2') {
|
||||
# --- DHCP ---
|
||||
Write-Host ""
|
||||
Write-Host "Setting $($nic.Name) to DHCP..." -ForegroundColor Yellow
|
||||
& netsh interface ipv4 set address name="$($nic.Name)" source=dhcp
|
||||
& netsh interface ipv4 set dnsservers name="$($nic.Name)" source=dhcp
|
||||
Write-Host "Done." -ForegroundColor Green
|
||||
}
|
||||
else {
|
||||
# --- Static ---
|
||||
$ip = Read-Host "IP address [10.10.10.1]"
|
||||
if ([string]::IsNullOrWhiteSpace($ip)) { $ip = '10.10.10.1' }
|
||||
|
||||
$mask = Read-Host "Subnet mask [255.255.255.0]"
|
||||
if ([string]::IsNullOrWhiteSpace($mask)) { $mask = '255.255.255.0' }
|
||||
|
||||
$gw = Read-Host "Gateway (Enter to skip)"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Setting $($nic.Name) -> $ip / $mask$( if ($gw) { " via $gw" })" -ForegroundColor Yellow
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($gw)) {
|
||||
& netsh interface ipv4 set address name="$($nic.Name)" static $ip $mask
|
||||
} else {
|
||||
& netsh interface ipv4 set address name="$($nic.Name)" static $ip $mask $gw
|
||||
}
|
||||
Write-Host "Done." -ForegroundColor Green
|
||||
}
|
||||
|
||||
# --- Show current state ---
|
||||
Write-Host ""
|
||||
Write-Host "Current IPv4 config:" -ForegroundColor Cyan
|
||||
Get-NetIPAddress -InterfaceIndex $nic.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.PrefixOrigin -ne 'WellKnown' } |
|
||||
Format-Table IPAddress, PrefixLength, PrefixOrigin -AutoSize
|
||||
|
||||
Read-Host "Press Enter to exit"
|
||||
Loading…
Reference in a new issue