If you have been following my blogs for a while, you already know that I have a special place in my heart for event-driven architecture. There is just something elegant about letting events do the heavy lifting for you!
Especially when utilizing modern approaches in Azure like Azure Functions, Azure Servicebus and my personal favorite βPowerShellβ π₯°things really start to come together and form a platform instead of just standalone components.
In this post, weβre diving into something a little bit more custom than the previous approach Iβve shown with EventGrid. Weβll be building a simple, event-driven βsend -> responseβ mechanism using Azure Functions, PowerShell and Azure Service Bus.
Also, in this blog, youβll find the βDeploy to Azureβ button deploying a basic Azure Function for you!
During this post, youβll see this icon π¬ which indicates that action is required so you get the full benefit out of this post.
And Iβve introduced the π which indicates that the subsequent part explains the technical details in the context of this post.
Letβs get started!
Some things explained
Before diving into all technical details letβs explain some things which weβll be using in this post.
Azure Service Bus
Azure Service Bus is a fully managed message broker from Microsoft Azure. Itβs designed to connect different applications, services, and systems, even when theyβre not online at the same time. Think of it as a post office π¨ that handles reliable message delivery between senders and receivers, without either needing to know anything about each other directly.
Queues vs Topics
Letβs talk about one of the classic questions when working with Azure Service Bus: whatβs the difference between queues and topics? π€
Imagine youβre running a coffee shop βοΈ.
Queues – One line, one barista
A queue is like a single line of customers waiting to order from one barista. Each customer (message) waits their turn. The first one in line gets served first (FIFO: First-In-First-Out), and once the order is taken, that customer leaves the queue. No one else gets that same order, it was meant for that one barista (or function) only.
This is great for point-to-point communication. One sender, one receiver. Nice and clean!
π Use queues when you want one consumer to process each message.
Topics β One announcement, multiple listeners
Now, a topic is more like making an announcement over the shopβs announcement system π€ βFree croissants at the counter!β π₯
Everyone in the shop hears it, but only the people whoβve signed up for βFree Food Alertsβ (subscribers) will jump up to claim theirs. Each person whoβs subscribed can act on that same message independently. Some might ignore it, some might react, but the message was sent once and handled by many.
This is perfect for publish/subscribe scenarios where one sender wants to notify multiple, potentially different, receivers.
π Use topics when multiple consumers need to react to the same message, each in their own way.
So to summarize things:
- Queue = single path, one consumer.
- Topic = broadcast with multiple tailored subscriptions.
Prepare the deployment
You can choose as promised π to use the βLet me deploy it for youβ functionality. Or deploy everything on your own. No worries Iβll provide the code for the business logic on the way.
Deploy on your own:
If you want to deploy all resources on your own, make sure these get deployed:
- Storage account
- Function App (PowerShell 7.4 runtime)
- App Service Plan
- Service Bus NameSpace
- Also add a queue!
You should end up with something like below:

Let me deploy it for you:
Let me deploy it for you! π Click the button below to deploy everything you need to get started!
Azure Function
In this setup, the Azure Function will be the real workhorse! itβs the one actually executing our business logic.
Weβll configure it so that it listens to messages from the Azure Service Bus. Once a message arrives, the Azure Function gets triggered and takes over from there. This is where your logic lives, processing data, calling APIs, triggering other systemsβ¦ whatever your use case demands!
Think of it like this:
The Service Bus is the messenger π§Ύ delivering a sealed envelope (message), and the Azure Function is the person opening that envelope and taking action based on what’s inside. π―
So, while the Service Bus handles the transportation and delivery, the Azure Function is where the decision-making and actual processing happen.
π¬ Modify the Azure function as the steps describe below
- Create a new Azure Function in the Function App with the βAzure Service Bus Queue Triggerβ
- Make a new ServiceBus connection and point it to your Service Bus
- π Donβt forget to put the right queue name in there! Otherwise our messages wonβt reach their destination!
- Now add the code below to the function
using namespace System.Net
param($mySbMsg, $TriggerMetadata)
Write-Host "π ServiceBus Message Received!"
Write-Host "π
Timestamp: $(Get-Date)"
Write-Host "π Message ID: $($TriggerMetadata.MessageId)"
Write-Host "π Message Type: $($mySbMsg.GetType().FullName)"
if ($mySbMsg -is [hashtable] -or $mySbMsg -is [System.Collections.Specialized.OrderedDictionary]) {
Write-Host "π Message Content (Object):"
$mySbMsg | ConvertTo-Json -Depth 3 | Write-Host
if ($mySbMsg.message) {
Write-Host "π Actual Message: $($mySbMsg.message)"
}
if ($mySbMsg.timestamp) {
Write-Host "β° Message Timestamp: $($mySbMsg.timestamp)"
}
if ($mySbMsg.source) {
Write-Host "π‘ Message Source: $($mySbMsg.source)"
}
} else {
Write-Host "π Message Content (Raw): $mySbMsg"
}
Write-Host "π Delivery Count: $($TriggerMetadata.DeliveryCount)"
Write-Host "β° Enqueued Time: $($TriggerMetadata.EnqueuedTimeUtc)"
try {
if ($mySbMsg -is [hashtable] -or $mySbMsg -is [System.Collections.Specialized.OrderedDictionary]) {
Write-Host "β
Processing structured message:"
foreach ($key in $mySbMsg.Keys) {
Write-Host " $key`: $($mySbMsg[$key])"
}
if ($mySbMsg.message) {
$actualMessage = $mySbMsg.message
Write-Host "π― Processing actual message content: $actualMessage"
}
} else {
if ($mySbMsg -match '^[\{\[].*[\}\]]$') {
$messageObject = $mySbMsg | ConvertFrom-Json
Write-Host "β
Successfully parsed JSON message:"
$messageObject | ConvertTo-Json -Depth 3 | Write-Host
} else {
Write-Host "π Plain text message: $mySbMsg"
}
}
Write-Host "π Message Properties:"
if ($TriggerMetadata.UserProperties) {
$TriggerMetadata.UserProperties | ConvertTo-Json -Depth 2 | Write-Host
} else {
Write-Host " No user properties"
}
Write-Host "βοΈ Processing message..."
Start-Sleep -Seconds 1
Write-Host "β
Message processed successfully!"
} catch {
Write-Error "β Error processing message: $($_.Exception.Message)"
Write-Error "Stack Trace: $($_.Exception.StackTrace)"
throw
}
Write-Host "π Message processing completed."
Write-Host "βββββββββββββββββββββββββββββββββββββββββββββββββββ"
π The service connection as mentioned above to the Service Bus is important! Missing any confiscations here will result in a non-working setup. If you forgot and need to modify you can do so on the integration page of the function as shown below

