Azure Service Bus with PowerShell


Microsoft describes Azure Service Bus as “cloud messaging as a service”, or MaaS for you who enjoy when your service categories rhyme. To simplify the service it lets you send a message to a queue, where another system can pick it up and act on it, similar to how Storage queues work. Among other things this lets you decouple solutions nicely, or add redundancy between layers if needed. If you’re interested in a deeper comparison between them Microsoft has written an article about it.

While both queuing technologies exist concurrently, Storage queues were introduced first, as a dedicated queue storage mechanism built on top of Azure Storage services. Service Bus queues are built on top of the broader messaging infrastructure designed to integrate applications or application components that may span multiple communication protocols, data contracts, trust domains, and/or network environments.

To summarize you could say that the Service Bus is a more advanced version of the service, or simply Storage queues on steroids. The relationship between the two services may of course come to change in the future, but let’s take a look at how to use the Service Bus today.

The Azure Service Bus API

Service Bus can be a solid option if we’re integrating with a system that needs us to send data to it from somewhere, especially if the system itself does not have an API. The system could set up queues that it reads from, and we can post to those and avoid solutions such as file transfer through FTP.

If you’re like me and want to send messages to this system using PowerShell, you might start with looking through the Az module. Note that if you’re working with an Azure Function (which is now a live service compared to when I wrote about it during the preview) there are bindings that may make the integration a lot easier, but that’s a topic for another day.

I already have the Az module installed, including Az.ServiceBus, but after I make my next point you’ll see why it’s not strictly necessary for this post, even though I recommend that you install the module if you work with Azure at all.

PipeHow:\Blog> Get-Command -Module Az.ServiceBus

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AzServiceBusIPRule                             1.1.0      Az.ServiceBus
Cmdlet          Add-AzServiceBusVirtualNetworkRule                 1.1.0      Az.ServiceBus
Cmdlet          Complete-AzServiceBusMigration                     1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusAuthorizationRule                  1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusGeoDRConfiguration                 1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusKey                                1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusMigration                          1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusNamespace                          1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusNetworkRuleSet                     1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusOperation                          1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusQueue                              1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusRule                               1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusSubscription                       1.1.0      Az.ServiceBus
Cmdlet          Get-AzServiceBusTopic                              1.1.0      Az.ServiceBus
Cmdlet          New-AzServiceBusAuthorizationRule                  1.1.0      Az.ServiceBus
Cmdlet          New-AzServiceBusGeoDRConfiguration                 1.1.0      Az.ServiceBus
Cmdlet          New-AzServiceBusKey                                1.1.0      Az.ServiceBus
Cmdlet          New-AzServiceBusNamespace                          1.1.0      Az.ServiceBus
Cmdlet          New-AzServiceBusQueue                              1.1.0      Az.ServiceBus
Cmdlet          New-AzServiceBusRule                               1.1.0      Az.ServiceBus
Cmdlet          New-AzServiceBusSubscription                       1.1.0      Az.ServiceBus
Cmdlet          New-AzServiceBusTopic                              1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusAuthorizationRule               1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusGeoDRConfiguration              1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusIPRule                          1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusMigration                       1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusNetworkRuleSet                  1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusQueue                           1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusRule                            1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusSubscription                    1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusTopic                           1.1.0      Az.ServiceBus
Cmdlet          Remove-AzServiceBusVirtualNetworkRule              1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusAuthorizationRule                  1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusGeoDRConfigurationBreakPair        1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusGeoDRConfigurationFailOver         1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusNamespace                          1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusNetworkRuleSet                     1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusQueue                              1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusRule                               1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusSubscription                       1.1.0      Az.ServiceBus
Cmdlet          Set-AzServiceBusTopic                              1.1.0      Az.ServiceBus
Cmdlet          Start-AzServiceBusMigration                        1.1.0      Az.ServiceBus
Cmdlet          Stop-AzServiceBusMigration                         1.1.0      Az.ServiceBus
Cmdlet          Test-AzServiceBusName                              1.1.0      Az.ServiceBus

Above are all commands included in the Az.ServiceBus and if you’re not sure what you should be looking for I’ll save you the time - there is no way to post to or read messages from a service bus queue using the module. This might not come as a surprise to you if you’ve already worked with Storage queues in PowerShell, so what can we do?

