Joy-Conのbluetoothでの接続状態をPowerShellから確認したい。

いろいろとあって、PowershellでJoy-Conの接続状態を取得したかったのですがかなり苦労したので備忘録を残しておきます。
全体のソースは[一番下](#ソース全体)に載せておきます。

# はじめに
Nintendo Switchに付属しているコントローラである、[Joy-Con](https://ja.wikipedia.org/wiki/Nintendo_Switch#Joy-Con)はPCとBluetoothで接続することが可能です。
ご存じの通り、Bluetooth製品はまず「ペアリング」を行い、その後「接続」され始めて使用が可能となります。

Joy-Conがペアリングされていて接続されていない状態なのか、それとも既に接続されている状態なのかを取得したかったのですが、`Get-PnpDevice`からはその状態を判別できなかったため、`Get-PnpDeviceProperty`を使って詳しいプロパティから状態を取得しました。

# 実践
ここからは[全体のソース](#ソース全体)を小分けにして何をしているか説明します。
## 1.登録されているJoy-Con一覧を取得
とりあえず、"Joy-Con"として登録されているデバイス一覧を取得します。
ここではペアリングされているデバイスのみが取得可能なので、ここで取得できていればペアリングされているということになります。

``` 1.登録されているJoy-Con一覧を取得.ps1
# 1.登録されているJoy-Con一覧を取得
$joyconInfo = Get-PnpDevice | ? {$_.friendlyname -like '*Joy-Con*'}
```

## 2.登録されているJoy-Conの中で接続されているものがあるか判定
ここでは1で取得したデバイス一覧からそれぞれの詳しい情報を取得して判定していきます。
`Get-PnpDeviceProperty`で取得した結果は以下のようなものが返却されています。
```
InstanceId KeyName                                   Type       Data                                                       
---------- -------                                   ----       ----                                                       
BTHENUM... DEVPKEY_Device_DeviceDesc                 String     Bluetooth デバイス 
BTHENUM... DEVPKEY_Device_HardwareIds                StringList {hogee} 
BTHENUM... DEVPKEY_Device_CompatibleIds              StringList {hoge}
BTHENUM... DEVPKEY_Device_Class                      String     Bluetooth 
BTHENUM... DEVPKEY_Device_ClassGuid                  Guid       {hoge}
BTHENUM... DEVPKEY_Device_Driver                     String     {hoge}hoge
BTHENUM... DEVPKEY_Device_ConfigFlags                UInt32     0
BTHENUM... DEVPKEY_Device_Manufacturer               String     Microsoft 
BTHENUM... DEVPKEY_Device_FriendlyName               String     Joy-Con (L)
BTHENUM... DEVPKEY_Device_PDOName                    String     \Device\hoge
BTHENUM... DEVPKEY_Device_Capabilities               UInt32     000
BTHENUM... DEVPKEY_Device_EnumeratorName             String     hoge
----    ----    (後略)    ----    ----    
```

この中で使用するのはKeyNameが`DEVPKEY_Device_IsPresent`と`DEVPKEY_Bluetooth_LastConnectedTime`の値になります。
これらのプロパティから以下のことがわかります。
- `DEVPKEY_Device_IsPresent`がFalseの時はPC側のBluetooth自体がOFFとなっている。
- `DEVPKEY_Bluetooth_LastConnectedTime`がプロパティにある場合、ペアリングされているかつデバイスが接続されていない状態。

(以上2つは実際の値から推測したもののため正しくない場合があります。)

上記の判定を取得したデバイスごとに実施し、どちらの条件にもかからないデバイスがあった場合に`$hasValidJoyCon`をTrueとして、有効なデバイスがあったことをロジック3に伝えます。

``` 2.登録されているJoy-Conの中で接続されているものがあるか判定.ps1
# 2.登録されているJoy-Conの中で接続されているものがあるか判定
#有効なJoyConがあるか
$hasValidJoyCon = $False

#bluetoothが無効となっている
$bluetoothDisable = $False
#JoyConが接続されていない
$joyConNotConnected = $False

#デバイスリストを回す
foreach($aInstance in $joyconInfo){
    $joyconProperties = Get-PnpDeviceProperty -InstanceId $aInstance.InstanceId 
    $bluetoothDisable = $False
    $joyConNotConnected = $False

    foreach($aProperty in $joyconProperties){
        if($aProperty.KeyName -eq "DEVPKEY_Device_IsPresent"){
            if($aProperty.Data -eq $False){
                # Bluetoothが有効か？
                $bluetoothDisable = $True
            }
        }
        if($aProperty.KeyName -eq "DEVPKEY_Bluetooth_LastConnectedTime"){
            # 最終接続日時（これがプロパティに入っている場合、Bluetoothが有効かつ、デバイスが接続されていない）
            $joyConNotConnected = $True
        }
        
    }
    IF(!$bluetoothDisable -And !$joyConNotConnected){
        $hasValidJoyCon = $True
        break
    }
}

```


## 3.接続されているものがなければ、処理を終了
ここは単に結果を出力しているだけですが、1件でも有効なデバイスがあれば素通り、無効なデバイスのみであれば最後の1件の理由がわかるようになっています。
~~本来なら取得できたデバイスすべての結果を出力するべきかもしれませんが、自分用ツールなので。。。~~
``` 3.接続されているものがなければ、処理を終了.ps1
# 3.接続されているものがなければ、処理を終了
IF(!$hasValidJoyCon){
    IF($bluetoothDisable){
        echo "Bluetoothが無効なので処理を終了します。設定でBluetoothが有効になっていることを確認してください。"
    }
    ELSEIF($joyConNotConnected){
        echo "Joyconが接続されていないので処理を終了します。設定でJoyconが接続されていることを確認してください。"
    }
    exit 1
}

```


# おわり
本記事は以上となります。
PowershellでBluetoothデバイスの状態を取得する需要があるかは疑問ですが、私が調べた限りではやっている方がいなかったので備忘録として残しておきます。
なにかおかしい部分などあればコメント等よろしくお願いします。


# ソース全体

``` joyconCheck.ps1
echo 'Joycon起動処理を実行しています…'
# 1.登録されているJoy-Con一覧を取得
$joyconInfo = Get-PnpDevice | ? {$_.friendlyname -like '*Joy-Con*'}


# 2.登録されているJoy-Conの中で接続されているものがあるか判定
#有効なJoyConがあるか
$hasValidJoyCon = $False

#bluetoothが無効となっている
$bluetoothDisable = $False
#JoyConが接続されていない
$joyConNotConnected = $False

foreach($aInstance in $joyconInfo){
    $joyconProperties = Get-PnpDeviceProperty -InstanceId $aInstance.InstanceId 
    $bluetoothDisable = $False
    $joyConNotConnected = $False

    foreach($aProperty in $joyconProperties){
        if($aProperty.KeyName -eq "DEVPKEY_Device_IsPresent"){
            if($aProperty.Data -eq $False){
                # Bluetoothが有効か？
                $bluetoothDisable = $True
            }
        }
        if($aProperty.KeyName -eq "DEVPKEY_Bluetooth_LastConnectedTime"){
            # 最終接続日時（これがプロパティに入っている場合、Bluetoothが有効かつ、デバイスが接続されていない）
            $joyConNotConnected = $True
        }
        
    }
    IF(!$bluetoothDisable -And !$joyConNotConnected){
        $hasValidJoyCon = $True
        break
    }
}

# 3.接続されているものがなければ、処理を終了
IF(!$hasValidJoyCon){
    IF($bluetoothDisable){
        echo "Bluetoothが無効なので処理を終了します。設定でBluetoothが有効になっていることを確認してください。"
    }
    ELSEIF($joyConNotConnected){
        echo "Joyconが接続されていないので処理を終了します。設定でJoyconが接続されていることを確認してください。"
    }
    exit 1
}


echo "Joyconが接続されています"
```