Powershell IP 地址范围

问题描述 投票:0回答:4

我需要帮助我编写用 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)时,问题就开始了。

输出无效。请尝试一下。谢谢您的帮助。

正确的输出应该是,IP 地址是 10.4.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
powershell ip
4个回答
2
投票

使用 IP 地址和范围很复杂,如果我正在使用的程序/软件已经这样做了,我会尽量避免这样做。以下是我不久前编写的一些函数,它们将地址转换为十进制值,更易于操作。可能有比这更好、更精确的解决方案,但它也会返回基于带有子网地址或 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

0
投票

您必须将 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
}

0
投票

我希望我理解你的问题。我相信一旦第 3 个八位位组从 254 迭代到 255,您想将第 4 个八位位组的计数器重新启动到 1 吗?可能有更好的方法来做到这一点,但目前希望这可行。我添加了一个 if 语句,一旦达到最终 10.4.254.255 ip,该语句就会重置范围。这将允许您的循环包含从第 4 个八位字节中的 1 开始直到达到 255 的 10.4.255.x 范围。一旦到达最终的 10.4.255.255 IP 并退出,while 循环条件将设置为 false。 我希望这会有所帮助并提供所需的结果。

$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";
            }
        }
    }
}

结果:
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

带有新参数的解决方案。

# 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";
            }
        }
    }
}

结果:
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


0
投票

二进制方法要快得多,“FastPing”就是一个很好的例子。请参阅“GetNetworkRange”(需要脚本中的 ConvertToNetwork 和 ConvertToDeicmal)。您可以将这 3 个函数复制到 ISE 会话中来使用它。

我编写了一个字符串方法来生成列表,我相信它是准确的(希望得到反馈 - 模块Test-PowerPing)。地址生成方法是“Get-PowerIPRange”。

我正在努力添加注释,但循环复杂性会根据开始/结束八位字节“a.b.c.d”的差异而变化。如果开始/结束 a.b.c 没有变化(全部相等),您只需修改最后一个八位字节“d”(最多 256 个地址):

$range = 0..255
$range | foreach-object {'a.b.c.'+"$_"}

如果第三个八位字节“c”存在差异,循环复杂度将会增加。上述逻辑将应用于“c”中的每个更改。您可以根据需要循环,我选择使用数组列表来管理添加列表等。

$range = 0..255
$base = 'a.b.' + '0'
$range | foreach-object {$base+ ".$_"}
$base = 'a.b.' + '1'
$range | foreach-object {$base+ ".$_"}

但是要拥有可以直接使用的东西,您必须考虑各种开始/结束场景。我们不能为每个范围都设置 0..255,我们需要添加逻辑以从修改“c”和“d”的循环跳转到仅修改最终条目的“d”等。

© www.soinside.com 2019 - 2024. All rights reserved.