Reading through the official documentation for Service Bus Messaging we can see a few languages listed with quickstart guides, but they seem to be relying on SDKs and PowerShell is not among them.

While I’m sure we could figure out how to use the SDK in PowerShell as well, our most reliable and documented way is using the REST API. The format of the API is very standardized, works well with PowerShell’s capabilities for web requests and it’s something we come back to often on the blog.

Creating the Service Bus

We’ve found the API and where to look for information, so let’s look at creating our Service Bus, or rather our Service Bus Namespace, that we’ll work with.

You can do this in the Azure Portal as well, and if you haven’t worked with Azure Service Bus before you might want to do just that, to get a better overview of how the service works. You’re welcome to then delete the resource and come back here to follow along again, since we can actually use a few of the commands we found before and avoid leaving our comfy console for too long.

If you haven’t connected your account using Connect-AzAccount you’ll need to do that first, so that you’re logged in. Make sure that you’re selecting the right environment using the parameters of the command if you have several subscriptions or tenants connected to your account.

We need to do a few things before we can start working with the API.

Then we will explore a few of the operations, starting with posting a message to the queue.

PipeHow:\Blog> $RG = New-AzResourceGroup -Name 'test-servicebus-rg' -Location 'West Europe'
PipeHow:\Blog> $RG

ResourceGroupName : tst-servicebus-rg
Location          : westeurope
ProvisioningState : Succeeded
Tags              :
ResourceId        : /subscriptions/aaaaaaaa-1111-bbbb-2222-cccccccccccc/resourceGroups/tst-servicebus-rg

Once we have a resource group we can proceed with creating our namespace and queue that we will work with.

$Params = @{
    ResourceGroupName = $RG.ResourceGroupName
    Location = 'West Europe'
    SkuName = 'Basic'
    Name = 'tst-pipehow-servicebus'
}

Another thing that returns often on this blog is the method of using parameters as a hashtable, called Splatting. This lets us reuse common parameters between commands, decrease the length of the command and usually increases overall readability.

As for the actual command, we specify the resource group to create it in, the region of the resource, the SKU and the name of the new namespace.

PipeHow:\Blog> $ServiceBus = New-AzServiceBusNamespace @Params
PipeHow:\Blog> $ServiceBus

Name               : tst-pipehow-servicebus
Id                 : /subscriptions/aaaaaaaa-1111-bbbb-2222-cccccccccccc/resourceGroups/tst-servicebus-rg/providers/Microsoft.ServiceBus/namespaces/tst-pipehow-servicebus
ResourceGroupName  : tst-servicebus-rg
Location           : West Europe
Sku                : Name : Basic , Tier : Basic, Capacity :
Tags               :
ProvisioningState  : Succeeded
CreatedAt          : 2020-09-15 16:03:16
UpdatedAt          : 2020-09-15 16:04:00
ServiceBusEndpoint : https://tst-pipehow-servicebus.servicebus.windows.net:443/

I noticed that the command itself will not give very clear errors when creating a namespace with a name that is not available, so if you get stuck on this you can start with verifying that your $ErrorView variable is set to “Normal” for more information, or try to create the namespace in the portal with the same information and see if you get a more clear error message there.

When using splatting we can modify our hashtable to add and remove parameters that are not common between the commands, while keeping the ones that are. In this case we only have one common parameter, but as an example this is one way that it can be done.

$Params.Remove('Location')
$Params.Remove('SkuName')
$Params.Name = 'pipehow-queue'
$Params.Namespace = $ServiceBus.Name

Using the same hashtable for further splatting, next up is the queue.

PipeHow:\Blog> $Queue = New-AzServiceBusQueue @Params
PipeHow:\Blog> $Queue

