Powershell IP 地址范围

Powershell IP address range

我需要帮助我用 Powershell 编写的代码。程序应生成范围内的 IP 地址。例如从 10.4.254.250 到 10.4.255.255.

当我有相同的子网时(从 10.4.255.x 到 10.4.255.x),一切都是正确的。当我有不同的子网(从 10.4.254.250 到 10.4.255.255)时,问题就开始了。

输出无效。请试一试。谢谢你的帮助。

正确的输出应该是,10.4的ip地址。255.X从1开始。现在从250开始到255。

我需要获取从变量 $from 到变量 $to 的所有 IP 地址。当 IP 地址在同一子网时 $from = "10.4.255.1" $to = "10.4.255.1" 都是正确的。问题开始了,当不同的子网 $from = "10.4.254.250" $to = "10.4.255.255"

看下面我的代码:

$from = "10.4.254.250"
$to = "10.4.255.255"

$Ip_Adresa_Od = $from -split "\."
$Ip_Adresa_Do = $to -split "\."

foreach ($Ip_Adresa_A in $Ip_Adresa_Od[0]..$Ip_Adresa_Do[0])
{
    foreach ($Ip_Adresa_B in $Ip_Adresa_Od[1]..$Ip_Adresa_Do[1])
    {
        foreach ($Ip_Adresa_C in $Ip_Adresa_Od[2]..$Ip_Adresa_Do[2])
        {
            foreach ($Ip_Adresa_D in $Ip_Adresa_Od[3]..$Ip_Adresa_Do[3])
            {
                $Ip_Adresa_Pocitace = "$Ip_Adresa_A.$Ip_Adresa_B.$Ip_Adresa_C.$Ip_Adresa_D"
                $Ip_Adresa_Pocitace
            }
        }
    }
}

错误的输出是:

10.4.254.250
10.4.254.251
10.4.254.252
10.4.254.253
10.4.254.254
10.4.254.255
10.4.255.250
10.4.255.251
10.4.255.252
10.4.255.253
10.4.255.254
10.4.255.255

您必须将您的 IP 地址转换为整数,然后在 for 循环的每次迭代中将整数转换为字节数组:

$from = "10.4.254.250"
$to = "10.4.255.255"

$Ip_Adresa_Od = $from -split "\."
$Ip_Adresa_Do = $to -split "\."

#change endianness
[array]::Reverse($Ip_Adresa_Od)
[array]::Reverse($Ip_Adresa_Do)

#convert octets to integer
$start=[bitconverter]::ToUInt32([byte[]]$Ip_Adresa_Od,0)
$end=[bitconverter]::ToUInt32([byte[]]$Ip_Adresa_Do,0)

for ($ip=$start; $ip -lt $end; $ip++)
{ 
    #convert integer back to byte array
    $get_ip=[bitconverter]::getbytes($ip)

    #change endianness
    [array]::Reverse($get_ip)

    $new_ip=$get_ip -join "."
    $new_ip
}

使用 IP 地址和范围很复杂,如果我正在使用的 program/software 已经做到了,我会尽量避免这样做。这是我前段时间写的一些函数,可以将地址转换为十进制值,这样更容易操作。可能有比这更好、更精确的解决方案,但它也会 return 基于具有子网地址或 CIDR 掩码的地址的范围。它还应涵盖提到的 @vonPryz 情况,其中地址跨越 .24 CIDR 范围。

