Skip to content

Instantly share code, notes, and snippets.

@stknohg
Last active October 26, 2017 10:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stknohg/711293bbfa69fd2499b3 to your computer and use it in GitHub Desktop.
Save stknohg/711293bbfa69fd2499b3 to your computer and use it in GitHub Desktop.
PowerShellでipcalcっぽいことをするスクリプト
<#
.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