Id                                  : /subscriptions/aaaaaaaa-1111-bbbb-2222-cccccccccccc/resourceGroups/tst-servicebus-rg/providers/Microsoft.ServiceBus/namespaces/tst-pipehow-servicebus/queues/pipehow-queue
Name                                : pipehow-queue
LockDuration                        : PT1M
AccessedAt                          : 0001-01-01 00:00:00
AutoDeleteOnIdle                    : P10675199DT2H48M5.4775807S
CreatedAt                           : 2020-09-15 16:09:30
DefaultMessageTimeToLive            : P14D
DuplicateDetectionHistoryTimeWindow : PT10M
DeadLetteringOnMessageExpiration    : False
EnableExpress                       : False
EnablePartitioning                  : False
MaxDeliveryCount                    : 10
MaxSizeInMegabytes                  : 5120
MessageCount                        : 0
CountDetails                        : Microsoft.Azure.Management.ServiceBus.Models.MessageCountDetails
RequiresDuplicateDetection          : False
RequiresSession                     : False
SizeInBytes                         : 0
Status                              : Active
UpdatedAt                           : 2020-09-15 16:09:30
ForwardTo                           :
ForwardDeadLetteredMessagesTo       :
EnableBatchedOperations             : False

Today we’ll only look at the basic operations of the queue, but as we can see above there are a lot of properties and settings that you can explore and set to adapt the service to your needs.

The Shared Access Signature

We have our resource, now we need to be able to access it using PowerShell. To use the REST API that I mentioned earlier we need to prove that we have right to access it in our code, adding authorization either using Azure AD or using something called a SAS token.

In a previous post we used a SAS token to work with an Azure Storage Table, and although the structure of it and the procedure to create it will be slightly different, the idea is the same.

We can either use the default policy RootManageSharedAccessKey for our namespace to create our token, or we can create a new one limited by rights and/or queue.

Reading the very thorough documentation around the Service Bus SAS we can see that there are three different policy rights that can be set:

  • ‘Send’ - Confers the right to send messages to the entity
  • ‘Listen’ - Confers the right to listen (relay) or receive (queue, subscriptions) and all related message handling
  • ‘Manage’ - Confers the right to manage the topology of the namespace, including creating and deleting entities

If we pretend that we’re building a small part of a larger solution where our app only needs to send data, we should create an appropriate policy to limit the access it has to only Send for the specific queue, making sure that our system won’t be able to read messages or post to other queues.

PipeHow:\Blog> $Params.Queue = $Queue.Name
PipeHow:\Blog> $Params.Rights = 'Send'
PipeHow:\Blog> $Policy = New-AzServiceBusAuthorizationRule @Params
PipeHow:\Blog> $Policy

Id     : /subscriptions/aaaaaaaa-1111-bbbb-2222-cccccccccccc/resourceGroups/tst-servicebus-rg/providers/Microsoft.ServiceBus/namespaces/tst-pipehow-servicebus/queues/pipehow-queue/authoriz
         ationRules/SendPolicy
Name   : SendPolicy
Rights : {Send}

Using this new policy we can finally create a SAS token that we will use in our Authorization header for our web requests.

The SAS Token

I would like to say that there are two main ways to go about getting the token, one way being quite a lot easier than the other, but that wouldn’t be true to my experience.

There is another command that we should be able to use to get the token since we have access to the environment where the namespace is created, but the resulting token is not valid. For the situations where we don’t have access, or as a workaround for the problem with the command, there is still another way to create it as long as we have a connection string, or at least a few vital parts of it, namely a key and the name of the policy.

The (Potentially) Short Path

The first way to create our token should be another command from the same module, but as of writing it doesn’t seem to work as intended.

PipeHow:\Blog> $Token = New-AzServiceBusAuthorizationRuleSASToken -KeyType Primary -AuthorizationRuleId $Policy.Id -ExpiryTime (Get-Date).AddHours(1)

We choose which key, primary or secondary, to base the token on. If we give an external party a key we might choose the secondary, and keep the primary to ourselves. This way we can avoid downtime in case a key we give to an external party is compromised.

We can specify both the start time and expiry time of our token, in this case I let it be valid for an hour starting when it was created, and I sent it the id of the SAS policy we just created.

The token that we receive back looks like this:

SharedAccessSignature
---------------------
 sr=tst-pipehow-servicebus.servicebus.windows.net%2fpipehow-queue&sig=<signature>&se=09/15/2020 20:40:01&skn=Primary

