Skip to content

How to Get the Link-Local IPv6 Address in Batch Script

Learn how to extract your Windows Link-Local IPv6 address (starting with fe80:) using Batch scripting, including parsing ipconfig, PowerShell integration, and troubleshooting common IPv6 parsing errors.

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

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.

@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

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.

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

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.

Navigation