Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions MQTTnet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.Extensions.TopicTem
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.Server", "Source\MQTTnet.Server\MQTTnet.Server.csproj", "{C876EFFD-C5AD-4E26-BD9F-4C48252C02BC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTnet.PowerShell", "Source\MQTTnet.PowerShell\MQTTnet.PowerShell.csproj", "{37B129C5-0231-4EB5-AF13-77959068911C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -79,6 +81,10 @@ Global
{C876EFFD-C5AD-4E26-BD9F-4C48252C02BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C876EFFD-C5AD-4E26-BD9F-4C48252C02BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C876EFFD-C5AD-4E26-BD9F-4C48252C02BC}.Release|Any CPU.Build.0 = Release|Any CPU
{37B129C5-0231-4EB5-AF13-77959068911C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{37B129C5-0231-4EB5-AF13-77959068911C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{37B129C5-0231-4EB5-AF13-77959068911C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{37B129C5-0231-4EB5-AF13-77959068911C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
47 changes: 47 additions & 0 deletions Source/MQTTnet.PowerShell/Cmdlets/ConnectMqttSessionCmdlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Management.Automation;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet(VerbsCommunications.Connect, "MqttSession")]
[OutputType(typeof(MqttClientConnectResult))]
public class ConnectMqttSessionCmdlet : PSCmdlet
{
[Parameter]
public SwitchParameter CleanSession { get; set; } = true;

[Parameter]
public string? ClientId { get; set; } = Guid.NewGuid().ToString();

[Parameter(Mandatory = true)]
public required new string Host { get; set; }

[Parameter]
public string? Password { get; set; }

[Parameter]
public int Port { get; set; } = 1883;

[Parameter(Mandatory = true, ValueFromPipeline = true)]
public required PsMqttSession Session { get; set; }

[Parameter]
public string? Username { get; set; }

[Parameter]
public SwitchParameter UseTls { get; set; }

protected override void ProcessRecord()
{
var clientOptionsBuilder = new MqttClientOptionsBuilder();
clientOptionsBuilder.WithTcpServer(Host, Port);

if (Username != null)
{
clientOptionsBuilder.WithCredentials(Username, Password);
}

var response = Session.GetClient().ConnectAsync(clientOptionsBuilder.Build()).GetAwaiter().GetResult();

WriteObject(response);
}
}
31 changes: 31 additions & 0 deletions Source/MQTTnet.PowerShell/Cmdlets/DisconnectMqttSessionCmdlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Management.Automation;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet(VerbsCommunications.Disconnect, "MqttSession")]
public class DisconnectMqttSessionCmdlet : PSCmdlet
{
[Parameter]
public MqttClientDisconnectOptionsReason Reason { get; set; } = MqttClientDisconnectOptionsReason.NormalDisconnection;

[Parameter]
public string? ReasonString { get; set; }

[Parameter(Mandatory = true, ValueFromPipeline = true)]
public required PsMqttSession Session { get; set; }

[Parameter]
public uint SessionExpiryInterval { get; set; }

protected override void ProcessRecord()
{
if (Session.GetClient().IsConnected)
{
var options = new MqttClientDisconnectOptionsBuilder().WithSessionExpiryInterval(SessionExpiryInterval).WithReason(Reason).WithReasonString(ReasonString).Build();

Session.GetClient().DisconnectAsync(options).GetAwaiter().GetResult();
}

WriteObject("Disconnected.");
}
}
13 changes: 13 additions & 0 deletions Source/MQTTnet.PowerShell/Cmdlets/NewMqttSessionCmdlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Management.Automation;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet(VerbsCommon.New, "MqttSession")]
[OutputType(typeof(PsMqttSession))]
public class NewMqttSessionCmdlet : PSCmdlet
{
protected override void ProcessRecord()
{
WriteObject(new PsMqttSession());
}
}
52 changes: 52 additions & 0 deletions Source/MQTTnet.PowerShell/Cmdlets/PublishMqttMessageCmdlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Management.Automation;
using System.Text;
using MQTTnet.Protocol;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet(VerbsData.Publish, "MqttMessage")]
public class PublishMqttMessageCmdlet : PSCmdlet
{
[Parameter(Mandatory = true)]
public string? Payload { get; set; }

[Parameter]
public int QoS { get; set; } = 0;

[Parameter]
public SwitchParameter Retain { get; set; }

[Parameter(Mandatory = true, ValueFromPipeline = true)]
public required PsMqttSession Session { get; set; }

[Parameter(Mandatory = true)]
public required string Topic { get; set; }

public string? ContentType { get; set; }

public string? ResponseTopic { get; set; }

public ushort TopicAlias { get; set; }

public uint MessageExpiryInterval { get; set; }

protected override void ProcessRecord()
{
// if (Session == null || !Session.IsConnected)
// throw new InvalidOperationException("Session not connected.");

var msg = new MqttApplicationMessageBuilder().WithTopic(Topic)
.WithPayload(Encoding.UTF8.GetBytes(Payload ?? string.Empty))
.WithQualityOfServiceLevel((MqttQualityOfServiceLevel)QoS)
.WithRetainFlag(Retain)
.WithContentType(ContentType)
.WithResponseTopic(ResponseTopic)
.WithTopicAlias(TopicAlias)
.WithMessageExpiryInterval(MessageExpiryInterval)
.Build();

var response = Session.GetClient().PublishAsync(msg).GetAwaiter().GetResult();

WriteObject(response);
}
}
74 changes: 74 additions & 0 deletions Source/MQTTnet.PowerShell/Cmdlets/ReceiveMqttMessageCmdlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Management.Automation;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet(VerbsCommunications.Receive, "MqttMessage")]
[OutputType(typeof(PsMqttMessage))]
public class ReceiveMqttMessageCmdlet : PSCmdlet
{
[Parameter(Mandatory = true, ValueFromPipeline = true)]
public required PsMqttSession Session { get; set; }

[Parameter]
[ValidateRange(0, int.MaxValue)]
public int TimeoutSeconds { get; set; } = 0;

protected override void ProcessRecord()
{
var tcs = new TaskCompletionSource<PsMqttMessage>();
EventHandler<PsMqttMessage>? handler = null;
CancellationTokenSource? cts = null;

try
{
handler = (s, e) =>
{
if (!tcs.Task.IsCompleted)
{
tcs.TrySetResult(e);
}
};

Session.MessageReceived += handler;

// Optionaler Timeout
if (TimeoutSeconds > 0)
{
cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(TimeoutSeconds));
cts.Token.Register(() =>
{
if (!tcs.Task.IsCompleted)
{
tcs.TrySetCanceled();
}
});
}

WriteVerbose("Waiting for next MQTT message...");

try
{
var message = tcs.Task.GetAwaiter().GetResult();
WriteObject(message);
}
catch (TaskCanceledException)
{
WriteWarning($"Timeout after {TimeoutSeconds} seconds — no message received.");
}
}
finally
{
if (handler != null)
{
Session.MessageReceived -= handler;
}

cts?.Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet(VerbsLifecycle.Register, "MqttMessageHandler")]
public class RegisterMqttMessageHandlerCmdlet : PSCmdlet
{
[Parameter(Mandatory = true, ValueFromPipeline = true)]
public required PsMqttSession Session { get; set; }

[Parameter(Mandatory = true)]
public ScriptBlock? Action { get; set; }

protected override void ProcessRecord()
{
EventHandler<PsMqttMessage> handler = (s, e) =>
{
//throw new NotImplementedException();
//InvokeCommand.InvokeScript(Action, false, PipelineResultTypes.Output, null, new object[] { e.Topic, e.Payload });
};

Session.MessageReceived += handler;
WriteObject($"Handler registered for MQTT messages on session.");
}
}
16 changes: 16 additions & 0 deletions Source/MQTTnet.PowerShell/Cmdlets/RemoveMqttSessionCmdlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Management.Automation;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet(VerbsCommon.Remove, "MqttSession")]
public class RemoveMqttSessionCmdlet : PSCmdlet
{
[Parameter(Mandatory = true, ValueFromPipeline = true)]
public required PsMqttSession Session { get; set; }

protected override void ProcessRecord()
{
Session.Dispose();
WriteObject("Session removed.");
}
}
55 changes: 55 additions & 0 deletions Source/MQTTnet.PowerShell/Cmdlets/SubscribeMqttTopicCmdlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Management.Automation;
using MQTTnet.Protocol;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet("Subscribe", "MqttTopic")]
[OutputType(typeof(MqttClientSubscribeResult))]
public class SubscribeMqttTopicCmdlet : PSCmdlet
{
[Parameter]
public bool NoLocal { get; set; }

[Parameter]
public int QoS { get; set; } = 0;

[Parameter]
public bool RetainAsPublished { get; set; }

[Parameter]
public MqttRetainHandling RetainHandling { get; set; } = MqttRetainHandling.SendAtSubscribe;

[Parameter(Mandatory = true, ValueFromPipeline = true)]
public required PsMqttSession Session { get; set; }

[Parameter]
public uint SubscriptionIdentifier { get; set; }

[Parameter(Mandatory = true)]
public required string Topic { get; set; }

protected override void ProcessRecord()
{
var topicFilter = new MqttTopicFilterBuilder().WithTopic(Topic)
.WithQualityOfServiceLevel((MqttQualityOfServiceLevel)QoS)
.WithNoLocal(NoLocal)
.WithRetainAsPublished(RetainAsPublished)
.WithRetainHandling(RetainHandling)
.Build();

var options = new MqttClientSubscribeOptionsBuilder().WithTopicFilter(topicFilter);

if (SubscriptionIdentifier > 0)
{
options.WithSubscriptionIdentifier(SubscriptionIdentifier);
}

var response = Session.GetClient().SubscribeAsync(options.Build()).GetAwaiter().GetResult();

WriteObject(response);
}
}
23 changes: 23 additions & 0 deletions Source/MQTTnet.PowerShell/Cmdlets/UnsubscribeMqttTopicCmdlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Management.Automation;

namespace MQTTnet.PowerShell.Cmdlets;

[Cmdlet("Unsubscribe", "MqttTopic")]
[OutputType(typeof(MqttClientUnsubscribeResult))]
public class UnsubscribeMqttTopicCmdlet : PSCmdlet
{
[Parameter(Mandatory = true, ValueFromPipeline = true)]
public required PsMqttSession Session { get; set; }

[Parameter(Mandatory = true)]
public required string Topic { get; set; }

protected override void ProcessRecord()
{
var options = new MqttClientUnsubscribeOptionsBuilder().WithTopicFilter(Topic).Build();

var response = Session.GetClient().UnsubscribeAsync(options).GetAwaiter().GetResult();

WriteObject(response);
}
}
Loading