$objContext.AcceptWebSocketAsync($null)
での呼び出し部分は、$null
ではなく[NullString]::Value
で指定すると成功します。
PowerShell
1 $wsContextTask = $context.AcceptWebSocketAsync([NullString]::Value)
以下の簡単なPowerShellスクリプトによるWebSocketサーバーのサンプルプログラムで実行例を示します。もとはAIのCopilotさん提案のコードを元に、更に簡単にしたものです。尚、クライアント側はWebブラウザー上からJavaScriptで実行する簡単なコードなので、割愛します。
PowerShell
1# t4c.ps1
2#Add-Type -AssemblyName System.Net.HttpListener
3#Add-Type -AssemblyName System.Net.WebSockets
4
5$listener = New-Object System.Net.HttpListener
6$listener.Prefixes.Add("http://localhost:8081/ws/")
7$listener.Start()
8Write-Host "Listening on ws://localhost:8081/ws/..."
9$context = $listener.GetContext()
10
11if ($context.Request.IsWebSocketRequest) {
12 # Accept the WebSocket connection
13 # $nullでは失敗する
14 $wsContextTask = $context.AcceptWebSocketAsync($null)
15 Write-Host "#pass1 : $wsContextTask"
16
17 # [NullString]::Valueで成功する
18 $wsContextTask = $context.AcceptWebSocketAsync([NullString]::Value)
19
20 # $wsContextTaskが返っていることを確認
21 Write-Host "#pass2 : $wsContextTask"
22 $wsContextTask.Wait()
23
24 $wsContext = $wsContextTask.Result
25 $websocket = $wsContext.WebSocket
26
27 Write-Host "WebSocket connection accepted!"
28
29 $websocket.Dispose()
30} else {
31 $context.Response.StatusCode = 400
32 $context.Response.Close()
33 Write-Host "Rejected non-WebSocket request."
34}
クライアントからはws://localhost:8081/ws/
で接続します。これを実行してみます。
PowerShell
1PS> # PowerShellのバージョン
2PS> $PSVersionTable
3
4Name Value
5---- -----
6PSVersion 5.1.19041.5965
7PSEdition Desktop
8PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
9BuildVersion 10.0.19041.5965
10CLRVersion 4.0.30319.42000
11WSManStackVersion 3.0
12PSRemotingProtocolVersion 2.3
13SerializationVersion 1.1.0.1
14
15
16PS> PowerShell -ExecutionPolicy RemoteSigned .\t4c.ps1
17Listening on ws://localhost:8081/ws/...
18"1" 個の引数を指定して "AcceptWebSocketAsync" を呼び出し中に例外が発生しました: "空の文字列は、有効な subprotocol 値で
19はありません。値を指定しない場合は、"null" を使用してください。
20パラメーター名:subProtocol"
21発生場所 C:\_work\ClassLibrary1\t4c.ps1:14 文字:5
22+ $wsContextTask = $context.AcceptWebSocketAsync($null)
23+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
25 + FullyQualifiedErrorId : ArgumentException
26
27#pass1 :
28#pass2 : System.Threading.Tasks.Task`1[System.Net.WebSockets.HttpListenerWebSocketContext]
29WebSocket connection accepted!
30PS>
31
$null
を指定しての呼び出しではご質問と同様のエラーが発生し、[NullString]::Value
では成功していることが分かると思います。
おそらく、なぜか null が string にキャストされて string.empty になってるんだと思いますが、
これはほぼご推測の通りで、.NETのメソッドについて$null
をSystem.String
型の引数に指定するとPowerShellによってnull
ではなく空文字列""
に変換されてしまうようです。Microsoftが個人のブログを共有したかたちで記事を載せているので、公式の情報と言ってよいのでしょう。
$nullについて知りたいこと - Microsoft Learn
※上記は自動翻訳による日本語記事なので、ところどころ読みづらい部分があります。元の英語記事はこちら。
Everything you wanted to know about $null - Microsoft Learn
null
ではない空文字列は$s = ""
のように表現できるのに、$null
をSystem.String
な引数に渡したメソッド呼び出し時に変換されてしまうのは私個人的にもちょっと不便、と言うか余計なお世話にも感じますね。まぁ、スクリプトと.NETの相互運用性から便宜を図る意図があったのでしょう。
[NullString]::Value について追記:
[NullString]::Value
についてはPowerShellの$null
とC#のstring
の扱いについての話題でたまに見かけるのですが、なかなか公式のリファレンスには辿り着きづらいようです。今回の回答にあたって気になっていたので、少し調べていました。
PowerShell SDKの以下の情報がそれにあたるようです。
NullString Class - Microsoft Learn
Definition
...
This type is introduced to provide a way to pass null into a .NET method that has a string parameter.
との説明なので、まさにその用途のクラスですね。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2025/06/28 04:30
2025/06/29 23:53