We will soon see why this is not a valid key, and why I think the command simply does not do what it’s supposed to.

The Long Path

For the situations where we don’t have access to the environment where the namespace is created, or in the current case where the simple short way does not work, let me show you the long and more complicated way of creating the token. This may also be preferable if you want to avoid a dependency on the Az.ServiceBus module completely.

First I need to explain what actually makes up the SAS token, once more with a little help of the same documentation. The API wants us to authorize ourselves by adding a header called Authorization with the token in the format below.

SharedAccessSignature sig=<signature-string>&se=<expiry>&skn=<keyName>&sr=<URL-encoded-resourceURI>

We can quickly see that it mostly matches the SAS token that we created using the command before, so let’s break down the different parts of the token, with the definitions from Microsoft’s documentation linked above.

  • se - Token expiry instant. Integer reflecting seconds since the epoch 00:00:00 UTC on 1 January 1970 (UNIX epoch) when the token expires.
  • skn - Name of the authorization rule.
  • sr - URI of the resource being accessed.
  • sig - Signature.

To summarize, se is the time of expiry, skn is the name of the policy we created, sr is the URL-encoded URI of the service bus namespace being accessed and sig is the tricky part.

If we compare it again with the token we received from the PowerShell command in the Az.ServiceBus module we see that both the se and skn seem to be wrong, not following Unix time and the name of the policy simply being the name of the key used. Feel free to let me know in the comment section if I’m simply using the command in the wrong way, regardless I opened an issue on Microsoft’s GitHub about it to let them know about the potential bug.

Either way, the sig, “signature”, or “signature-string” is really the crux of the token. Microsoft explains it as following:

The signature-string is the SHA-256 hash computed over the resource URI (scope as described in the previous section) and the string representation of the token expiry instant, separated by LF.

Even after reading that, looking at the provided pseudo-code below and finding an example of how to do it, it took me a moment to grasp exactly how to assemble the at this point somewhat elusive SAS token.

SHA-256('https://<yournamespace>.servicebus.windows.net/'+'\n'+ 1438205742)

In the Event Hub section of the REST API documentation there is a good example of how to create a SAS token according to the instructions above, which I will clean up and make the base of the solution further down.

Since the use case for this longer way of creating the SAS token may come with a few limitations I will not use the variables from earlier, instead I will assume that you only have access to a connection string, containing the endpoint, key and policy name. The only components that are actually required are one of the keys, and the name of the policy, but for simplicity I will use a connection string as the example since it is most likely what will be given to someone integrating with the Service Bus.

The connection strings can easily be found in the Azure Portal under our created Service Bus Namespace -> Queues -> QueueName -> Shared access policies > PolicyName. There is also a section for namespace-wide policies if you didn’t limit your policy to a single queue, including the default root policy.

I will walk through the code step by step to make it a little more clear, and post it all at the end.

$ConnectionString = 'Endpoint=sb://tst-pipehow-servicebus.servicebus.windows.net/;SharedAccessKeyName=SendPolicy;SharedAccessKey=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=;EntityPath=pipehow-queue'

$Pattern = 'Endpoint=(.+);SharedAccessKeyName=(.+);SharedAccessKey=(.+);EntityPath=(.+)'
([uri]$Endpoint),$PolicyName,$Key,$Queue = ($ConnectionString -replace $Pattern,'$1;$2;$3;$4') -split ';'

Don’t be intimidated by the crazy symbols, this is regex. In short we simply extract the variables from the string. Regex deserves its own post(s), but the .NET Quick Reference is always handy if you’re unsure of a specific character.

First we define our connection string. Then, using regex, we replace the entire string with only the strings found after the equal signs of each part, still separated by semicolon. Finally we split the result on semicolon and store the four parts in different variables by comma-separating them, casting $Endpoint to an [uri] since we will need both the full endpoint but also strip it from its protocol later. If you’re unsure of how that works, try simply running [uri]'https:\\google.com' in the console to see the different properties of the object.

# Depending on your environment you may need to load the assembly System.Web
# $null = [Reflection.Assembly]::LoadWithPartialName("System.Web")

$UrlEncodedEndpoint = [System.Web.HttpUtility]::UrlEncode($Endpoint)
$Expiry = [DateTimeOffset]::Now.ToUnixTimeSeconds() + 3600