function Find-IPRange {
    <#
    .SYNOPSIS
    Determines all the IP address in a given range or subnet.
    .DESCRIPTION
    This function can evaluate a set of addresses based of the following three options:

        Range - What IP addresses are between this and that address
        Mask - What are the IP addresses given a particular IP address and mask, i.e. 24, 25.
        Subnet - What are the IP addresses given a particular IP address and subnet address, i.e 255.255.0.0, 255.255.255.192

    You have to specify an IP address to use the subnet and mask options. For the range you have to specify two addresses.
    .PARAMETER Start
    Start address of an IP range
    .PARAMETER End
    End address of an IP range
    .PARAMETER IP
    Any valid ip address
    .PARAMETER Subnet
    A valid Subnet IP address i.e. 255.255.255.0, 255.255.0.0
    .PARAMETER Mask
    A valid net mask from 0 to 32
    .EXAMPLE
    Find-IPRange -IP 192.168.0.4 -mask 30
    .EXAMPLE
    Find-IPRange -Start 192.168.1.250 -End 192.168.2.5
    .EXAMPLE
    Find-IPRange -IP 10.100.100.10 -Subnet 255.255.255.240
    #>
    [CmdletBinding(DefaultParameterSetName = "Range")]
    Param (
        [Parameter(Mandatory = $true, ParameterSetName = "Range")]
        [System.Net.IPAddress]
        $Start,

        [Parameter(Mandatory = $true, ParameterSetName = "Range")]
        [System.Net.IPAddress]
        $End,

        [Parameter(Mandatory = $true, ParameterSetName = "Mask")]
        [Parameter(Mandatory = $true, ParameterSetName = "Subnet")]
        [System.Net.IPAddress]
        $IP,

        [Parameter(Mandatory = $true, ParameterSetName = "Subnet")]
        [System.Net.IPAddress]
        $Subnet,

        [Parameter(Mandatory = $true, ParameterSetName = "Mask")]
        [ValidateRange(0, 32)]
        [System.Int32]
        $Mask,

        [Parameter(ParameterSetName = "Mask")]
        [Parameter(ParameterSetName = "Subnet")]
        [System.Management.Automation.SwitchParameter]
        $ReturnRange
    )
    Begin {
        # If the user specifies a mask, then convert it to a subnet ip address
        if ($Mask) {
            $Binary = ("1" * $Mask) + ("0" * (32 - $Mask))
            $Decimal = [System.Convert]::ToInt64($Binary, 2)
            [System.Net.IPAddress]$Subnet = ConvertFrom-IntToIP -Decimal $Decimal
        }
    }
    Process {
        # If we're looking at a subnet, we need to establish the start address and the broadcast address for it. We're using bitwise operators to do this.
        if ($PSCmdlet.ParameterSetName -ne "Range") {
            # Compare bits where both are a match using the bitwise AND operator
            [System.Net.IPAddress]$SubnetAddr = $Subnet.Address -band $IP.Address

            # Flip the subnet mask i.e. 0.0.0.255 for 255.255.255.0 by using the bitwise XOR operator and then compare against a bitwise OR operator
            [System.Net.IPAddress]$Broadcast = ([System.Net.IPAddress]'255.255.255.255').Address -bxor $Subnet.Address -bor $SubnetAddr.Address

            # Return the start and end of a subnet only if requested
            if ($ReturnRange) { return $SubnetAddr, $Broadcast }

            # Convert the start and end of the ranges to integers
            $RangeStart = ConvertFrom-IPToInt -ip $SubnetAddr.IPAddressToString
            $RangeEnd = ConvertFrom-IPToInt -ip $Broadcast.IPAddressToString
        }
        else {
            $RangeStart = ConvertFrom-IPToInt -ip $Start.IPAddressToString
            $RangeEnd = ConvertFrom-IPToInt -ip $End.IPAddressToString
        }

        # Loop through the points between the start and end of the ranges and convert them back to IP addresses
        for ($Addr = $RangeStart; $Addr -le $RangeEnd; $Addr ++) { ConvertFrom-IntToIP -Decimal $Addr }
    }
    End {
    }
}

function ConvertFrom-IPToInt {
    <#
    .SYNOPSIS
    Converts an IP address to an Int64 value.
    .DESCRIPTION
    Converts an IP address to an Int64 value.
    .PARAMETER IP
    A valid IP address to be converted to an integer
    .EXAMPLE
    ConvertFrom-IPToInt -IP 192.168.0.1
    #>
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)]
        [System.Net.IPAddress]
        $IP
    )
    Begin {
    }
    Process {
        # Split the IP address in to octets
        $Octets = $IP -split "\."

        # Multiply the octets based on the maximum number of addresses each octet provides.
        [System.Int64]$Decimal = ([System.Int32]$Octets[0] * [System.Math]::Pow(256, 3)) +
            ([System.Int32]$Octets[1] * [System.Math]::Pow(256, 2)) +
            ([System.Int32]$Octets[2] * 256) +
            ([System.Int32]$Octets[3])
    }
    End {
        # Return the int64 value
        $Decimal
    }
}

function ConvertFrom-IntToIP {
    <#
    .SYNOPSIS
    Converts an Int64 value to an IP address.
    .DESCRIPTION
    Converts an Int64 value to an IP address.
    .PARAMETER Decimal
    A decimal value for the IP Address to be converted
    .EXAMPLE
    ConvertFrom-IntToIP -Decimal 3232235521
    #>
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)]
        [System.Int64]
        $Decimal
    )
    Begin {
        # Initialise an array for the octets
        $Octets = @()
    }
    Process {
        # Work out first octet by dividing by the total number of addresses.
        $Octets += [System.String]([System.Math]::Truncate($Decimal / [System.Math]::Pow(256, 3)))

        # Work out second octet by the modulus of the first octets total number of addresses divided by the total number of address available for a class B subnet.
        $Octets += [System.String]([System.Math]::Truncate(($Decimal % [System.Math]::Pow(256, 3)) / [System.Math]::Pow(256, 2)))

        # Work out third octet by the modulus of the second octets total number of addresses divided by the total number of address available for a class C subnet.
        $Octets += [System.String]([System.Math]::Truncate(($Decimal % [System.Math]::Pow(256, 2)) / 256))

        # Work out fourth octet by the modulus of the third octets total number of addresses.
        $Octets += [System.String]([System.Math]::Truncate($Decimal % 256))

        # Join the strings to form the IP address
        [System.Net.IPAddress]$IP = $Octets -join "."
    }
    End {
        # Return the ip address object
        $IP.IPAddressToString
    }
}

