How to Get the Link-Local IPv6 Address in Batch Script
While most users are familiar with IPv4 (e.g., 192.168.1.5), modern Windows networking relies heavily on IPv6. Specifically, the Link-Local Address (which always starts with fe80:) is a unique identifier that every network card automatically assigns itself. This address allows your computer to communicate with other devices on the same local network even without a router or a DHCP server. Identifying this address is essential for troubleshooting "Neighbor Discovery" issues, homegroups, or local printer connections.
This guide will explain how to extract your IPv6 Link-Local address using Batch.
Method 1: Parsing IPCONFIG (The Fast Way)
The Link-Local address is clearly labeled in the ipconfig output. However, the address contains colons, the same character used as the FOR /F delimiter, which requires careful parsing.
@echo off
setlocal enabledelayedexpansion
echo [NET] Searching for IPv6 Link-Local Address...
echo.
set "IPV6="
set "AdapterCount=0"
:: The IPv6 address contains colons, so we CANNOT use colon as a delimiter
:: Instead, use "delims=" to capture the full line, then extract the address
for /f "delims=" %%L in ('ipconfig ^| findstr /i /c:"Link-local IPv6"') do (
set "line=%%L"
set /a AdapterCount+=1
:: Extract everything after the last ": " (the address itself)
:: Find the position of "fe80" in the line
set "addr="
for %%w in (!line!) do (
echo %%w | findstr /i "fe80" >nul 2>&1
if !errorlevel! equ 0 set "addr=%%w"
)
if defined addr (
echo [FOUND] Adapter #!AdapterCount! - Link-Local: !addr!
:: Keep the last one found (or change logic to keep first)
set "IPV6=!addr!"
)
)
echo.
if not defined IPV6 (
echo [ERROR] No Link-Local IPv6 address found.
echo Possible causes:
echo - IPv6 is disabled on your network adapter
echo - No active network adapters
echo.
echo [TIP] Check adapter properties: ncpa.cpl
) else (
echo [RESULT] Primary Link-Local IPv6: !IPV6!
)
pause
endlocal
delims=:?Using delims=: will destroy the IPv6 address. An IPv6 address like fe80::1a2b:3c4d:5e6f:7890%12 contains 6 colons, splitting on : would scatter it across multiple tokens, and tokens=2 would only capture fe80, not the full address.
Method 2: Adapter-Specific Query (PowerShell Bridge)
If you have multiple adapters (Wi-Fi, Ethernet, VPN), you need to know which Link-Local address belongs to which adapter. PowerShell's Get-NetIPAddress provides clean, structured output.
The Win32_NetworkAdapterConfiguration class's IPAddress property returns IPv4 and IPv6 addresses as an array, but parsing arrays from WMIC in Batch is extremely unreliable. PowerShell is the correct tool for this task.
@echo off
setlocal
echo [QUERY] Retrieving Link-Local IPv6 addresses per adapter...
echo.
powershell -NoProfile -Command ^
"$addrs = Get-NetIPAddress -AddressFamily IPv6 -ErrorAction SilentlyContinue |"^
" Where-Object { $_.IPAddress -like 'fe80::*' -and $_.AddressState -eq 'Preferred' };"^
""^
"if (-not $addrs) {"^
" Write-Host '[ERROR] No Link-Local IPv6 addresses found.';"^
" Write-Host ' IPv6 may be disabled on all adapters.';"^
" exit 1"^
"};"^
""^
"Write-Host (' {0,-25} {1,-45} {2}' -f 'ADAPTER','LINK-LOCAL ADDRESS','ZONE ID');"^
"Write-Host (' ' + '-' * 80);"^
""^
"foreach ($a in $addrs) {"^
" $ifAlias = (Get-NetAdapter -InterfaceIndex $a.InterfaceIndex -ErrorAction SilentlyContinue).Name;"^
" if (-not $ifAlias) { $ifAlias = 'Interface #' + $a.InterfaceIndex };"^
" $zoneId = $a.InterfaceIndex;"^
" Write-Host (' {0,-25} {1,-45} %%{2}' -f $ifAlias, $a.IPAddress, $zoneId)"^
"};"^
""^
"Write-Host (' ' + '-' * 80)"
pause
endlocal
WMIC's IPAddress property returns a comma-separated array inside curly braces (e.g., {"192.168.1.5","fe80::1a2b..."}). Parsing this reliably in Batch is nearly impossible, the braces, quotes, and commas all conflict with Batch's special characters. PowerShell returns structured objects that can be filtered cleanly.
Method 3: Quick One-Line Extraction
For scripts that just need the address in a variable without detailed output.
@echo off
setlocal
set "IPV6="
:: Extract only fe80: addresses in Preferred state
for /f "delims=" %%a in ('powershell -NoProfile -Command ^
"(Get-NetIPAddress -AddressFamily IPv6 -ErrorAction SilentlyContinue | Where-Object { $_.IPAddress -like 'fe80::*' -and $_.AddressState -eq 'Preferred' } | Select-Object -First 1).IPAddress"') do set "IPV6=%%a"
if not defined IPV6 (
echo [ERROR] No Link-Local IPv6 address found.
) else (
echo Link-Local IPv6: %IPV6%
)
pause
endlocal
Method 4: Full IPv6 Audit (All Address Types)
For a complete picture of your machine's IPv6 configuration, including global, link-local, and temporary addresses.
@echo off
setlocal
echo [AUDIT] Complete IPv6 Address Report
echo %COMPUTERNAME% - %date% %time%
echo.
powershell -NoProfile -Command ^
"$all = Get-NetIPAddress -AddressFamily IPv6 -ErrorAction SilentlyContinue;"^
"if (-not $all) { Write-Host '[ERROR] No IPv6 addresses found.'; exit 1 };"^
""^
"$linkLocal = $all | Where-Object { $_.IPAddress -like 'fe80::*' };"^
"$global = $all | Where-Object { $_.IPAddress -match '^2[0-9a-f]{3}:' };"^
"$loopback = $all | Where-Object { $_.IPAddress -eq '::1' };"^
"$temporary = $all | Where-Object { $_.IPAddress -like 'fd*' -or ($_.SuffixOrigin -eq 'Random') };"^
""^
"Write-Host ' === LINK-LOCAL (fe80::) ===';"^
"if ($linkLocal) {"^
" foreach ($a in $linkLocal) {"^
" $if = (Get-NetAdapter -InterfaceIndex $a.InterfaceIndex -EA SilentlyContinue).Name;"^
" Write-Host (' {0,-20} {1}' -f $if, $a.IPAddress)"^
" }"^
"} else { Write-Host ' None found' };"^
""^
"Write-Host '';"^
"Write-Host ' === GLOBAL (Routable) ===';"^
"if ($global) {"^
" foreach ($a in $global) {"^
" $if = (Get-NetAdapter -InterfaceIndex $a.InterfaceIndex -EA SilentlyContinue).Name;"^
" $state = $a.AddressState;"^
" Write-Host (' {0,-20} {1} [{2}]' -f $if, $a.IPAddress, $state)"^
" }"^
"} else { Write-Host ' None - ISP may not support IPv6' };"^
""^
"Write-Host '';"^
"Write-Host ' === TEMPORARY (Privacy) ===';"^
"if ($temporary) {"^
" foreach ($a in $temporary) {"^
" Write-Host (' {0} [Valid: {1}h]' -f $a.IPAddress, [math]::Round($a.ValidLifetime.TotalHours,1))"^
" }"^
"} else { Write-Host ' None active' };"^
""^
"Write-Host '';"^
"Write-Host (' Total IPv6 addresses: ' + $all.Count)"
pause
endlocal
How to Avoid Common Errors
Wrong Way: Using Colon as a Delimiter to Parse IPv6
IPv6 addresses contain colons as separators (e.g., fe80::1a2b:3c4d:5e6f:7890). Using delims=: in a FOR /F loop splits the address itself into fragments, destroying it:
:: WRONG - "tokens=2 delims=:" captures only "fe80" (before the first colon)
for /f "tokens=2 delims=:" %%a in ('ipconfig | findstr "Link-local"') do set "IPV6=%%a"
Correct Way: Use delims= (no delimiter) to capture the entire line, then extract the fe80: address with string matching:
for /f "delims=" %%L in ('ipconfig ^| findstr /i "Link-local"') do (
:: Parse the full line to find the fe80: address
)
Or use PowerShell (Methods 2–4) which returns structured data without parsing issues.
Wrong Way: Confusing Link-Local with Global IPv6
A Global IPv6 address (usually starts with 2001: or 2600:) is routable on the internet. A Link-Local address (starts with fe80:) only works on your physical cable or Wi-Fi network.
Correct Way: Always filter for the fe80: prefix if you are doing local troubleshooting. If you try to use a Link-Local address for internet communication, it will fail.
Wrong Way: Using WMIC to Parse IPv6 Arrays
WMIC returns IP addresses as a formatted array string: {"192.168.1.5","fe80::1a2b..."}. The curly braces, quotes, and commas all conflict with Batch's special characters, making reliable parsing nearly impossible.
Correct Way: Use PowerShell's Get-NetIPAddress which returns properly structured objects:
Get-NetIPAddress -AddressFamily IPv6 | Where-Object { $_.IPAddress -like 'fe80::*' }
Problem: Temporary IPv6 Addresses
Windows often creates multiple "Temporary" IPv6 addresses for privacy. These addresses change frequently and should not be used as stable identifiers.
Solution: The Link-Local address (fe80:) is permanent. It's derived from your MAC address (or generated via Stable NONCE). Use the fe80: address if you need a stable local identifier. Method 4 distinguishes between all address types clearly.
Best Practices and Rules
1. Include the Zone ID (%)
Link-Local addresses often end with a % followed by a number (e.g., fe80::1a2b:3c4d%12). This number is the Zone ID (Interface Index). You must include this ID when pinging or connecting to a Link-Local address from another machine:
ping fe80::1a2b:3c4d:5e6f:7890%%12
Note the double %%: Batch requires this to escape the percent sign in scripts.
2. Verify IPv6 Support
If your script returns no results, check if IPv6 is unchecked in your network adapter properties. Many older network guides suggest disabling it for "speed," but it is required for many modern Windows features including:
- HomeGroup / Nearby Sharing
- DirectAccess VPN
- Windows Peer Name Resolution Protocol (PNRP)
To check: ncpa.cpl → Right-click adapter → Properties → look for "Internet Protocol Version 6 (TCP/IPv6)"
3. Log for Discovery
If you are building a tool for network peer-to-peer discovery, log the Link-Local address. It is the most reliable way to identify a specific hardware NIC on a local segment without worrying about DHCP IP changes.
4. IPv6 Address Types Quick Reference
| Prefix | Type | Scope |
|---|---|---|
fe80:: | Link-Local | Local network only (auto-assigned) |
2001:, 2600:, etc. | Global Unicast | Internet-routable |
fd00:: | Unique Local | Private network (similar to IPv4 10.x.x.x) |
::1 | Loopback | This machine only (similar to 127.0.0.1) |
ff02:: | Multicast | Group communication |
5. Always Use setlocal / endlocal
Without setlocal, every variable your script creates persists in the parent shell session, causing potential conflicts when running multiple scripts in sequence.
Conclusions
Identifying your Link-Local IPv6 address is a vital step in navigating the world of modern Windows networking. By moving beyond legacy IPv4 and recognizing your machine's permanent local hardware address, you gain the ability to troubleshoot complex connectivity issues and local device discovery. This professional visibility ensures that your scripts and tools are ready for the IPv6-first future of infrastructure.