PowerShellでネットワークアダプタの設定変更

## Windows PowerShell の起動

スタートボタンを右クリックしてメニューから`Windows PowerShell`を選択するか、キーボードから `Windows + X` → `I` と操作すると Windows PowerShell を開くことができます。現行の設定の確認や、設定方法のヘルプの確認の多くは管理者権限無しでも行うことができます。

## Windows PowerShell (管理者) の起動

管理者ユーザでWindowsにログインした状態で、スタートボタンを右クリックしてメニューから`Windows PowerShell (管理者)`を選択するか、キーボードから `Windows + X` → `A` と操作すると Windows PowerShell (管理者) を開くことができます。実際に設定を変更して適用する場合の多くは、管理者権限が必要になります。

## まずはアダプタの名称や設定情報を確認しましょう

```powershell
Write-Host '* ネットワークアダプタの一覧';
# テーブル出力
Get-NetAdapter|Format-Table;
# リスト出力
Get-NetAdapter|Format-List;

Write-Host '* ネットワークアダプタのバインド';
# テーブル出力
Get-NetAdapterBinding|Format-Table;
# リスト出力
Get-NetAdapterBinding|Format-List;

Write-Host '* ネットワークアダプタの詳細設定';
# テーブル出力
Get-NetAdapterAdvancedProperty|Format-Table;
# リスト出力
Get-NetAdapterAdvancedProperty|Format-List;

Write-Host '* ネットワークアダプタのデバイス情報';
# テーブル出力
Get-PnpDevice|? Class -eq 'Net'|Format-Table;
# リスト出力
Get-PnpDevice|? Class -eq 'Net'|Format-List;

Write-Host '* 電源の管理 - 電力の節約のために、コンピューターでこのデバイスの電源をオフにできるようにする';
# テーブル出力
Get-CimInstance MSPower_DeviceEnable -Namespace root/WMI|Format-Table;
# リスト出力
Get-CimInstance MSPower_DeviceEnable -Namespace root/WMI|Format-List;

Write-Host '* 電源の管理 - このデバイスで、コンピューターのスタンバイ状態を解除できるようにする';
# テーブル出力
Get-CimInstance MSPower_DeviceWakeEnable -Namespace root/WMI|Format-Table;
# リスト出力
Get-CimInstance MSPower_DeviceWakeEnable -Namespace root/WMI|Format-List;

Write-Host '* 電源の管理 - Magic Packet でのみ、コンピューターのスタンバイ状態を解除できるようにする';
# テーブル出力
Get-CimInstance MSNdis_DeviceWakeOnMagicPacketOnly -Namespace root/WMI|Format-Table;
# リスト出力
Get-CimInstance MSNdis_DeviceWakeOnMagicPacketOnly -Namespace root/WMI|Format-List;

Write-Host '* ネットワークデバイスの電源管理の設定';
# リスト出力
Get-NetAdapterPowerManagement|Format-List;

Write-Host '* ネットワークインターフェースのIP設定';
# リスト出力
Get-NetIPConfiguration|Format-List;

Write-Host '* ネットワークインターフェースのIPアドレス';
# テーブル出力
Get-NetIPAddress|Format-Table
# リスト出力
Get-NetIPAddress|Format-List;

Write-Host '* ネットワークインターフェースのDNSクライアントの対向DNSサーバアドレス';
# テーブル出力
Get-DnsClientServerAddress|Format-Table;
# リスト出力
Get-DnsClientServerAddress|Format-List;
```

## 設定用のマニュアルを読みましょう

```powershell
Get-Help Disable-NetAdapter -full;
Get-Help Enable-NetAdapter -full;
Get-Help Rename-NetAdapter -full;
Get-Help Restart-NetAdapter -full;

Get-Help Set-NetAdapterAdvancedProperty -full;

Get-Help Set-NetAdapterBinding -full;
Get-Help Disable-NetAdapterBinding -full;
Get-Help Enable-NetAdapterBinding -full;

Get-Help New-NetIPAddress -full;
Get-Help Set-NetIPAddress -full;
Get-Help Remove-NetIPAddress -full;

Get-Help Set-DnsClientServerAddress -full;

Get-Help Set-CimInstance -full;
```

# レシピ例

