Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a Websocket client to open a long-lived connection to a URL, using PowerShell V2?

I am trying to use PowerShell V2 (testing purposes) to initiate a real-time messaging (rtm) instance with Slack. But according to Slack's FAQ, to connect to their rtm API, I need to use the wss:// protocol via a Websocket client to stream events associated. I am also trying to make it an asynchronous connection (receiving as well as connecting).

This doesn't work :

$webSock = New-Object System.Net.WebSocket.ClientWebSocket
$client = New-Object System.Threading.CancellationToken

One other thing is that I need a function to convert from JSON in PowerShell V2.

I tried using this but it doesn't work too:

function ConvertFrom-Json20([object] $item){ 
    add-type -assembly system.web.extensions
    $ps_js=new-object system.web.script.serialization.javascriptSerializer

    #The comma operator is the array construction operator in PowerShell
    return ,$ps_js.DeserializeObject($item)
}
like image 223
r3dfl4g Avatar asked Oct 26 '16 08:10

r3dfl4g


People also ask

How do WebSockets work?

- Kevin Sookocheff How Do Websockets Work? A WebSocket is a persistent connection between a client and server. WebSockets provide a bidirectional, full-duplex communications channel that operates over HTTP through a single TCP/IP socket connection. At its core, the WebSocket protocol facilitates message passing between a client and server.

How do I connect to a WebSocket server?

All you have to do is call the WebSocket constructor and pass in the URL of your server. Once the connection has been established, the open event will be fired on your Web Socket instance.

Are there any security concerns with using WebSocket?

Since the WebSocket re-uses the HTTP connection, there are potential security concerns if either side interprets WebSocket data as an HTTP request. After the client receives the server response, the WebSocket connection is open to start transmitting data.

What is the correct version of the WebSocket protocol?

The only accepted version of the WebSocket protocol is 13. Any other version listed in this header is invalid. Together, these headers would result in an HTTP GET request from the client to a ws:// URI like in the following example:


2 Answers

Oddly enough, I had this same need recently. Thanks to Mark Wragg, and his helpful link, here is a quick bit of code to get this going. You'll need at least Windows 8 and Server 2012 to make these things work.

Try{  
    Do{
        $URL = 'ws://YOUR_URL_HERE/API/WebSocketHandler.ashx'
        $WS = New-Object System.Net.WebSockets.ClientWebSocket                                                
        $CT = New-Object System.Threading.CancellationToken
        $WS.Options.UseDefaultCredentials = $true

        #Get connected
        $Conn = $WS.ConnectAsync($URL, $CT)
        While (!$Conn.IsCompleted) { 
            Start-Sleep -Milliseconds 100 
        }
        Write-Host "Connected to $($URL)"
        $Size = 1024
        $Array = [byte[]] @(,0) * $Size

        #Send Starting Request
        $Command = [System.Text.Encoding]::UTF8.GetBytes("ACTION=Command")
        $Send = New-Object System.ArraySegment[byte] -ArgumentList @(,$Command)            
        $Conn = $WS.SendAsync($Send, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $CT)

        While (!$Conn.IsCompleted) { 
            #Write-Host "Sleeping for 100 ms"
            Start-Sleep -Milliseconds 100 
        }

        Write-Host "Finished Sending Request"

        #Start reading the received items
        While ($WS.State -eq 'Open') {                        

            $Recv = New-Object System.ArraySegment[byte] -ArgumentList @(,$Array)
            $Conn = $WS.ReceiveAsync($Recv, $CT)
            While (!$Conn.IsCompleted) { 
                    #Write-Host "Sleeping for 100 ms"
                    Start-Sleep -Milliseconds 100 
            }

            #Write-Host "Finished Receiving Request"

            Write-Host [System.Text.Encoding]::utf8.GetString($Recv.array)


        }   
    } Until ($WS.State -ne 'Open')

}Finally{

    If ($WS) { 
        Write-Host "Closing websocket"
        $WS.Dispose()
    }

}
like image 52
Vince Pike Avatar answered Sep 16 '22 12:09

Vince Pike


It is possible to use .NET's System.Net.WebSockets.ClientWebSocket class to do this. You need to be running Windows 8 or Server 2012 or newer as your underlying OS to utilise this class, so therefore I think you'd have at least PowerShell v3 regardless (and as a result the ConvertFrom-Json cmdlet). You also need to make use of the System.ArraySegment .NET class.

I've created a simple framework that demonstrates how to use the various classes to interact with the Slack RTM API from a PowerShell script. You can find the project on GitHub here: https://github.com/markwragg/Powershell-SlackBot

I've also blogged about it in more detail here: http://wragg.io/powershell-slack-bot-using-the-real-time-messaging-api/

like image 29
Mark Wragg Avatar answered Sep 19 '22 12:09

Mark Wragg