$RawSignatureString = "$UrlEncodedEndpoint`n$Expiry"

We make sure that the endpoint we use will survive the web request by encoding it, and set the token expiry time as Unix time, in this case an hour from now using the nifty [DateTimeOffset] which has a method for the format. Since we have the key and full access to what the policy is set to, we ourselves decide how long the token will be valid for. Technically we could create a token valid for a long time and send it to someone else for yet another level of access control.

As for the above code it makes more sense if we go back to the definition of the signature string.

The signature-string is the SHA-256 hash computed over the resource URI (scope as described in the previous section) and the string representation of the token expiry instant, separated by LF.

LF is short for “Line Feed”, or simply newline, which in a PowerShell string is an escaped n using the backtick character. The SHA-256 part is the tricky one since cryptography is far from my area of expertise, but luckily Microsoft provided a solid example of what we need to do, and how to do it. We need to hash the signature string we assembled above containing the URI and expiry time (in Unix time) using our key, or rather using the raw bytes of it.

$HMAC = New-Object System.Security.Cryptography.HMACSHA256
$HMAC.Key = [Text.Encoding]::ASCII.GetBytes($Key)
$HashBytes = $HMAC.ComputeHash([Text.Encoding]::ASCII.GetBytes($RawSignatureString))
$SignatureString = [Convert]::ToBase64String($HashBytes)
$UrlEncodedSignatureString = [System.Web.HttpUtility]::UrlEncode($SignatureString)

After making sure to URL encode the final signature just as with our previous endpoint, we’re ready to assemble the SAS token!

Listing the previously defined parts of the token we can see that now have all of them, and that we’re ready to make our requests to the API.

$SASToken = "SharedAccessSignature sig=$UrlEncodedSignatureString&se=$Expiry&skn=$PolicyName&sr=$UrlEncodedEndpoint"

Using the API

Actually using the API is probably the simplest part of the entire ordeal. Since we used a policy that should only have access to post to the queue we created, we can also verify that it prevents us from reading once we’ve added a message.

According to the API documentation we need to post the message according to the following format:

http{s}://{serviceNamespace}.servicebus.windows.net/{queuePath&#124;topicPath}/messages|HTTP/1.1

Since the namespace we created is of the Basic SKU we don’t have support for topics, so it’s fairly straight forward. Let’s set up another hashtable for splatting and finally try it out.

$Params = @{
    Uri = "https://$($Endpoint.Host)/$Queue/messages"
    ContentType = 'text/plain;charset=utf-8'
    Method = 'Post'
    Body = 'Azure Service Bus with PowerShell | How'
    Headers = @{
        'Authorization' = $SASToken
    }
}

This is where the cast of the endpoint to an [uri] comes into play. The original URI comes with a sb:// protocol, which we can remove by using the Host property.

The documentation also specifies which content type to use but I found it to be more flexible than specified, supporting other formats such as plaintext or even json quite nicely.

PipeHow:\Blog> Invoke-RestMethod @Params

If the command worked you should have no output at all. We can now use other operations to see if the data is there, or simply go into the Azure Portal and read the data.

Here’s the entire code again, to make copying a little easier.

# Depending on your environment you may need to load the assembly System.Web
# $null = [Reflection.Assembly]::LoadWithPartialName("System.Web")

# Replace with your own connectionstring
$ConnectionString = '<your-connection-string>'
$TokenValidFor = 3600

# This part may need editing, EntityPath is specific to connection strings from policies on a queue level
$Pattern = 'Endpoint=(.+);SharedAccessKeyName=(.+);SharedAccessKey=(.+);EntityPath=(.+)'
([uri]$Endpoint),$PolicyName,$Key,$Queue = ($ConnectionString -replace $Pattern,'$1;$2;$3;$4') -split ';'

$UrlEncodedEndpoint = [System.Web.HttpUtility]::UrlEncode($Endpoint)
$Expiry = [DateTimeOffset]::Now.ToUnixTimeSeconds() + $TokenValidFor
$RawSignatureString = "$UrlEncodedEndpoint`n$Expiry"

