1

I have CSV containing IP number's related to IPv6 and I am reading and converting them to IPv6 ip address which is failing at the moment.

I am using below code but getting error:

Cannot convert value "281470698520576" to type "System.Net.IPAddress". Error: "Specified argument was out of the range of valid values.

function Convert-NumberToIP
{
    param(
        [Parameter(Mandatory=$true)][string]$number
    )

    [Int64] $numberInt = 0
    
    if([Int64]::TryParse($number, [ref]$numberInt))
    {
        if(($numberInt -ge 0) -and ($numberInt -le 0xFFFFFFFFl))
        {
            #([IPAddress] $numberInt).ToString()
            $ipBytes = ([IPAddress]$numberInt).GetAddressBytes()
            [array]::Reverse($ipBytes)
            ([IPAddress]$ipBytes).IPAddressToString
        }
    }
}

$startIP = Convert-NumberToIP -number '281470698520576'
$endIP = Convert-NumberToIP -number '281470698520580'
Naveen Kumar
  • 1,266
  • 1
  • 21
  • 50

2 Answers2

4

To use a 128bit integer in PowerShell you can leverage .NET System.Numerics.BigInteger class. Like this:

$ipv6Decimal = [System.Numerics.BigInteger]::Parse($number)

Then you can convert the BigInt to a byte array using ToByteArray(). However the resulting array needs to be "padded" to 16 bytes and reversed (Host vs Network order).

This works for me:

function Convert-NumberToIPv6
{
    param(
        [Parameter(Mandatory=$true)][string]$number
    )
     
    $ipv6Decimal  = [System.Numerics.BigInteger]::Parse($number)
    $ipv6Bytes = $ipv6Decimal.ToByteArray()
    # pad to 16 bytes
    [Array]::Resize([ref]$ipv6Bytes, 16)

    # reverse the bytes
    [Array]::Reverse($ipv6Bytes)
    
    # provide a scope identifier to prevent "cannot find overload error"
    $ipAddress = New-Object Net.IPAddress($ipv6Bytes, 0)
    $ipAddress.ToString()
}

So the output for: Convert-NumberToIPv6 -number '281470698520576' is ::ffff:1.0.0.0

Remko
  • 7,214
  • 2
  • 32
  • 52
  • Nice! For improved error handling, you might want to check `$ipv6Bytes.Count -le 16`, instead of just trimming to 16 bytes. – zett42 Feb 22 '23 at 16:49
  • @Remko When I am converting the decimal to ipv6 `Convert-NumberToIPv6 -number '281470698520576' is ::ffff:1.0.0.0` it's actually ipv4 mapped ipv6 address any idea how to separate this with actual ipv6 – Naveen Kumar Apr 21 '23 at 06:59
0

Using PowerShell 7+, here is a possible implementation that works similar to the function in your question in that invalid input will be detected and doesn't cause an exception. In this case the function returns "nothing", which converts to $false in a boolean context.

If you need compatibility with Windows PowerShell (5.x), have a look at this answer.

function Convert-NumberToIPv6
{
    param(
        [Parameter(Mandatory)] [string] $number
    )

    [Numerics.BigInteger] $bigInt = 0
    if( [Numerics.BigInteger]::TryParse( $number, [ref] $bigInt ) ) {
        # Check that input is in the range of an unsigned 128 bit number
        if( $bigInt.Sign -ge 0 -and $bigInt.GetBitLength() -le 128 ) {
            $bytes = $bigInt.ToByteArray($true, $true)  # unsigned, big-endian
            $zeros = @(0) * (16 - $bytes.Length)        # zeros to preprend to ensure 128 bit length
            $bytes = [byte[]] ($zeros + $bytes)         # prepend zeros
            ([IPAddress] $bytes).ToString()             # convert to IPAddress and then to string
        }
    }
}

Usage:

if( $ipv6 = Convert-NumberToIPv6 '281470698520576' ) {
    # Conversion successful, output the address in text form
    $ipv6   
}
else {
    "IPv6 conversion failed!"
}

Output:

::ffff:1.0.0.0
zett42
  • 25,437
  • 3
  • 35
  • 72
  • Hey @zett42 thanks could you please let me know how to convert it into cidr notation (i.e using start ipv6 and end ipv6) – Naveen Kumar Feb 22 '23 at 17:56
  • @NaveenKumar You may add [this C# code](https://stackoverflow.com/a/16263105/7571258) using `Add-Type 'INSERT-C#-CODE'`, then use it like `[IPRangeToCidr.CIDR]::Split([IPAddress]'2a01:111:f406:c00::', [IPAddress]'2a01:111:f406:c00:ffff:ffff:ffff:ffff') | ForEach ToString` which prints `2a01:111:f406:c00::/64`. – zett42 Feb 23 '23 at 09:07
  • is there any function or code in powershell instead using c# code – Naveen Kumar Feb 23 '23 at 17:12
  • @NaveenKumar I don't know any. – zett42 Feb 23 '23 at 17:17
  • thanks can we leverage the same function Get-IpSubnets with some modification mentioned in question. – Naveen Kumar Feb 23 '23 at 17:34