免责声明:我不是网络工程师,所以请随时提出有关地址与整数和返回地址转换方式的任何更改。此功能也未经过任何单元测试,因此可能存在无法使用的情况。

示例输出:

Find-IPRange -Start 10.4.254.250 -End 10.4.255.255
10.4.254.250
10.4.254.251
10.4.254.252
10.4.254.253
10.4.254.254
10.4.254.255
10.4.255.0
10.4.255.1
10.4.255.2
...truncated
10.4.255.249
10.4.255.250
10.4.255.251
10.4.255.252
10.4.255.253
10.4.255.254
10.4.255.255

其他用途:

Find-IPRange -IP 192.168.0.4 -Mask 28
192.168.0.0
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7
192.168.0.8
192.168.0.9
192.168.0.10
192.168.0.11
192.168.0.12
192.168.0.13
192.168.0.14
192.168.0.15

Find-IPRange -IP 192.168.0.4 -Subnet 255.255.255.252
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7

I hope I understand your question. I believe you would like to restart the counter on the 4th octet back to 1 once the 3rd octet iterates from 254 to 255? There's probably a better way to do this but for now hopefully this works. I've added an if statement that resets the range once the final 10.4.254.255 ip is reached. This will allow your loop to include the 10.4.255.x range starting from 1 in the 4th octet until 255 is reached. The while loop condition will be set to false once the final 10.4.255.255 IP is reached and exit. I hope this helps and provides the desired result.

$from = "10.4.254.250"
$to = "10.4.254.255"

$Ip_Adresa_Od = $from -split "\."
$Ip_Adresa_Do = $to -split "\."
$run = "true";

while($run -eq "true")
{

   if($Ip_Adresa_Pocitace -eq "10.4.254.255")
   {
    
            $from = "10.4.255.1"
            $to = "10.4.255.255"

            $Ip_Adresa_Od = $from -split "\."
            $Ip_Adresa_Do = $to -split "\."

    }

    foreach ($Ip_Adresa_C in $Ip_Adresa_Od[2]..$Ip_Adresa_Do[2])
    {
        foreach ($Ip_Adresa_D in $Ip_Adresa_Od[3]..$Ip_Adresa_Do[3])
        {
            $Ip_Adresa_Pocitace = "10.4.$Ip_Adresa_C.$Ip_Adresa_D"
            $Ip_Adresa_Pocitace
   
            if($Ip_Adresa_Pocitace -eq "10.4.255.255")
            {
                $run = "false";
            }
        }
    }
}

Results:
10.4.254.250
10.4.254.251
10.4.254.252
10.4.254.253
10.4.254.254
10.4.254.255
10.4.255.1
10.4.255.2
10.4.255.3
...
10.4.255.249
10.4.255.250
10.4.255.251
10.4.255.252
10.4.255.253
10.4.255.254
10.4.255.255

Solution w/ new parameters.

# Orininal Parameters
# $from = "10.4.254.250"
# $to = "10.4.254.255"
$from = "10.4.253.250" 
$to = "10.4.253.255"

$Ip_Adresa_Od = $from -split "\."
$Ip_Adresa_Do = $to -split "\."
$run = "true";

while($run -eq "true")
{

   if($Ip_Adresa_Pocitace -eq "10.4.253.255")
   {
         # Orininal Parameters   
         #   $from = "10.4.255.1"
         #  $to = "10.4.255.255"

         $from = "10.4.254.1" 
         $to = "10.4.254.255"
          $end = $to
            $Ip_Adresa_Od = $from -split "\."
            $Ip_Adresa_Do = $to -split "\."

    }

    foreach ($Ip_Adresa_C in $Ip_Adresa_Od[2]..$Ip_Adresa_Do[2])
    {
        foreach ($Ip_Adresa_D in $Ip_Adresa_Od[3]..$Ip_Adresa_Do[3])
        {
            $Ip_Adresa_Pocitace = "10.4.$Ip_Adresa_C.$Ip_Adresa_D"
            $Ip_Adresa_Pocitace
   
            if($Ip_Adresa_Pocitace -eq $end)
            {
                $run = "false";
            }
        }
    }
}

Results:
10.4.253.250
10.4.253.251
10.4.253.252
10.4.253.253
10.4.253.254
10.4.253.255
10.4.254.1
10.4.254.2
10.4.254.3
...
10.4.254.253
10.4.254.254
10.4.254.255