ここでは、Intel製のネットワークアダプタが搭載された製品での設定の一例を挙げておきます。

## 設定変更レシピ

```powershell
Write-Host '* LANアダプタ(ここでは機器名が"Intel*")を "機器名 (MAC Address)" に名前変更';
Get-NetAdapter|
? InterfaceDescription -like 'Intel*'|
%{$_|Rename-NetAdapter -PassThru -ThrottleLimit 1 -ErrorAction SilentlyContinue -NewName ("{0} ({1})" -f $_.InterfaceDescription,$_.MacAddress)};
```
```powershell
Write-Host '* 有線LANアダプタ(ここでは機器名が"Intel*Gigabit*")を "Ethernet" に名前変更';
Get-NetAdapter|
? InterfaceDescription -like 'Intel*Gigabit*'|
Rename-NetAdapter -PassThru -ThrottleLimit 1 -ErrorAction SilentlyContinue -NewName 'Ethernet';
```
```powershell
Write-Host '* 無線LANアダプタ(ここでは機器名が"Intel*Wireless*")を "Wi-Fi" に名前変更';
Get-NetAdapter|
? InterfaceDescription -like 'Intel*Wireless*'|
Rename-NetAdapter -PassThru -ThrottleLimit 1 -ErrorAction SilentlyContinue -NewName 'Wi-Fi';
```
```powershell
Write-Host '* 無線LANアダプタ(ここでは機器名が"Intel*Wireless*")のローミング積極性を "4.中高" に変更(レジストリ上の設定値は3)';
Get-NetAdapterAdvancedProperty|
? InterfaceDescription -like 'Intel*Wireless*'|
? RegistryKeyword -eq 'RoamAggressiveness'|
Set-NetAdapterAdvancedProperty -PassThru -ThrottleLimit 1 -RegistryValue 3;
```

## 機能無効化レシピ

```powershell
Write-Host '* 全インターフェースの IPv6 と QoSパケットスケジューラ のバインドを無効化';
Get-NetAdapterBinding|
? ComponentID -Match 'ms_tcpip6|ms_pacer'|
Disable-NetAdapterBinding -PassThru -ThrottleLimit 1;
```
```powershell
Write-Host '* 有線・無線アダプタ(ここでは機器名が"Intel*Gigabit*"もしくは"Intel*Wireless*")の電源の管理';
Write-Host '  * 電力の節約のために、コンピューターでこのデバイスの電源をオフにできるようにする の無効化';
Get-PnpDevice|
? Class -eq 'Net'|
? Name -Match 'Intel.*Gigabit.*|Intel.*Wireless.*'|
%{
  $_|Format-List;
  Get-CimInstance MSPower_DeviceEnable -Namespace root/WMI|
  ? InstanceName -ILike "$($_.DeviceID)*"|
  %{
    $_.Enable = $false;
    $_|Set-CimInstance;
    $_|Format-List;
  }
}
```

## 機能有効化レシピ

```powershell
Write-Host '* 全インターフェースの IPv6 と QoSパケットスケジューラ のバインドを有効化';
Get-NetAdapterBinding|
? ComponentID -Match 'ms_tcpip6|ms_pacer'|
Enable-NetAdapterBinding -PassThru -ThrottleLimit 1;
```
```powershell
Write-Host '* 有線・無線アダプタ(ここでは機器名が"Intel*Gigabit*"もしくは"Intel*Wireless*")の電源の管理';
Write-Host '  * 電力の節約のために、コンピューターでこのデバイスの電源をオフにできるようにする の有効化';
Get-PnpDevice|
? Class -eq 'Net'|
? Name -Match 'Intel.*Gigabit.*|Intel.*Wireless.*'|
%{
  $_|Format-List;
  Get-CimInstance MSPower_DeviceEnable -Namespace root/WMI|
  ? InstanceName -ILike "$($_.DeviceID)*"|
  %{
    $_.Enable = $true;
    $_|Set-CimInstance;
    $_|Format-List;
  }
}
```

## IPアドレスの変更レシピ

注意点が2点。詳しくは後述の `NicIpAddr.psm1` の中身を確認して下さい。

- LANケーブルを繋げていないなど、リンクアップしていない状態のネットワークインターフェースのDHCP設定を `Set-NetIPInterface -Dhcp Disabled` で無効化できない、という事象が見受けられました。この回避策として、Tcpipサービスのレジストリキーを直接操作し、DHCP機能を無効化させています。
  - 参考: [serverfault - Powershell: Configure a static IP on an unplugged NIC](https://serverfault.com/questions/933630/powershell-configure-a-static-ip-on-an-unplugged-nic)
- Windows10 version 1709 (Fall Creators Update) 以降、 `Wi-Fi設定` ( `ms-settings:network-wifi` ) の `既知のネットワークの管理` ( `ms-settings:network-wifisettings` ) に `IP設定` という設定項目が追加されており、Wi-Fiの接続先によってIP設定を変更する場合はこの設定を用いることになるかと思います。この設定を変更すると、`WlanSvc` サービスによってレジストリの `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WlanSvc\Interfaces\{ (Interface GUID) }\Profiles\{ (Wlan Profile GUID) }\MetaData\` に `ProfileIpConfigurationV4` や `ProfileIpConfigurationV6` のレジストリキーが作成され、Wi-Fi接続時や、無線プロファイルのプロパティを開いた時などに参照が行われているようです。このレジストリへのアクセスの様子は、 [Windows Sysinternals - Process Monitor](https://technet.microsoft.com/ja-jp/sysinternals/processmonitor) のツールを使って観察する事が出来ましたが、特にこの仕様についての文書化もされてはいないようで、将来のWindowsの更新で特に断りなく仕様が変更される可能性がありますのでご注意ください。レジストリを直接操作する以外の方法でGUIを使わないより適切な手段があればコメント等で教えて頂ければと。
  - [フィードバックHub - WLANプロファイルの静的IP設定の公開APIの要望](https://aka.ms/AA4gnr1) の方にこの点についての要望を出してみましたので、公開APIの要望に賛同される方はこちらにもリアクション頂けると幸いです。

長くなってしまったので、モジュールを用いる形で記述しました。
以下の例は、後述するモジュールファイル `NicIpAddr.psm1` を同じディレクトリに置き、それをインポートして使うレシピになります。

```powershell
# .\NicIpAddr.psm1 のインポート
Import-Module .\NicIpAddr.psm1;

# IP設定の一覧
Get-NetAdapter|Get-NicIpConfig;

# "Gigabit|GBE|Network Connection" にマッチするインターフェースに対してDHCP有効化
Get-NetAdapter|? InterfaceDescription -Match "Gigabit|GBE|Network Connection"|Set-NicDhcp;

# "Gigabit|GBE|Network Connection" にマッチするインターフェースに対して静的IPアドレス設定
Get-NetAdapter|? InterfaceDescription -Match "Gigabit|GBR|Network Connection"|
Set-NicStaticIpAddr -IpAddress 192.168.100.10 -PrefixLength 24 -DefaultGateway 192.168.100.1 -DnsServer 192.168.100.1;

# 無線プロファイル一覧
Get-WlanProfilePlace;

# SSID "test" のIPv4設定取得
Get-WlanProfilePlace|? SSID -eq test|Get-WlanProfileStaticIPv4;

# SSID "test" のIPv6設定取得
Get-WlanProfilePlace|? SSID -eq test|Get-WlanProfileStaticIPv6;

# SSID "test" のIP設定削除
Get-WlanProfilePlace|? SSID -eq test|Remove-WlanProfileStaticIP;

# SSID "test" の静的IPv4アドレス設定
Get-WlanProfilePlace|? SSID -eq test|
Set-WlanProfileStaticIPv4 -IpAddress 192.168.100.10 -PrefixLength 24 -DefaultGateway 192.168.100.1 -DnsServer1 192.168.100.1;

# SSID "test" の静的IPv6アドレス設定
Get-WlanProfilePlace|? SSID -eq test|
Set-WlanProfileStaticIPv6 -IpAddress 2001:db8:beef::dead -PrefixLength 60 -DefaultGateway 2001:db8:beef:1::1 -DnsServer1 2001:db8:beef:1::2 -DnsServer2 2001:db8:beef:1::3

# NicIpAddr モジュールの削除
Remove-Module NicIpAddr;
```

```powershell:NicIpAddr.psm1
function Get-NicIpConfig{
<# Usage
Get-NetAdapter|? InterfaceDescription -Match "Gigabit|GBE|Network Connection"|Get-NicIpConfig;
#>
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [uint32]$InterfaceIndex
  )
  Process{
    Get-NetIPConfiguration -InterfaceIndex $InterfaceIndex|
    ForEach-Object{[PSCustomObject]@{
      InterfaceIndex = [uint32]($_.InterfaceIndex);
      InterfaceAlias = [string]($_.InterfaceAlias);
      InterfaceDescription = [string]($_.InterfaceDescription);
      "NetAdapter.Status" = [string]($_.NetAdapter.Status);
      "NetProfile.Name" = [string]($_.NetProfile.Name);
      "NetProfile.NetworkCategory" = [string]($_.NetProfile.NetworkCategory);
      IPv4Dhcp = [string]($_.NetIPv4Interface.Dhcp);
      IPv6Dhcp = [string]($_.NetIPv6Interface.Dhcp);
      IPv4Address = [string[]]($_.IPv4Address|Where-Object{$_}|ForEach-Object{"$($_.IPAddress)/$($_.PrefixLength)"});
      IPv6Address = [string[]]($_.IPv6Address|Where-Object{$_}|ForEach-Object{"$($_.IPAddress)/$($_.PrefixLength)"});
      IPv4DefaultGateway = [string[]]($_.IPv4DefaultGateway.NextHop);
      IPv6DefaultGateway = [string[]]($_.IPv6DefaultGateway.NextHop);
      DNSServer = [string[]]($_.DNSServer.ServerAddresses);
    }};
  }
}
function Set-NicDhcp{
<# Usage
Get-NetAdapter|? InterfaceDescription -Match "Gigabit|GBE|Network Connection"|Set-NicDhcp;
#>
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [uint32]$InterfaceIndex
  )
  Process{
    # disable dhcp
    ### "Tcpip"/"Tcpip6" Services EnableDHCP property set to disabled
    $ifGuid = (Get-NetAdapter -InterfaceIndex $InterfaceIndex).InterfaceGuid;
    Set-ItemProperty -Path(
      "HKLM:\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\$ifGuid",
      "HKLM:\SYSTEM\CurrentControlSet\services\Tcpip6\Parameters\Interfaces\$idGuid"
    ) -Name EnableDHCP -Value 0;
    ### "Set-NetIPInterface -Dhcp Disabled" Cmdlet cannot affect IPv4 DHCP Disconnected NIC
    Set-NetIPInterface -InterfaceIndex $InterfaceIndex -Dhcp Disabled -Confirm:$false;
    # remove ipaddr
    Remove-NetIPAddress -InterfaceIndex $InterfaceIndex -Confirm:$false;
    # remove route
    Remove-NetRoute -InterfaceIndex $InterfaceIndex -Confirm:$false;
    # remove dnsserver
    Set-DnsClientServerAddress -InterfaceIndex $InterfaceIndex -ResetServerAddresses -Confirm:$false;
    # enable dhcp
    Set-NetIPInterface -InterfaceIndex $InterfaceIndex -Dhcp Enabled -Confirm:$false;
    # get nicipconfig
    Get-NicIpConfig -InterfaceIndex $InterfaceIndex;
  }
}
function Set-NicStaticIpAddr{
<# Usage
Get-NetAdapter|? InterfaceDescription -like "*USB 3.0 to Gigabit Ethernet Adapter*")|
Set-NicStaticIpAddr -IpAddress 192.168.100.10 -PrefixLength 24 -DefaultGateway 192.168.100.1 -DnsServer 192.168.100.1;
#>
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [uint32]$InterfaceIndex,
    [string]$IpAddress,
    [byte]$PrefixLength,
    [string]$DefaultGateway,
    [string[]]$DnsServer
  )
  Process{
    # disable dhcp
    ### "Tcpip"/"Tcpip6" Services EnableDHCP property set to disabled
    $ifGuid = (Get-NetAdapter -InterfaceIndex $InterfaceIndex).InterfaceGuid;
    Set-ItemProperty -Path(
      "HKLM:\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\$ifGuid",
      "HKLM:\SYSTEM\CurrentControlSet\services\Tcpip6\Parameters\Interfaces\$ifGuid"
    ) -Name EnableDHCP -Value 0;
    ### "Set-NetIPInterface -Dhcp Disabled" Cmdlet cannot affect IPv4 DHCP Disconnected NIC
    Set-NetIPInterface -InterfaceIndex $InterfaceIndex -Dhcp Disabled -Confirm:$false;
    # remove netroute
    Remove-NetRoute -InterfaceIndex $InterfaceIndex -Confirm:$false;
    # remove dnsserver
    Set-DnsClientServerAddress -InterfaceIndex $InterfaceIndex -ResetServerAddresses -Confirm:$false;
    # remove ipaddr
    Remove-NetIPAddress -InterfaceIndex $InterfaceIndex -Confirm:$false;
    # new ipaddr
    New-NetIPAddress -InterfaceIndex $InterfaceIndex -IPAddress $IpAddress -PrefixLength $PrefixLength -DefaultGateway $DefaultGateway -Confirm:$false|Out-Host;
    # set dnsserver
    Set-DnsClientServerAddress -InterfaceIndex $InterfaceIndex -ServerAddresses $DnsServer -Confirm:$false;
    # get nicipconfig
    Get-NicIpConfig -InterfaceIndex $InterfaceIndex;
  }
}
class WlanProfIpData{
  [int]$type;
  [Net.IpAddress]$ipv4;
  [Net.IpAddress]$ipv6;
  [byte]$masklen;
  WlanProfIpData(){
    $this.type = 0;
    $this.ipv4 = "0.0.0.0";
    $this.ipv6 = "::";
    $this.masklen = 0;
  }
  [byte[]]GetBytes(){
    $r = $();
    $r += [BitConverter]::GetBytes($this.type);
    $r += $this.ipv4.MapToIPv4().GetAddressBytes();
    $r += $this.ipv6.MapToIPv6().GetAddressBytes();
    $r += @([byte]0) * 104;
    return $r;
  }
  [byte[]]GetCidrBytes(){
    $r = $this.GetBytes();
    $r += @($this.masklen);
    $r += @([byte]0) * 7;
    return $r;
  }
  [string]ToString(){
    switch ($this.type){
      2{
        if($this.masklen -gt 0){
          return "{0}/{1}" -f $this.ipv4,$this.masklen;
        } else{
          return $($this.ipv4);
        }
      }
      23{
        if($this.masklen -gt 0){
          return "{0}/{1}" -f $this.ipv6,$this.masklen;
        } else{
          return $($this.ipv6);
        }
      }
    }
    return [void]$null;
  }
  [Net.IpAddress]GetAddr(){
    switch ($this.type){
      2{ return $this.ipv4.MapToIPv4(); }
      23{ return $this.ipv6.MapToIPv6(); }
    }
    return [void]$null;
  }
  static [WlanProfIpData]Parse([byte[]]$bytes){
    $r = New-Object WlanProfIPData;
    $r.type = [BitConverter]::ToInt32($bytes, 0);
    $r.ipv4 = [byte[]]($bytes[4..7]);
    $r.ipv6 = [byte[]]($bytes[8..23]);
    return $r;
  }
  static [WlanProfIpData]CidrParse([byte[]]$bytes){
    $r = New-Object WlanProfIPData;
    $r.type = [BitConverter]::ToInt32($bytes, 0);
    $r.ipv4 = [byte[]]($bytes[4..7]);
    $r.ipv6 = [byte[]]($bytes[8..23]);
    $r.masklen = $bytes[128];
    return $r;
  }
  static [WlanProfIpData]V4([Net.IpAddress]$addr, [byte]$masklen){
    $r = New-Object WlanProfIPData;
    $r.type = 2;
    $r.ipv4 = $addr.MapToIPv4();
    $r.ipv6 = "::";
    $r.masklen = $masklen;
    return $r;
  }
  static [WlanProfIpData]V6([Net.IpAddress]$addr, [byte]$masklen){
    $r = New-Object WlanProfIPData;
    $r.type = 23;
    $r.ipv4 = "0.0.0.0";
    $r.ipv6 = $addr.MapToIPv6();
    $r.masklen = $masklen;
    return $r;
  }
}
class WlanProfIpConfigData{
  [WlanProfIpData[]]$ipaddr;
  [WlanProfIpData[]]$gateway;
  [WlanProfIpData[]]$dnsserver;
  WlanProfIpConfigData(){
    $this.ipaddr = @();
    $this.gateway = @();
    $this.dnsserver = @();
  }
  [byte[]] GetBytes(){
    $len_ipaddr = $this.ipaddr.Length;
    $len_gateway = $this.gateway.Length;
    $len_dnsserver = $this.dnsserver.Length;
    $off_ipaddr = 28;
    $off_gateway = 136 * $len_ipaddr + $off_ipaddr;
    $off_dnsserver = 136 * $len_gateway + $off_gateway;
    if($len_ipaddr -eq 0){ $off_ipaddr = 0; }
    if($len_gateway -eq 0){ $off_gateway = 0; }
    if($len_dnsserver -eq 0){ $off_dnsserver = 0; }
    $r = [BitConverter]::GetBytes([int]0);
    $r += [BitConverter]::GetBytes($len_ipaddr);
    $r += [BitConverter]::GetBytes($off_ipaddr);
    $r += [BitConverter]::GetBytes($len_gateway);
    $r += [BitConverter]::GetBytes($off_gateway);
    $r += [BitConverter]::GetBytes($len_dnsserver);
    $r += [BitConverter]::GetBytes($off_dnsserver);
    for($i = 0; $i -lt $len_ipaddr; $i++){
      $r += $this.ipaddr[$i].GetCidrBytes();
    }
    for($i = 0; $i -lt $len_gateway; $i++){
      $r += $this.gateway[$i].GetCidrBytes();
    }
    for($i = 0; $i -lt $len_dnsserver; $i++){
      $r += $this.dnsserver[$i].GetBytes();
    }
    return $r;
  }
  static [WlanProfIpConfigData] Parse([byte[]]$bytes){
    $r = New-Object WlanProfIpConfigData;
    if(-not $bytes){ return $r; }
    $len_ipaddr    = [BitConverter]::ToInt32($bytes,  4);
    $off_ipaddr    = [BitConverter]::ToInt32($bytes,  8);
    $len_gateway   = [BitConverter]::ToInt32($bytes, 12);
    $off_gateway   = [BitConverter]::ToInt32($bytes, 16);
    $len_dnsserver = [BitConverter]::ToInt32($bytes, 20);
    $off_dnsserver = [BitConverter]::ToInt32($bytes, 24);
    for($i = 0; $i -lt $len_ipaddr; $i++){
      $off = $i * 136 + $off_ipaddr;
      $r.ipaddr += ([WlanProfIpData]::CidrParse($bytes[$off..($off+135)]));
    }
    for($i = 0; $i -lt $len_gateway; $i++){
      $off = $i * 136 + $off_gateway;
      $r.gateway += [WlanProfIpData]::CidrParse($bytes[$off..($off+135)]);
    }
    for($i = 0; $i -lt $len_dnsserver; $i++){
      $off = $i * 128 + $off_dnsserver;
      $r.dnsserver += [WlanProfIpData]::Parse($bytes[$off..($off+127)]);
    }
    return $r;
  }
  static [WlanProfIpConfigData]V4(
    [Net.IPAddress]$ipaddr,
    [byte]$masklen,
    [Net.IPAddress]$gateway,
    [Net.IPAddress]$dnsserver1,
    [Net.IPAddress]$dnsserver2
  ){
    $r = New-Object WlanProfIpConfigData;
    $r.ipaddr = @($ipaddr)|
      Where-Object{$_}|
      ForEach-Object{[WlanProfIpData]::V4($_, $masklen)};        
    $r.gateway = @($gateway)|
      Where-Object{$_}|
      ForEach-Object{[WlanProfIpData]::V4($_, 0)};
    $r.dnsserver = @($dnsserver1,$dnsserver2)|
      Where-Object{$_}|
      ForEach-Object{[WlanProfIpData]::V4($_, 0)};
    return $r;
  }
  static [WlanProfIpConfigData]V6(
    [Net.IPAddress]$ipaddr,
    [byte]$masklen,
    [Net.IPAddress]$gateway,
    [Net.IPAddress]$dnsserver1,
    [Net.IPAddress]$dnsserver2
  ){
    $r = New-Object WlanProfIpConfigData;
    $r.ipaddr = @($ipaddr)|
      Where-Object{$_}|
      ForEach-Object{[WlanProfIpData]::V6($_, $masklen)};        
    $r.gateway = @($gateway)|
      Where-Object{$_}|
      ForEach-Object{[WlanProfIpData]::V6($_, 0)};
    $r.dnsserver = @($dnsserver1,$dnsserver2)|
      Where-Object{$_}|
      ForEach-Object{[WlanProfIpData]::V6($_, 0)};
    return $r;
  }
}
function Get-WlanProfilePlace{
<# Usage
Get-WlanProfilePlace
#>
  [CmdletBinding()]
  Param()
  Process{
    $adapters = Get-NetAdapter;
    Get-ChildItem (Join-Path ([Environment]::GetFolderPath("CommonApplicationData")) "Microsoft\Wlansvc\Profiles\Interfaces") -Recurse|
    Where-Object Extension -EQ .xml|
    Where-Object{Test-Path -Path "HKLM:\SOFTWARE\Microsoft\WlanSvc\Interfaces\$($_.Directory.Name)\Profiles\$($_.BaseName)\Metadata"}|
    ForEach-Object{
      $interfaceGuid = [Guid]($_.Directory.Name);
      $wlanProfileGuid = [Guid]($_.BaseName);
      $adapter = $adapters|Where-Object{[Guid]($_.InterfaceGuid) -eq $interfaceGuid};
      if($adapter){
        $xml = [Xml]($_|Get-Content);
        [PSCustomObject]@{
          ProfileName = $xml.WLANProfile.name;
          SSID = $xml.WLANProfile.SSIDConfig.SSID.name;
          InterfaceGuid = $interfaceGuid;
          WlanProfileGuid = $wlanProfileGuid;
          InterfaceIndex = $adapter.InterfaceIndex;
          InterfaceAlias = $adapter.InterfaceAlias;
          InterfaceDescription = $adapter.InterfaceDescription;
        };
      }
    };
  }
}
function Get-WlanProfileStaticIPv4{
<# Usage
Get-WlanProfilePlace|? SSID -eq test|Get-WlanProfileStaticIPv4
#>
  [OutputType([WlanProfIpConfigData])]
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$InterfaceGuid,
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$WlanProfileGuid
  )
  Process{
    [WlanProfIpConfigData]::Parse((Get-ItemProperty -Path(
      "HKLM:\SOFTWARE\Microsoft\WlanSvc\Interfaces\{$InterfaceGuid}\Profiles\{$WlanProfileGuid}\Metadata"
    )).ProfileIpConfigurationV4);
  }
}
function Get-WlanProfileStaticIPv6{
<# Usage
Get-WlanProfilePlace|? SSID -eq test|Get-WlanProfileStaticIPv6
#>
  [OutputType([WlanProfIpConfigData])]
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$InterfaceGuid,
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$WlanProfileGuid
  )
  Process{
    [WlanProfIpConfigData]::Parse((Get-ItemProperty -Path(
      "HKLM:\SOFTWARE\Microsoft\WlanSvc\Interfaces\{$InterfaceGuid}\Profiles\{$WlanProfileGuid}\Metadata"
    )).ProfileIpConfigurationV6);
  }
}
function Remove-WlanProfileStaticIP{
<# Usage
Get-WlanProfilePlace|? SSID -eq test|Remove-WlanProfileStaticIP
#>
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$InterfaceGuid,
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$WlanProfileGuid
  )
  Process{
    if(([Environment]::OSVersion.Version) -lt ([Version]"10.0.16299")){
      "Set-WlanProfileStaticIP: not affect before Windows 10 Version 1709"|Out-Error;
    }
    Remove-ItemProperty -Path(
      "HKLM:\SOFTWARE\Microsoft\WlanSvc\Interfaces\{$InterfaceGuid}\Profiles\{$WlanProfileGuid}\Metadata"
    ) -Name ProfileIpConfigurationV4;
    Remove-ItemProperty -Path(
      "HKLM:\SOFTWARE\Microsoft\WlanSvc\Interfaces\{$InterfaceGuid}\Profiles\{$WlanProfileGuid}\Metadata"
    ) -Name ProfileIpConfigurationV6;
  }
}
function Set-WlanProfileStaticIPv4{
<# Usage
Get-WlanProfilePlace|? SSID -eq test|Set-WlanProfileStaticIPv4 -IpAddress 192.168.100.10 -PrefixLength 24 -DefaultGateway 192.168.100.1 -DnsServer1 192.168.100.1
#>
[CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$InterfaceGuid,
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$WlanProfileGuid,
    [Net.IPAddress]$IpAddress,
    [byte]$PrefixLength,
    [Net.IPAddress]$DefaultGateway,
    [Net.IPAddress]$DnsServer1,
    [Net.IPAddress]$DnsServer2
  )
  Process{
    if(([Environment]::OSVersion.Version) -lt ([Version]"10.0.16299")){
      "Set-WlanProfileStaticIP: not affect before Windows 10 Version 1709"|Out-Error;
    }
    $data = [WlanProfIpConfigData]::V4($IPAddress, $PrefixLength, $DefaultGateway, $DnsServer1, $DnsServer2);
    New-ItemProperty -Path(
      "HKLM:\SOFTWARE\Microsoft\WlanSvc\Interfaces\{$InterfaceGuid}\Profiles\{$WlanProfileGuid}\Metadata"
    ) -Name ProfileIpConfigurationV4 -Value $data.GetBytes() -PropertyType Binary -Force|Out-Null;
    $data;
  }
}
function Set-WlanProfileStaticIPv6{
<# Usage
Get-WlanProfilePlace|? SSID -eq test|Set-WlanProfileStaticIPv6 -IpAddress 2001:db8:beef::dead -PrefixLength 60 -DefaultGateway 2001:db8:beef:1::1 -DnsServer1 2001:db8:beef:1::2 -DnsServer2 2001:db8:beef:1::3
#>
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$InterfaceGuid,
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Guid]$WlanProfileGuid,
    [Net.IPAddress]$IpAddress,
    [byte]$PrefixLength,
    [Net.IPAddress]$DefaultGateway,
    [Net.IPAddress]$DnsServer1,
    [Net.IPAddress]$DnsServer2
  )
  Process{
    if(([Environment]::OSVersion.Version) -lt ([Version]"10.0.16299")){
      "Set-WlanProfileStaticIP: not affect before Windows 10 Version 1709"|Out-Error;
    }
    $data = [WlanProfIpConfigData]::V6($IPAddress, $PrefixLength, $DefaultGateway, $DnsServer1, $DnsServer2);
    New-ItemProperty -Path(
      "HKLM:\SOFTWARE\Microsoft\WlanSvc\Interfaces\{$InterfaceGuid}\Profiles\{$WlanProfileGuid}\Metadata"
    ) -Name ProfileIpConfigurationV4 -Value $data.GetBytes() -PropertyType Binary -Force|Out-Null;
    $data;
  }
}

Export-ModuleMember -Function *;
```

## Wi-Fi接続プロファイルの作成は？

今の所、この文章では触れていません。

従来から存在していて将来の廃止が予告されている ネットワークシェル `netsh` を用いるか、`wifiprofilemanagement` などで試みられているように `wlanapi.dll` 等を読み込んで制御するか、の大きく2通りの方法になるかと思います。

- ネットワークシェル `netsh` を用いる
  - [ネットワークシェル Netsh](https://docs.microsoft.com/ja-jp/windows-server/networking/technologies/netsh/netsh)
  - [Qiita内検索: netsh wlan add profile](https://qiita.com/search?utf8=%E2%9C%93&sort=&q=netsh+wlan+add+profile)
  - [Google検索: netsh wlan add profile](https://www.google.co.jp/search?lr=lang_ja&hl=ja&q=netsh+wlan+add+profile)
- `wlanapi` を用いる
  - [wlanapi.h header](https://docs.microsoft.com/ja-jp/windows/desktop/api/wlanapi/)
- 別途、有志が作成したPowerShellモジュールを用いる
  - `wifiprofilemanagement` : [(PowerShell Gallery)](https://www.powershellgallery.com/packages/wifiprofilemanagement/) [(GitHib)](https://github.com/jcwalker/WiFiProfileManagement)