Accessing the API / event hubs via my own .NET client app

This I know is a vague question, but just looking for idea of possibilities before I investigate further.

Basically I want to have my own .NET client app (helper app) probably written in VB.NET which will be installed on a client machine (outside my own network!) which will then collect information such as disk space, error information etc etc and I want to then be able to send it to my powershell universal instance hosted (location to be determined, but perhaps Azure or any IIS / linux hosting platform) so I can then have dashboards to visualize the information for each client I have the client / helper app installed on.

I know you provide a Event Hub client app, but I don’t want to use that, I would prefer an SDK or way to use same functionality in my own app?

Finally if possible in that app I would want it to have similar functionality to the even hub client in that I can send a “command” from powershell universal sever to a specific client to invoke an action.

In principle is this doable?

This is possible. You’ll need to install the SignalR client in your app. Here’s the connection logic. It just connects up to the hub. It uses a different hub if authentication is enabled.


            var url = "eventhub";
            if (clientConnection.AppToken != null || clientConnection.UseDefaultCredentials)
            {
                url = "autheventhub";
            }

            var connection = new HubConnectionBuilder()
                .ConfigureLogging(logging =>
                {
                    logging.AddSerilog();
                    logging.SetMinimumLevel(LogLevel.Debug);
                })
                .WithUrl($"{clientConnection.Url}/{url}?group={clientConnection.Hub}", options =>
                {
                    if (clientConnection.AppToken != null)
                    {
                        options.AccessTokenProvider = () => Task.FromResult(clientConnection.AppToken)!;
                    }

                    if (handler != null)
                        options.HttpMessageHandlerFactory = _ => handler;

                    options.UseDefaultCredentials = clientConnection.UseDefaultCredentials;
                    
                    options.Headers.Add("PSUComputerName", Environment.MachineName);
                    options.Headers.Add("PSUUserName", Environment.UserName);
                    options.Headers.Add("PSUDomainName", Environment.UserDomainName);
                })
                .WithAutomaticReconnect(new RetryPolicy())
                .Build();

When it receives a “Module” message, it will invoke the command. This method will get the name of the command. The data is a PSSerialized string.

connection.On(clientConnection.Hub + "Module", (string command, string data, bool returnResult) => eventHubExecutor.ExecuteCommand(clientConnection.Hub, command , data, returnResult));

Here’s some psuedocode. PS expects the ExecuteCommand method to return immediately with an execution ID. If not, the hub will only let one command run at a time.

    public string ExecuteCommand(string hub, string command, string data, bool returnResult)
    {
        Log.Information($"Received event on hub {hub}.");

        var executionId = Guid.NewGuid().ToString();

        _ = Task.Run(() =>
        {
                var item = PSSerializer.Deserialize(data);
// run command 
                    _output[executionId] = output;    
         }
        return executionId;
    }

After executing the command, it will then attempt to get a result back for the command.

connection.On("GetResult", (string eventId) => eventHubExecutor.GetResult(eventId));

It will need to access the _output collection and return the result.

    public string GetResult(string executionId)
    {
        if (!_output.TryGetValue(executionId, out var result))
        {
            return "running";
        }

        _output.TryRemove(executionId, out _);
        return result;
    }

Hope that helps!

Hi Adam, thank you so much for that detailed reply, much appreciated.

So this would cover the part of being able to send commands and get a response. But what about just sending information from “my client” app to the powershell universal instance to be able to record customer information etc? I would just send results and diagnostic information in one go so to speak, so it would just contain an GUID / ID to indicate which client and then other data which I would store to view in dashboard etc

Sending info back to PSU would likely be done via an API and not an event hub. It’s arguably a bit simpler because you don’t need a web socket connection and could have your client app just make an HTTP request.

Currently, event hubs don’t have a push mechanism. It wouldn’t be too hard to implement on our end, but it would be very similar to what API endpoints already provide.

okay cool. Do you have any sample apps or code snippets showing how to both authenticate to and then send data to PSU using websocket etc?