Last week, Jeff Hicks asked a question on the BurntToast repo that made me realize I've got a lot to work to do documenting the module. I mean, I already knew this, but it was the first time someone had said "I'm trying to figure this out using only the built-in help, and it's not working!"
One of the main things this highlighted, and a good place to start, was that I've never written about the how the module's "advanced" functions map to the structure of the resulting XML that Windows uses to display toast notifications. Nor how they all interact in their seemingly random order.
Right, let's start at the beginning—or rather the end—of the toast notification construction journey.
The layout and content of a toast notification, ignoring data bindings (which need more documentation too) and other metadata, is defined in an XML document. For a default notification created with BurntToast, that XML is:
<?xml version="1.0" encoding="utf-8"?> <toast> <visual> <binding template="ToastGeneric"> <text>Default Notification</text> <image src="" placement="appLogoOverride" hint-crop="circle" /> </binding> </visual> <audio src="ms-winsoundevent:Notification.Default" /> </toast>
If you knew the XML schema well enough, you could work directly with it.
Up until the release of BurntToast v0.5.0 in 2016, the module was entirely based on direct XML manipulation.
I'm so glad those days are in the past.
But no one wants to work directly with XML (and if you do, we can't be friends!)
The rest of this post is going to focus on the individual elements of a toast notification's XML document and how BurntToast works to, hopefully, make building it easier.
If you happen to want to forge your own path, without dealing with raw XML, check out the Microsoft Community Toolkit. This is what BurntToast uses, so that I too don't have to spend my life seeing XML!
A Hefty Example
In order to have something meaty to bite into, let's start with a more complex example.
This example is inspired by the Restaurant.xml demo in the Notifications Visualizer app. It's a great tool for testing toast notifications and is available from the Microsoft Store.
This is the toast that we'll be dissecting today:
And the XML behind this is:
<?xml version="1.0" encoding="utf-8"?> <toast> <visual> <binding template="ToastGeneric"> <text>Upcoming Reservation</text> <text>You have a booking at Wildfire tonight, make sure you know how to get there!</text> <image src="C:\Demos\Map.png" hint-removeMargin="false" /> <image src="C:\Demos\WildFire.jpg" placement="hero" /> <image src="C:\Demos\ChefIcon.png" placement="appLogoOverride" hint-crop="circle" /> </binding> </visual> <actions> <action content="Google Maps" arguments="https://www.google.com/maps/SNIP" activationType="protocol" /> <action content="Bing Maps" arguments="https://www.bing.com/maps?SNIP" activationType="protocol" /> </actions> </toast>
But how the heck did we get there?
Growing All Organic Toast
When creating toast notifications using BurntToast's advanced notifications, I begin with any images and text that'll be displayed on it. Let's start with the images.
$AppLogo = New-BTImage -Source 'C:\Demos\ChefIcon.png' -AppLogoOverride -Crop Circle $HeroImage = New-BTImage -Source 'C:\Demos\WildFire.jpg' -HeroImage $MapImage = New-BTImage -Source 'C:\Demos\Map.png'
There are three different types images here.
$AppLogois the icon that is displayed to the left of the main content on your toast. It is otherwise known as the "App Logo Override", as it replaces the logo that would normally be associated with the application popping the notification (PowerShell in this case.)
$HeroImageis the large image displayed across the very top of the notification, above all other content and stretching from edge to edge.
$MapImageis a normal image which displays under any text.
Text is next. There's a little less to worry about with text, as you're just specifying the string to display.
$TextHeading = New-BTText -Text 'Upcoming Reservation' $TextBody = New-BTText -Text 'You have a booking at Wildfire tonight, make sure you know how to get there!'
But then, what do we do with all of these objects that we're creating? We "bind" then into a "binding" object.
$Binding = New-BTBinding -Children $TextHeading, $TextBody, $MapImage -AppLogoOverride $AppLogo -HeroImage $HeroImage
The key thing here is the order in which you add your text objects. The first one supplied is considered to be the heading and will display first and bold. There's no other way to designate this, other than the order in which they're provided.
This maps through to our XML as shown in this splatter of arrows.
What next? We have our binding element; this now needs to go under a visual element. This is a touch boring in our use case today, as we're not using any features enabled through the visual element, so we'll just assign our binding to it.
$Visual = New-BTVisual -BindingGeneric $Binding
Looking one more layer up in our XML we can see that the next (and final) element is the toast element, but we're not ready for that yet. You'll notice that there's another element we need to prepare first.
This last section is our buttons. In the XML schema they're called an action, and are assigned to an actions element. Like your text and images, let's create the buttons first.
$GoogleButton = New-BTButton -Content 'Google Maps' -Arguments 'https://www.google.com/maps/place/Wildfire+Auckland/@-36.842,174.76443,15z/data=!4m5!3m4!1s0x0:0xd5bbf397c4772716!8m2!3d-36.842!4d174.76443?hl=en-GB' $BingButton = New-BTButton -Content 'Bing Maps' -Arguments 'https://www.bing.com/maps?osid=24c08897-bb68-48e5-95a8-fe2f70c5d53e&cp=-36.8421~174.762899&lvl=17&imgid=51ef1b68-a3e7-4fd8-a1e9-d04940a98398&v=2&sV=2&form=S00027'
Here, the content is the text to display on the button and the argument is the url to be opened when you click on a given button.
Now add the buttons to an action object.
$Actions = New-BTAction -Buttons $GoogleButton, $BingButton
Again, the order here is important. The first button specified will be on the left-hand side of the toast followed by any others in order.
Now we have all the components we need to wrap up all the content that describes our toast notification.
$Content = New-BTContent -Visual $Visual -Actions $Actions
It's at this point that you can take your XML document and redistribute it, as described in a previous post. Alternatively, if you want to pop your notification go ahead and submit it.
Submit-BTNotification -Content $Content
My original intention was to end with an image of the PowerShell code next to the XML and arrows connecting all the pieces. That ended up looking for too much like spaghetti.
Instead we'll end with the script in its entirety, annotated with how I think through the order of things.
# First, create all the component pieces $AppLogo = New-BTImage -Source 'C:\Demos\ChefIcon.png' -AppLogoOverride -Crop Circle $HeroImage = New-BTImage -Source 'C:\Demos\WildFire.jpg' -HeroImage $MapImage = New-BTImage -Source 'C:\Demos\Map.png' $TextHeading = New-BTText -Text 'Upcoming Reservation' $TextBody = New-BTText -Text 'You have a booking at Wildfire tonight, make sure you know how to get there!' # Then bind them together $Binding = New-BTBinding -Children $TextHeading, $TextBody, $MapImage -AppLogoOverride $AppLogo -HeroImage $HeroImage # And remember that these components are visual, but not actionable $Visual = New-BTVisual -BindingGeneric $Binding # Speaking of actionable, we're using actions right? $GoogleButton = New-BTButton -Content 'Google Maps' -Arguments 'https://www.google.com/maps/SNIP' $BingButton = New-BTButton -Content 'Bing Maps' -Arguments 'https://www.bing.com/maps?SNIP' # Don't forget that an action by itself is useless, even a single button needs to become plural $Actions = New-BTAction -Buttons $GoogleButton, $BingButton # Now all of the content is together... $Content = New-BTContent -Visual $Visual -Actions $Actions # We can submit it to the Operating System Submit-BTNotification -Content $Content
I hope all of that made sense. I realize there's a lot to BurntToast, and toast notifications in general, that need more and better documentation.
This is going to be a big focus of mine over the coming months, but it's hard to know what's needed when you're so close to the topic. Getting feedback in issues and discussions on GitHub is a great way of steering where attention should be directed.
If you've got any specific requests for documentation that should be accelerated, please do get in touch!
You can get all images and code from this posts example here.