$HMAC = New-Object System.Security.Cryptography.HMACSHA256
$HMAC.Key = [Text.Encoding]::ASCII.GetBytes($Key)
$HashBytes = $HMAC.ComputeHash([Text.Encoding]::ASCII.GetBytes($RawSignatureString))
$SignatureString = [Convert]::ToBase64String($HashBytes)
$UrlEncodedSignatureString = [System.Web.HttpUtility]::UrlEncode($SignatureString)

$SASToken = "SharedAccessSignature sig=$UrlEncodedSignatureString&se=$Expiry&skn=$PolicyName&sr=$UrlEncodedEndpoint"

$Params = @{
    Uri = "https://$($Endpoint.Host)/$Queue/messages"
    ContentType = 'text/plain;charset=utf-8'
    Method = 'Post'
    Body = 'Azure Service Bus with PowerShell | How'
    Headers = @{
        'Authorization' = $SASToken
    }
}

Invoke-RestMethod @Params

Now that we’ve sent a message to the queue, there are two main ways of reading data from a Service Bus. Peek locks the message from being read by any other sources, but leaves it intact. Receive reads the message too, but it also destroys it in the process.

Now it’s more or less about changing the Uri, Body and Method depending on the endpoint or operation. If we want to peek using PowerShell we can simply change the URI to append /head to the same endpoint, or we could have if we had the access. Since we set the access to only Send we’re not going to be able to peek or receive messages.

PipeHow:\Blog> $Params.Uri += '/head'
PipeHow:\Blog> $PeekResult = Invoke-RestMethod @Params

Invoke-RestMethod: Response status code does not indicate success: 401 (SubCode=40100: Unauthorized : Unauthorized access for 'PeekLock' operation on endpoint 'sb://tst-pipehow-servicebus.servicebus.windows.net/pipehow-queue/messages/head'.).

If we change the access policy rights using our variables from earlier, we will get a better result. Note that we need to set all three access rights when adding Manage, since it includes both Send and Listen.

PipeHow:\Blog> Set-AzServiceBusAuthorizationRule -ResourceGroupName $RG.ResourceGroupName -Namespace $ServiceBus.Name -Queue $Queue.Name -Name $Policy.Name -Rights 'Manage','Listen','Send'

Metadata and Broker Properties

We now have full access to the queue, but if we keep using the same command we will notice that we get a very plain result, simply the text content of the entry.

PS F:\GitHub\Blog> $Result = Invoke-RestMethod @Params
PS F:\GitHub\Blog> $Result

Azure Service Bus with PowerShell | How

This might be fine, but if we want more data such as the token used to unlock the message from the peek again, we can use Invoke-WebRequest instead. This lets us see the metadata of the response and look into the BrokerProperties json data found in the headers.

PS F:\GitHub\Blog> $Result = Invoke-WebRequest @Params
PS F:\GitHub\Blog> $Result.Headers.BrokerProperties | ConvertFrom-Json

DeliveryCount          : 1
EnqueuedSequenceNumber : 0
EnqueuedTimeUtc        : Tue, 15 Sep 2020 20:56:28 GMT
LockToken              : 448b4848-49b4-4f0d-b3c9-19936ddf6de0
LockedUntilUtc         : Tue, 15 Sep 2020 21:27:09 GMT
MessageId              : 8761c355a324411a86605b5e48caf2be
SequenceNumber         : 1
State                  : Active
TimeToLive             : 1209600

We can see that the lock is set for about 30 minutes, and using the MessageId together with the LockToken we could unlock it again for other systems to read the same message.

These BrokerProperties are not specific to reading these entries though, we can also add them when we send messages. Here is a list of them, and you can also specify custom properties that end up in the headers when you read them.

Conclusion

As we can see, there’s a lot to dive into when it comes to the Azure Service Bus messaging service, and I still feel like we barely scratched the surface. I’m hopeful that the command to create a SAS token will work better in the future, but we found a way to do it nonetheless, avoiding module dependency in the process.

I hope you learned something and got a piece of code or two to take with you, to explore and play around with the API, and for your future projects with Azure Storage queue’s more advanced MaaS cousin.

Comments

comments powered by Disqus