@@ -484,142 +484,205 @@ function Get-WebSocket {
484
484
break
485
485
}
486
486
487
+ # If we're authenticating, and haven't yet said hello
487
488
if ($Authenticate -and -not $SaidHello ) {
488
- # a number of websockets require some handshaking to authenticate
489
- $authenticationMessage =
489
+ # then we should say hello.
490
+ # Determine the authentication message
491
+ $authenticationMessage =
492
+ # If the authentication message is a scriptblock,
490
493
if ($Authenticate -is [ScriptBlock ]) {
491
- & $Authenticate $MessageObject
494
+ & $Authenticate # run it
492
495
} else {
493
- $authenticate
496
+ $authenticate # otherwise, use it as-is.
494
497
}
495
498
499
+ # If we have an authentication message
496
500
if ($authenticationMessage ) {
501
+ # and it's not a string
497
502
if ($authenticationMessage -isnot [string ]) {
503
+ # then we should send it as JSON and mark that we've said hello.
498
504
$saidHello = $ws.SendAsync ([ArraySegment [byte ]]::new(
499
505
$OutputEncoding.GetBytes ((ConvertTo-Json - InputObject $authenticationMessage - Depth 10 ))
500
506
), ' Text' , $true , $CT )
501
507
}
502
508
}
503
509
}
504
510
511
+ # Ok, let's get the next message.
505
512
$Buf = [byte []]::new($BufferSize )
506
513
$Seg = [ArraySegment [byte ]]::new($Buf )
507
514
$receivingWebSocket = $ws.ReceiveAsync ($Seg , $CT )
515
+ # use this tight loop to let us cancel the await if we need to.
508
516
while (-not ($receivingWebSocket.IsCompleted -or $receivingWebSocket.IsFaulted -or $receivingWebSocket.IsCanceled )) {
509
517
518
+ }
519
+ # If we had a problem, write an error.
520
+ if ($receivingWebSocket.Exception ) {
521
+ Write-Error - Exception $receivingWebSocket.Exception - Category ProtocolError
522
+ continue
510
523
}
511
524
$MessageCount ++
512
525
513
526
try {
527
+ # If we have a handshake and we haven't yet shaken hands
514
528
if ($Handshake -and -not $shookHands ) {
515
- # a number of websockets require some handshaking
516
- $handShakeMessage =
529
+ # then we should shake hands.
530
+ # Get the message string
531
+ $messageString = $OutputEncoding.GetString ($Buf , 0 , $Buf.Count )
532
+ # and try to convert it from JSON.
533
+ $messageObject = ConvertFrom-Json - InputObject $messageString * > & 1
534
+ # Determine the handshake message
535
+ $handShakeMessage =
536
+ # If the handshake message is a scriptblock,
517
537
if ($Handshake -is [ScriptBlock ]) {
518
- & $Handshake $MessageObject
538
+ & $Handshake $MessageObject # run it and pass the message
519
539
} else {
520
- $Handshake
540
+ $Handshake # otherwise, use it as-is.
521
541
}
522
542
543
+ # If we have a handshake message
523
544
if ($handShakeMessage ) {
545
+ # and it's not a string
524
546
if ($handShakeMessage -isnot [string ]) {
547
+ # then we should send it as JSON and mark that we've shaken hands.
525
548
$saidHello = $ws.SendAsync ([ArraySegment [byte ]]::new(
526
549
$OutputEncoding.GetBytes ((ConvertTo-Json - InputObject $handShakeMessage - Depth 10 ))
527
550
), ' Text' , $true , $CT )
528
551
}
529
552
}
530
553
}
531
554
555
+ # Get the message from the websocket
532
556
$webSocketMessage =
533
- if ($Binary ) {
534
- $Buf -gt 0
557
+ if ($Binary ) { # If we wanted binary
558
+ $Buf -gt 0 -as [ byte []] # then return non-null bytes
535
559
} else {
560
+ # otherwise, get the message as a string
536
561
$messageString = $OutputEncoding.GetString ($Buf , 0 , $Buf.Count )
562
+ # if we have any filters
537
563
if ($Filter ) {
564
+ # then we see if we can apply them now.
538
565
foreach ($fil in $filter ) {
566
+ # Wilcard filters can be applied to the raw text
539
567
if ($fil -is [string ] -and $messageString -like " *$fil *" ) {
540
568
$FilteredCount ++
541
569
continue WebSocketMessageLoop
542
570
}
571
+ # and so can regex filters.
543
572
if ($fil -is [regex ] -and $fil.IsMatch ($messageString )) {
544
573
$FilteredCount ++
545
574
continue WebSocketMessageLoop
546
575
}
547
576
}
548
577
}
578
+ # If we have asked for -RawText
549
579
if ($RawText ) {
550
- $messageString
580
+ $messageString # then return the raw text
551
581
} else {
552
- $MessageObject = ConvertFrom-Json - InputObject $messageString
582
+ # Otherwise, try to convert the message from JSON.
583
+ $MessageObject = ConvertFrom-Json - InputObject $messageString
584
+
585
+ # Now we can run any filters that are scriptblocks or commands.
553
586
if ($filter ) {
554
587
foreach ($fil in $Filter ) {
555
- if ($fil -is [ScriptBlock ] -or
588
+ if ($fil -is [ScriptBlock ] -or
556
589
$fil -is [Management.Automation.CommandInfo ]
557
590
) {
558
- if (& $fil $MessageObject ) {
559
- $FilteredCount ++
591
+ # Capture the output of the filter
592
+ $filterOutput = $MessageObject | & $fil $MessageObject
593
+ # if the output was falsy,
594
+ if (-not $filterOutput ) {
595
+ $FilteredCount ++ # filter out the message.
560
596
continue WebSocketMessageLoop
561
597
}
562
598
}
563
599
}
564
- }
600
+ }
565
601
602
+ # If -Skip was provided and we haven't skipped enough messages
566
603
if ($Skip -and ($SkipCount -le $Skip )) {
604
+ # then skip this message.
567
605
$SkipCount ++
568
606
continue WebSocketMessageLoop
569
607
}
570
-
571
- $MessageObject
572
-
573
- # If we are forwarding events
574
- if ($ForwardEvent -and $MainRunspace.Events.GenerateEvent ) {
575
- # generate an event in the main runspace
576
- $null = $MainRunspace.Events.GenerateEvent (
577
- " $SocketUrl " ,
578
- $ws ,
579
- @ ($MessageObject ),
580
- $MessageObject
581
- )
582
- }
608
+
609
+ # Now, emit the message object.
610
+ # (expressions that are not assigned will be outputted)
611
+ $MessageObject
583
612
613
+ # If we have a -First parameter, and we have not yet reached the maximum
614
+ # (after accounting for skips and filters)
584
615
if ($First -and ($MessageCount - $FilteredCount - $SkipCount ) -ge $First ) {
616
+ # then set the maximum to first (which will cancel this after the next loop)
585
617
$Maximum = $first
586
618
}
587
619
}
588
620
}
621
+
622
+ # If we want to decorate the output
589
623
if ($PSTypeName ) {
624
+ # clear it's typenames
590
625
$webSocketMessage.pstypenames.clear ()
591
- [Array ]::Reverse($PSTypeName )
592
- foreach ($psType in $psTypeName ) {
593
- $webSocketMessage.pstypenames.add ($psType )
594
- }
626
+ for ($typeNameIndex = $PSTypeName.Length - 1 ; $typeNameIndex -ge 0 ; $typeNameIndex -- ) {
627
+ # and add each type name in reverse order
628
+ $webSocketMessage.pstypenames.add ($PSTypeName [$typeNameIndex ])
629
+ }
630
+ }
631
+
632
+ # If we are forwarding events
633
+ if ($ForwardEvent -and $MainRunspace.Events.GenerateEvent ) {
634
+ # generate an event in the main runspace
635
+ $null = $MainRunspace.Events.GenerateEvent (
636
+ " $SocketUrl " ,
637
+ $ws ,
638
+ @ ($webSocketMessage ),
639
+ $webSocketMessage
640
+ )
595
641
}
596
- if ($handler ) {
597
- $psCmd =
642
+
643
+ # If we have an output handler, try to run it and get the output
644
+ $handledResponse = if ($handler ) {
645
+ # We may need to run the handler in a `[PowerShell]` command.
646
+ $psCmd =
647
+ # This is true if we want `NoLanguage` mode.
598
648
if ($runspace.LanguageMode -eq ' NoLanguage' -or
599
649
$runspacePool.InitialSessionState.LanguageMode -eq ' NoLanguage' ) {
650
+ # (in which case we'll call .GetPowerShell())
600
651
$handler.GetPowerShell ()
601
- } elseif ($Runspace -or $RunspacePool ) {
602
- [PowerShell ]::Create().AddScript($handler )
652
+ } elseif (
653
+ # or if we have a runspace or runspace pool
654
+ $Runspace -or $RunspacePool
655
+ ) {
656
+ # (in which case we'll `.Create()` and `.AddScript()`)
657
+ [PowerShell ]::Create().AddScript($handler , $true )
603
658
}
604
659
if ($psCmd ) {
660
+ # If we have a runspace, we'll use that.
605
661
if ($Runspace ) {
606
662
$psCmd.Runspace = $Runspace
607
663
} elseif ($RunspacePool ) {
664
+ # or, alternatively, we can use a runspace pool.
608
665
$psCmd.RunspacePool = $RunspacePool
609
666
}
667
+ # Now, we can invoke the command.
668
+ $psCmd.Invoke (@ ($webSocketMessage ))
610
669
} else {
670
+ # Otherwise, we'll just run the handler.
611
671
$webSocketMessage | . $handler
612
672
}
613
-
614
673
} else {
615
674
$webSocketMessage
616
- }
675
+ }
617
676
} catch {
618
677
Write-Error $_
619
678
}
620
679
}
621
680
681
+ # Now that the socket is closed,
682
+ # check for a status description.
683
+ # If there is one,
622
684
if ($ws.CloseStatusDescription ) {
685
+ # write an error.
623
686
Write-Error $ws.CloseStatusDescription - TargetObject $ws
624
687
}
625
688
}
0 commit comments