結論から先にいうとそこまでどうにかなってはいない
PowerShellでSSID選んでWiFi繋ぐやつ書いた
これとか死んだわけです
記事にはしてないけどWeb資格情報の読み書きするModuleもやられた
どうするか
だいたいぐぐるとここに行き着くわけです
“Loading” of Windows Runtime assemblies fails in 7.1 Preview 4 · Issue #13042 · PowerShell/PowerShell
読んでいくと答えが書いてあるのでそれをやっていきます
やっていく手順
C#/WinRtだとかそういうのを使えるようにしていきます
Find-Package -ProviderName NuGet -Source https://www.nuget.org/api/v2 -Name Microsoft.Windows.CsWinRT | Install-Package
Find-Package -ProviderName NuGet -Source https://www.nuget.org/api/v2 -Name Microsoft.Windows.SDK.NET.Ref | Install-Package
nugetしていく
これやると $env:ProgramFiles\PackageManagement\NuGet\Packages
にインストールされるよ
その後はAdd-Type
する
Add-Type -Path 'C:\Program Files\PackageManagement\NuGet\Packages\Microsoft.Windows.CsWinRT.1.0.1\lib\net5.0\WinRT.Runtime.dll'
Add-Type -Path 'C:\Program Files\PackageManagement\NuGet\Packages\Microsoft.Windows.SDK.NET.Ref.10.0.19041.10\lib\Microsoft.Windows.SDK.NET.dll'
WinRT.Runtime.dllとMicrosoft.Windows.SDK.NET.dllをAdd-TypeするとWinRT使えるようになります
基本的には
(やる前よりかは動くようになる)
モジュールに手を入れる
まず
[Windows.Devices.WiFi.WiFiAdapter,Windows.Devices.WiFi,ContentType=WindowsRuntime] | Out-Null
こういうおまじないめいたやつは消してよい
Add-Typeした時点で[Windows.Devices.WiFi.WiFiAdapter]
とかもう使えるからです
その上でImport-Module
しなおして動かしてみよう
エラーが出たらその都度対応だッッッ!!!
困ったこと
[Windows.Security.Credentials.PasswordVault]::new().FindAllByResource($Resource)
これはWeb資格情報から保存してある資格情報を読み出すやつ
前まではSystem.__ComObject
が返ってたけど[Windows.Security.Credentials.PasswordCredential]
にキャストして使えてたのね
でも今回の方法でやってるとキャストできない
戻り値の型がWinRT.IInspectable
になっててどうしたもんだかわかない
同じことがWifiのやつでも起きてて
Get-WifiAdapter | Get-WiFiAvailableNetwork
で無事死ねるOutputType
指定しててもどうにもならんね
でもまぁ資格情報のやつなら
$Creds = [Windows.Security.Credentials.PasswordVault]::new().FindAllByResource($Resource)
$Creds.AdditionalTypeData.Values
とやると必要な値は取れるので別にキャストしなくてもいいのでは?
というとこまではわかった
あとは7.1より前と以降とでどうするか?ということも考えなくちゃいけないね
めんどうなことになったよ…
追記: 2020/11/24
nugetについて
WinRT.Runtime.dll
がMicrosoft.Windows.SDK.NET.Ref
にも入ってたのでそれだけnugetすればいいのかも?
バージョン別対応について
- 7.1より前ならおまじないする
- 7.1以降ならdllをAdd-Typeする
- dllがなかったらnugetしてからAdd-Type
ParameterSetNameで従来のパラメータの他に[WinRT.IInspectable]を受けるパラメータを作ることでだいたい対応できる
厳密にはWinRT.IInspectableの実態がなんの型か調べるとかしたほうが良い
(じゃないと何でも受け取れちゃうので)
けど面倒ならそれは運用回避
function Get-WiFiAvailableNetwork {
[OutputType([Windows.Devices.WiFi.WiFiAvailableNetwork])]
[CmdletBinding()]
param(
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='before71')]
[Windows.Devices.WiFi.WiFiAdapter] $WifiAdapter,
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='after71')]
[WinRT.IInspectable] $WifiAdapter_,
[Parameter()]
[string] $Ssid
)
process {
$AvailableNetworks = if ($WifiAdapter_) {
$WifiAdapter_.AdditionalTypeData.Values[0] | % {
$_.NetworkReport.AvailableNetworks.AdditionalTypeData.Values[0]
}
} else {
$WifiAdapter.NetworkReport.AvailableNetworks
}
if ($Ssid) {
$AvailableNetworks | Where-Object Ssid -Like $Ssid
} else {
$AvailableNetworks
}
}
}
やった例
Values[0]なのはそうしないとどう見ても同じものが2つ返ってるから
今のとこ不都合はなさそうだけど正しい対応なのかはわからない
WinRT.IInspectableの出力
ps1xmlでとりあえず中身がなんだかくらいわかるようにした
<Type>
<Name>WinRT.IInspectable</Name>
<Members>
<ScriptProperty>
<Name>IInspectable</Name>
<GetScriptBlock>
"{0} ({1})" -f @(
$this.AdditionalTypeData.Values[0]
($ada.AdditionalTypeData.Values[0] | gm -MemberType Properties | ? Name -NotIn ('AdditionalTypeData','HasUnwrappableNativeObject','NativeObject') | select -exp Name) -join ', '
)
</GetScriptBlock>
</ScriptProperty>
<MemberSet>
<Name>PSStandardMembers</Name>
<Members>
<PropertySet>
<Name>DefaultDisplayPropertySet</Name>
<ReferencedProperties>
<Name>IInspectable</Name>
</ReferencedProperties>
</PropertySet>
</Members>
</MemberSet>
</Members>
</Type>
追記: 2021/03/18
素敵なコメントを頂きましたよ
That’s how it works now
> https://github.com/PowerShell/PowerShell/issues/14991
これにより AdditionalTypeData.Values[0]
みたいな記述しないでもよくなりますね
$Creds = [Windows.Security.Credentials.PasswordVault]::new().FindAllByResource($Resource)
$Names = $Creds.AdditionalTypeData.Item([System.Collections.IEnumerable].TypeHandle).UserName
AdditionalTypeDataがなんか辞書っぽいのでキーがわかれば然るべき値が取れるという感じのようです
で、そのキーが [System.Collections.IEnumerable].TypeHandle だったと
リンク先だとAdditionalTypeData[[System.Collections.IEnumerable].TypeHandle]
という書き方してますがItem()
使わないとだめでした
Values[0]
だと良くない場合もあるかもしれんので今後はこれでやっていきましょう
追記: 2021/03/19
WinRTモジュールに以下を書いた
Update-TypeData -MemberType ScriptProperty -MemberName TypeData -Value {
$this.AdditionalTypeData.Item([System.Collections.IEnumerable].TypeHandle)
} -Force -TypeName WinRT.IInspectable
これはWinRT.IInspectable
にTypeDataというプロパティを生やして、本来欲しかった型のデータを取るためのものです
ので機能の追記のであれば
$Names = $Creds.TypeData.UserName
と書けます
そんでまぁ本来欲しかった型が取れるんだから7.1前後対応であれば
function Get-WifiAdapter {
[OutputType([Windows.Devices.WiFi.WiFiAdapter])]
[CmdletBinding()]
param()
process {
$adapter = Wait-IAsyncOperation -Method ([Windows.Devices.WiFi.WiFiAdapter]::FindAllAdaptersAsync)
if ($adapter.GetType() -eq [WinRT.IInspectable]) {
$adapter.TypeData
} else {
$adapter
}
}
}
みたいにすればいいよねってことになります
なりました
これでモジュールがいろいろすっきりした
That’s how it works now
https://github.com/PowerShell/PowerShell/issues/14991
ピンバック: PowerShellでSSID選んでWiFi繋ぐやつ書いた | たっぷす庵