Last active
October 26, 2017 10:24
-
-
Save stknohg/711293bbfa69fd2499b3 to your computer and use it in GitHub Desktop.
PowerShellでipcalcっぽいことをするスクリプト
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
IPアドレスからサブネットマスク、ネットワークアドレス、ブロードキャストアドレスを計算します。 | |
ipcalcコマンドと同等の機能になりますが、IPV4のみに対応しています。 | |
.DESCRIPTION | |
.EXAMPLE | |
Calculate-IPAddress -CalcType Subnet,Broadcast,Network -Address 192.168.123.45/21 | |
Calculate-IPAddress -CalcType Prefix,Broadcast,Network -Address 192.168.123.45 255.255.254.0 | |
#> | |
Function Calculate-IPAddress() { | |
[OutputType('Collections.Hashtable')] | |
[cmdletbinding()] | |
param( | |
[Parameter(Mandatory=$true, Position=0, HelpMessage='計算対象を選びます。SubnetとPrefixを同時に指定することは出来ません。')] | |
[ValidateSet('Subnet', 'Prefix', 'Network', 'Broadcast', 'Hostname')] | |
$CalcType, | |
[Parameter(Mandatory=$true, Position=1, HelpMessage='IPアドレスを指定します。CalcTypeがSubnetの場合はCIDR形式でサブネットマスク長を指定してください。')] | |
[string]$Address, | |
[Parameter(Mandatory=$false, Position=2, HelpMessage='サブネットマスクを指定します。CalcTypeがPrefixの場合に指定してください。')] | |
[string]$Subnet | |
) | |
$MSG_SELECT_PREFIX = "サブネットマスクのPrefixを指定してください。" | |
$MSG_DONT_SELECT_PREFIX = "サブネットマスクのPrefixは指定しないでください。" | |
$MSG_INVALID_IP_ADDRESS = "IPアドレスの指定が正しくありません。({0})" | |
$MSG_INVALID_SUBNET_LEN = "サブネットマスクの桁数が正しくありません。({0})" | |
$MSG_INVALID_SUBNETMASK = "サブネットマスクの指定が正しくありません。({0})" | |
$MSG_UNKNOWN_HOSTNAME = "IPアドレス({0})のホスト名が見つかりません。" | |
# IPアドレスの検証 | |
$SubnetLength = 0; | |
$Items = $Address.Split("/") | |
switch( $Items.Count ) | |
{ | |
1 { | |
if( $CalcType -contains 'Subnet' ){ | |
Write-Error $MSG_SELECT_PREFIX | |
return; | |
} | |
} | |
2 { | |
if( $CalcType -contains 'Prefix' ){ | |
Write-Error $MSG_DONT_SELECT_PREFIX | |
return; | |
} | |
$Address = $Items[0]; | |
if( !( [Int]::TryParse($Items[1], [ref]$null) ) ){ | |
Write-Error ( $MSG_INVALID_SUBNET_LEN -f $Items[1] ); | |
return; | |
} | |
if( $Items[1] -le 0 -or $Items[1] -gt 32 ){ | |
Write-Error ( $MSG_INVALID_SUBNET_LEN -f $Items[1] ); | |
return; | |
} | |
$SubnetLength = $Items[1] | |
} | |
default { | |
Write-Error ( $MSG_INVALID_IP_ADDRESS -F $Address); | |
return; | |
} | |
} | |
$ParsedIPAddress = $null; | |
if( !( [Net.IPAddress]::TryParse($Address, [ref]$ParsedIPAddress) ) ) | |
{ | |
Write-Error ( $MSG_INVALID_IP_ADDRESS -F $Address); | |
return; | |
} | |
# IPV4のみサポート | |
if( $ParsedIPAddress.AddressFamily -ne [Net.Sockets.AddressFamily]::InterNetwork ) | |
{ | |
Write-Error ( $MSG_INVALID_SUBNETMASK -F $Address); | |
return; | |
} | |
$ParsedIPBytes = $ParsedIPAddress.GetAddressBytes(); | |
Write-Verbose ("IP Address : {0}" -f $ParsedIPAddress) | |
# サブネットマスクの検証 | |
# 真面目にBit計算するのがめんどうだったので全パターン配列にぶっこんでみる | |
# TODO : IPV6に対応させる気が出たら真面目にやる。 | |
$SubnetArray = @( | |
"0.0.0.0" | |
,"128.0.0.0" | |
,"192.0.0.0" | |
,"224.0.0.0" | |
,"240.0.0.0" | |
,"248.0.0.0" | |
,"252.0.0.0" | |
,"254.0.0.0" | |
,"255.0.0.0" | |
,"255.128.0.0" | |
,"255.192.0.0" | |
,"255.224.0.0" | |
,"255.240.0.0" | |
,"255.248.0.0" | |
,"255.252.0.0" | |
,"255.254.0.0" | |
,"255.255.0.0" | |
,"255.255.128.0" | |
,"255.255.192.0" | |
,"255.255.224.0" | |
,"255.255.240.0" | |
,"255.255.248.0" | |
,"255.255.252.0" | |
,"255.255.254.0" | |
,"255.255.255.0" | |
,"255.255.255.128" | |
,"255.255.255.192" | |
,"255.255.255.224" | |
,"255.255.255.240" | |
,"255.255.255.248" | |
,"255.255.255.252" | |
,"255.255.255.254" | |
,"255.255.255.255" | |
) | |
if( $SubnetLength -gt 0 ) | |
{ | |
$Subnet = $SubnetArray[$SubnetLength]; | |
} | |
if( [Array]::IndexOf($SubnetArray, $Subnet) -le 0 ){ | |
Write-Error ( $MSG_INVALID_SUBNETMASK -f $Subnet ); | |
return; | |
} | |
$ParsedSubnet = $null; | |
if( !( [Net.IPAddress]::TryParse($Subnet, [ref]$ParsedSubnet) ) ) | |
{ | |
Write-Error ( $MSG_INVALID_SUBNETMASK -F $Address); | |
return; | |
} | |
$ParsedSubnetBytes = $ParsedSubnet.GetAddressBytes(); | |
Write-Verbose ("Argument Subnetmask Prefix : {0}" -f $SubnetLength) | |
Write-Verbose ("Subnetmask : {0}" -f $ParsedSubnet) | |
$RetValue = @{} | |
# サブネットマスクの計算 | |
if( $CalcType -contains 'Subnet' ){ | |
$RetValue.Add("SubnetMask", $Subnet); | |
} | |
# Prefixの計算 | |
if( $SubnetLength -eq 0 ){ | |
$SubnetLength = [Array]::IndexOf($SubnetArray, $Subnet); | |
Write-Verbose ("Calculated Subnetmask Prefix : {0}" -f $SubnetLength) | |
} | |
if( $CalcType -contains 'Prefix' ){ | |
$RetValue.Add("Prefix", $SubnetLength); | |
} | |
# ネットワークアドレスの計算 | |
if( $CalcType -contains 'Network' ){ | |
$WorksAddressBytes = New-Object Byte[] 4 | |
for($i = 0; $i -lt $WorksAddressBytes.Length; $i++) | |
{ | |
$WorksAddressBytes[$i] = ($ParsedIPBytes[$i] -band $ParsedSubnetBytes[$i]) | |
Write-Verbose ("NetworkAddress {0} octet : {1} & {2} -> {3}" -f ($i + 1), $ParsedIPBytes[$i], $ParsedSubnetBytes[$i], $WorksAddressBytes[$i]) | |
} | |
$RetValue.Add("NetworkAddress", ($WorksAddressBytes -join ".")); | |
} | |
# ブロードキャストアドレスの計算 | |
if( $CalcType -contains 'Broadcast' ){ | |
$BroadcastAddresBytes = New-Object Byte[] 4 | |
for($i = 0; $i -lt $BroadcastAddresBytes.Length; $i++) | |
{ | |
$BroadcastAddresBytes[$i] = ($ParsedIPBytes[$i] -bor ($ParsedSubnetBytes[$i] -bxor 255)) | |
Write-Verbose ("BroadcastAddress {0} octet : {1} | ( {2} ^ 255 ) -> {3}" -f ($i + 1), $ParsedIPBytes[$i], $ParsedSubnetBytes[$i], $BroadcastAddresBytes[$i]) | |
} | |
$RetValue.Add("BroadcastAddress", ($BroadcastAddresBytes -join ".")); | |
} | |
# ホスト名を取得 | |
if( $CalcType -contains 'Hostname' ){ | |
$Hostname = "" | |
try{ | |
$Hostname = [Net.Dns]::GetHostEntry($ParsedIPAddress).HostName | |
}catch{ | |
Write-Warning ( $MSG_UNKNOWN_HOSTNAME -f $ParsedIPAddress ) | |
} | |
$RetValue.Add("Hostname", $Hostname); | |
} | |
return $RetValue; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment