PowerShellでSSID選んでWiFi繋ぐやつ書いた

PowerShell 7.1 以降だとこの記事に記載された方法では動かなくなりました
こちらの記事で7.1以降でWinRTする方法を書いています


netshコマンドでやるやつはむかーし書いたのだけど
さすがに不便がすぎたので別の方法でやったのです

別の方法

WinRTですね
WinRTのあれもPowerShellからやれないことはない

こんな風に使うようにしました

$adapter = Get-WifiAdapter
$ap = Get-WiFiAvailableNetwork -WifiAdapter $adapter -Ssid "YourSsid"
Connect-WifiAdapter -WifiAdapter $adapter -WiFiAvailableNetwork $ap -WiFiReconnectionKind Automatic

保存済みの接続先ならこれで繋がります
未保存の接続先ならConnect-WifiAdapter-Passwordで接続時に必要なパスワードを指定できます
非表示のSSIDであれば-HiddenSsidで教えてあげましょう
-WiFiReconnectionKindは自動接続させるかどうかの設定で、デフォだとManual(自動接続しない)です

あとDisconnect-WifiAdapterというのもいて見た通り切断してくれます
そんなに使わないけど

以下が実際のモジュール
その下にめんどくさい部分の解説が付きますが通常読まなくてよいやつです

[Windows.Devices.WiFi.WiFiAdapter,Windows.Devices.WiFi,ContentType=WindowsRuntime] | Out-Null
Add-Type -AssemblyName System.Runtime.WindowsRuntime
Add-Type -AssemblyName System.Runtime.InteropServices.WindowsRuntime

Function Wait-IAsyncOperation {
    param(
        [Parameter(Mandatory)]
        [System.Management.Automation.PSMethod] $Method,
        [Parameter(Mandatory=$false)]
        [object[]] $Arguments = @(),
        [Parameter(Mandatory=$false)]
        [type] $ResultType
    )
    if (! $ResultType) {
        if ($Method.OverloadDefinitions[0] -match 'IAsyncOperation\[([\w\.\[\]]+)\] ') {
            $ResultType = $Matches[1] -as [type]
            Write-Verbose $ResultType
        } else {
            Write-Warning "不正なメソッド: $Method"
            break
        }
    }
    $asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | Where-Object { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
    $asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
    $netTask = $asTask.Invoke($null, @($Method.Invoke($Arguments)))
    try {
        $netTask.Wait(-1) | Out-Null
        $netTask.Result
    } catch {
        Write-Error $netTask.Exception
    }
}

function Get-WifiAdapter {
    [OutputType([Windows.Devices.WiFi.WiFiAdapter])]
    [CmdletBinding()]
    param(

    )
    process {
        $selector = [Windows.Devices.WiFi.WiFiAdapter]::GetDeviceSelector()
        Wait-IAsyncOperation -Method ([Windows.Devices.WiFi.WiFiAdapter]::FindAllAdaptersAsync)
    }
}

function Get-WiFiAvailableNetwork {
    [OutputType([Windows.Devices.WiFi.WiFiAvailableNetwork])]
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ValueFromPipeline)]
        [Windows.Devices.WiFi.WiFiAdapter] $WifiAdapter,
        [Parameter()]
        [string] $Ssid = '*'
    )
    process {
        $WifiAdapter.NetworkReport.AvailableNetworks | ? Ssid -Like $Ssid
    }
}

function Disconnect-WifiAdapter {
    [OutputType()]
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ValueFromPipeline)]
        [Windows.Devices.WiFi.WiFiAdapter] $WifiAdapter
    )
    process {
        $WifiAdapter.Disconnect()
    }
}

function Connect-WifiAdapter {
    [OutputType([Windows.Devices.WiFi.WiFiConnectionResult])]
    [CmdletBinding(DefaultParameterSetName='pipenetwork')]
    param(
        [Parameter(Mandatory,ValueFromPipeline,ParameterSetName='pipeadapter')]
        [Parameter(Mandatory,ParameterSetName='pipenetwork')]
        [Windows.Devices.WiFi.WiFiAdapter] $WifiAdapter,
        [Parameter(Mandatory,ParameterSetName='pipeadapter')]
        [Parameter(Mandatory,ValueFromPipeline,ParameterSetName='pipenetwork')]
        [Windows.Devices.WiFi.WiFiAvailableNetwork] $WiFiAvailableNetwork,
        [Parameter(Mandatory=$false)]
        [Windows.Devices.WiFi.WiFiReconnectionKind] $WiFiReconnectionKind = 'Manual',
        [Parameter(Mandatory=$false)]
        [string] $Password,
        [Parameter(Mandatory=$false)]
        [string] $HiddenSsid
    )
    process {
        $args = @(
            $WiFiAvailableNetwork
            $WiFiReconnectionKind
        )
        if ($Password) {
            $args += [Windows.Security.Credentials.PasswordCredential]::new('tmp', 'tmp', $Password)
            if ($HiddenSsid) {
                $args += $HiddenSsid
            }
        }
        Wait-IAsyncOperation -Method ($WifiAdapter.ConnectAsync) -Arguments $args
    }
}

Export-ModuleMember -Function *-Wifi*

以下はWinRT的なことをPowerShellでやりたい素っ頓狂な方向けのなにかです
ほんのりヒントになることを願って

[Windows.Devices.WiFi.WiFiAdapter,Windows.Devices.WiFi,ContentType=WindowsRuntime] | Out-Null
Add-Type -AssemblyName System.Runtime.WindowsRuntime
Add-Type -AssemblyName System.Runtime.InteropServices.WindowsRuntime

最初からおまじないめいてますね
Windows.Devices.WiFi.WiFiAdapterはふつーには出てこないので使えるようにしているのが1行目です、出力があるので黙らせています
続くAdd-Typeはなんか必要なのでやっておくやつです
WinRTをやるというのはおおよそこのようなことから始まっていきます

続いてWait-IAsyncOperationとかいう関数が出てきますがこれがキモです
WinRTはAsyncなメソッドが多いのでどうしてもAwaitする必要があります
それを実現するための関数ですね
ネットで拾ってきてやや改造を加えたものです
仕組みはややわかるけどよくわかりません
おまじないですね

        Wait-IAsyncOperation -Method ([Windows.Devices.WiFi.WiFiAdapter]::FindAllAdaptersAsync)
        Wait-IAsyncOperation -Method ($WifiAdapter.ConnectAsync) -Arguments $args

こんな感じで使われており、ぶっ叩くメソッドと引数を渡したり渡さなかったりします
必要性からメソッドの返り値の型を無理やり得る仕組みがあり、ただそれは失敗する場合もあるのでそういうときは-ResultTypeで返り値の型を自分で教えてやります

        $WifiAdapter.Disconnect()

Awaitしなくていいやつもいる
そういうやつは普通に呼んでよい

以上です
ヨカッタネ

PowerShellでSSID選んでWiFi繋ぐやつ書いた」への1件のフィードバック

  1. ピンバック: PowerShell 7.1 でWinRTが死んだのでなんとかしていく | たっぷす庵

コメントを残す