Eventually your trigger should look like something below (the queue name is different for each individual case if you havenβt used the βlet me deploy it for you functionalityβ

Preparing our first message
Before we can send out our first message to the Service bus there are some variables which we need to know. The Service bus contains an endpoint, this endpoint is used for delivery systems so they know where to drop a message.
π¬ Find and note down the Service bus connection string. You can find it by going to the Service Bus on the βShared access policies pageβ

On the right you will see the connection string:

Copy the value of the primary connection string and store it π the script Iβll provision for you needs it as input parameter.
π¬ Also note down the name of the Service bus queue youβve created. You can find it on the Service Bus underneath βqueuesβ

Sending the first message
Now letβs run the script Iβve prepared for you.
π¬ Run the script below and supply it with the parameters from the step above where we gathered the connection string and the queue name.
using namespace System.Net
param([string] $mySbMsg, $TriggerMetadata)
Write-Host "π ServiceBus Message Received!"
Write-Host "π
Timestamp: $(Get-Date)"
Write-Host "π Message ID: $($TriggerMetadata.MessageId)"
Write-Host "π Message Content: $mySbMsg"
Write-Host "π Delivery Count: $($TriggerMetadata.DeliveryCount)"
Write-Host "β° Enqueued Time: $($TriggerMetadata.EnqueuedTimeUtc)"
try {
if ($mySbMsg -match '^[\{\[].*[\}\]]$') {
$messageObject = $mySbMsg | ConvertFrom-Json
Write-Host "β
Successfully parsed JSON message:"
$messageObject | ConvertTo-Json -Depth 3 | Write-Host
} else {
Write-Host "π Plain text message: $mySbMsg"
}
Write-Host "π Message Properties:"
if ($TriggerMetadata.UserProperties) {
$TriggerMetadata.UserProperties | ConvertTo-Json -Depth 2 | Write-Host
}
Write-Host "βοΈ Processing message..."
Start-Sleep -Seconds 2
Write-Host "β
Message processed successfully!"
} catch {
Write-Error "β Error processing message: $($_.Exception.Message)"
Write-Error "Stack Trace: $($_.Exception.StackTrace)"
throw
}
Write-Host "π Message processing completed."
Write-Host "βββββββββββββββββββββββββββββββββββββββββββββββββββ"
π In my example I run it with:
.\Send-ServiceBusMessage.ps1 -ConnectionString “Endpoint=sb://sbbpas.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxxxxxxxxxxxx” -QueueName messagequeue
I named it βSend-ServiceBusMessage.ps1β
Validating the message arrival
When the message is sent by the PowerShell script you can see on the Service bus landing page that the amount of messages increases (note; this does take some time to refresh)

You can even drop down in the queue to see the actual message (but make sure nothing is listening at the queue)
π If your function is already started and listening this message wonβt be visible, It will immediately be delivered to the function and marked as βprocessedβ and will be removed from the bus.

π¬ Now open the Azure Function and sent a new message by repeating the script
Your view should be as below. When the messages arrives at the Service bus the function will be triggered and the code is executed.

You can see all the message details which is printed by our code

Summary
Thatβs a wrap! π
In this blog, we took a closer look at how to create a simple but powerful send β response event-driven mechanism using Azure Service Bus, Azure Functions, and of course… PowerShell π.
We started by laying the foundation, what Azure Service Bus is, how queues and topics differ (βοΈ remember the barista vs. announcement system analogy?)
We built an Azure Function to act as our business logic engine, ready to jump into action as soon as a message lands in our queue.
We sent our first message using PowerShell and watched as everything came together β¨.
And finally, we saw it all in action: message sent β message received β business logic executed.
π This post is all about combining the right Azure tools to build clean, scalable, event-driven platforms without overcomplicating things!
π¬ If you followed along step-by-step, you now have a working solution that you can expand, extend, or plug into a larger architecture.
Thanks again for reading! I hope this post inspires you to explore more creative ways to use Azure Functions, Service Bus, and PowerShell together. Let me know what youβll build next! π