Tag Archives: Json

Microsoft Teams MessageCards

‘Sup PSHomies,

I was excited to give the MS Teams module a go! I was secretly hoping for a cmdlet to send messages to channels. Unfortunately no such luck… yet! If push comes to shove you can always take the Graph route! 😉

I posted the blog on social media and that generated some interesting ideas. Emotions and opinions varied quite a bit. Prateek raised an interesting question on whether slack would become obsolete in the near future. MS Teams is gaining momentum and it integrates nicely in Microsoft’s eco system, so why wouldn’t you use it? It doesn’t have to be black or white, use whatever adds value to your business I’d say!

This is where social media can be a treasure trove at times, got an interesting tip from Brett Miller on posting messages to channels using webhooks! Ah! the missing cmdlet I was hoping for! “So basically it’s just an Invoke-RestMethod?” Cool! I gave it a spin:

New-TeamMessage

Nice! Hmmm… Webhooks eh? Sounds familiar… Where did I read about that? Ah yes! Stefan Stranger did a blog about that. To be honest, I did read his blog, but at that time I didn’t have access to Teams… 😉 Just follow his instructions and you’re golden!

Here’s when the fun really started! Come to find out that there’s a lot more you can post using the message card reference! There’s even a card playground where you can try out your message cards. It’s all JSON, no problem, we’ve got cmdlets for that.

There’s a whole design guide on Messagecards. Best of all it supports MarkDown format! I tried a sending a table but that didn’t work as planned.

Just imagine the automation possibilities here… I understand now why ChatOps is really taking off…

My first attempt at DSL

Looking at the MessageCard format I thought: “This would be interesting as a DSL (Domain Specific Language) implementation… Hmmm…” I’ve been meaning to look into DSL after reading Kevin Marquette’s blog series on the subject. Seems now is a good time as any to start! This is what I came up with so far… It’s a work in progress ( sharing is caring) , but it works!

#region MessageCard function helpers
function MessageCard {
param([scriptblock]$ScriptBlock)
$newScript = "@{$($ScriptBlock.ToString())}"
$newScriptBlock = [scriptblock]::Create($newScript)
& $newScriptBlock
}
function section {
param([scriptblock]$ScriptBlock)
$newScript = "[Ordered]@{$($ScriptBlock.ToString())}"
$newScriptBlock = [scriptblock]::Create($newScript)
& $newScriptBlock
}
function fact {
param([scriptblock]$ScriptBlock)
$Invoked = $ScriptBlock.Invoke()
$Invoked.Keys |
ForEach-Object {
@{
Name = $_
Value = $Invoked.$_
}
}
}
#endregion
#region Main
$NewMessage = MessageCard {
summary = 'This is the summary property'
title = "This is the card's title property"
text = 'This is the cards text property.'
sections = @(
section {
activityTitle = 'Activity Title'
activitySubtitle = 'Activity **Sub**Title'
images = @(
@{
image = "http://connectorsdemo.azurewebsites.net/images/WIN12_Scene_01.jpg"
title = "This is the image alternate text Pic 01"
}
@{
image = "http://connectorsdemo.azurewebsites.net/images/WIN12_Anthony_02.jpg"
title = "This is the image alternate text Pic 02"
}
)
PotentialAction = @(
@{
'@type' = 'Actioncard'
Name = 'Comment'
Inputs = @(
@{
'@type' = 'TextInput'
Id = 'Comment'
isMultiLine = $true
Title = 'Input title property'
}
)
Actions = @(
@{
'@type' = 'HttpPOST'
Name = 'Save'
Target = 'http://...'
}
)
}
@{
'@type' = 'Actioncard'
Name = 'Due Date'
Inputs = @(
@{
'@type' = 'DateInput'
Id = 'dueDate'
Title = 'Input due date'
}
)
Actions = @(
@{
'@type' = 'HttpPOST'
Name = 'Save'
Target = 'http://...'
}
)
}
)
}
section {
title = 'Details:'
facts = fact {
@{
GivenName = 'Irwin'
SurName = 'Strachan'
}
}
}
section {
activityTitle = 'Default MD Support'
activitySubtitle = 'Activity **Subtitle**'
facts = fact {
@{
Email = 'Irwin@DosSantos.ca'
WebSite = '[pshirwins](https://pshirwin.wordpress.com)'
}
}
}
)
}
$restparams = @{
Uri = "Your WebHook Uri"
Method = 'POST'
Body = $($NewMessage | ConvertTo-Json -Depth 6)
ContentType = 'application/JSON'
}
Invoke-RestMethod @restparams
#endregion

And here’s the result:

New-MessageCard

I used the full card format as reference.  I realize that others in the community could easily knock this out the park. Maybe we can make this a community project? I would love to see what the possibilities are here…

Turns out not having a Send-TeamMessage wasn’t as painful as I thought it would be. Many ways to Rome…

Shout out to Brett & Stefan! Gotta love the PowerShell community!!!

Hope it’s worth something to you,

Ttyl,

Urv

Revisiting Exporting Data

Sup PSHomies!

I’ve been playing with different formats lately. I’d like to share a few thoughts on the subject if I may… For demo purposes I’ll be using the following cmdlets: Export-Csv, Export-Clixml and ConvertTo-Json!

Export-Csv

I’ve talked about my love for exporting to csv in the past. Here’s thing, exporting to CSV treats everything as a string. For reporting purposes this might not be an issue. When it comes to nested objects… Yeah… Then you’re better off exporting to XML. Incidentally Jeff Hicks has a great blog on this topic, you should definitely check it out! CSV is still my goto format because of reporting in Excel, although, I’ve been using Doug Finke’s ImportExcel module more and more! Doug’s module cuts out the middle man and can export to Excel without having to export as a CSV first. It does a whole lot more! Worth looking into!

Export-Clixml

Exporting a nested object is pretty straightforward using Export-Clixml. The structure isn’t pretty though. That was the main reason I didn’t use the cmdlet. Export-Clixml is great when used in combination with Import-Clixml, it restores your nested object without a hitch! You can export your results, send the file and import elsewhere for further processing if needed. When I think of xml, I immediately conjure up ideas of html reporting. The xml tags are too cryptic for any css style, I wouldn’t even know where to begin. I recently discovered PScribo (Thanks to the PowerShell Summit in Stockholm), a module by Ian Brighton! This made html reporting a breeze! All I did was import my XML file back into PowerShell to retrieve my nested object and I did the rest in PowerShell! That was awesome!

ConvertTo-Json

The ConvertTo-Json cmdlet has been introduced in PowerShell version 3.0. Back then I was a stickler for XML so I briefly looked at it and forgot all about it… That is until Azure Resource Manager came along. If you’re doing anything with Azure Resource Manager then Json should be on your radar. If you’re not convinced just look at the ARM Templates out there. Json is a lot easier on the eyes for sure. Still not conviced? Just google Json vs XML.

Ok here’s some code you can play with to get a general idea of what the possibilities are when exporting to different formats. Have a look at the Json and Xml, which would you prefer? That was rhetorical… 😉


<#
Author: I.C.A Strachan
Version:
Version History:
Purpose: Demo exporting/importing to/from csv, xml and json format
#>
[CmdletBinding()]
#region Nested Object for Demo purposes
$Win32_ComputerSystem = @(
'DNSHostName'
'Model'
'Manufacturer'
'Domain'
'DomainRole'
'PartOfDomain'
'SystemType'
)
$Win32_OperatingSystem = @(
'Version'
'BuildNumber'
'BuildType'
'OSLanguage'
'OSType'
'OSArchitecture'
'MUILanguages'
'OperatingSystemSKU'
'Organization'
'ProductType'
'ServicePackMajorVersion'
'ServicePackMinorVersion'
'SizeStoredInPagingFiles'
'SystemDevice'
'SystemDirectory'
'WindowsDirectory'
)
$Win32_BIOS = @(
'SMBIOSBIOSVersion'
'Manufacturer'
'Name'
'SerialNumber'
'Version'
'ReleaseDate'
)
function Get-WMIData {
[cmdletbinding()]
param(
[string]
[ValidateNotNullOrEmpty()]
$WMIClass,
[string[]]
[ValidateNotNullOrEmpty()]
$ComputerName,
[string[]]
[ValidateNotNullOrEmpty()]
$WMIProperties
)
$queryProperties =''
foreach ($property in $WMIProperties){
$queryProperties += "$property,"
}
#Remove last character from $queryProperties
$queryProperties = $queryProperties -replace ".$"
Get-wmiObject -Query "SELECT $queryProperties FROM $WMIClass" -ComputerName $ComputerName |
Select-Object $WMIProperties
}
$Inventory = @{}
$Inventory.ComputerSystem = Get-WMIData -WMIClass Win32_ComputerSystem -ComputerName LocalHost -WMIProperties $Win32_ComputerSystem
$Inventory.OperatingSystem = Get-WMIData -WMIClass Win32_OperatingSystem -ComputerName LocalHost -WMIProperties $Win32_OperatingSystem
$Inventory.BIOS = Get-WMIData -WMIClass Win32_BIOS -ComputerName LocalHost -WMIProperties $Win32_BIOS
#endregion
#region Export-Csv
$exportSplat = @{
NoTypeInformation = $true
Encoding = 'UTF8'
Delimiter = ';'
}
#Export each key to seperate csv File
Foreach ($key in $Inventory.Keys) {
if ( $Inventory.$key.Count -ne 0 ){
$exportSplat.Path = "$PSSCriptRoot\$($key).csv"
$Inventory.$key |
Export-Csv @exportSplat
}
}
#Import Csv for verfication
$importCsv = @{}
#Get csv Files
$csvFiles = Get-ChildItem -Filter *.csv -Path $PSSCriptRoot -File
$importSplat =@{
Delimiter = ';'
Encoding = 'UTF8'
}
Foreach ($file in $csvFiles) {
$importCsv.$($file.BaseName) = Import-Csv -Path $file.FullName @importSplat
}
#endregion
#region Export-Clixml
$Inventory |
Export-Clixml -Path "$PSSCriptRoot\Inventory.xml" -Encoding UTF8
#Import Xml for verfication
$importXml = Import-Clixml -Path "$PSSCriptRoot\Inventory.xml"
#endregion
#region Export to Json Format using ConvertTo-Json
$Inventory |
ConvertTo-Json |
Out-File "$PSSCriptRoot\Inventory.json" -Encoding utf8
#Import Json for verification
$importJson = Get-Content -Path "$PSSCriptRoot\Inventory.json" |
ConvertFrom-Json
#endregion
#region Compare the membertypes of Csv, Xml & Json
$importCsv.ComputerSystem | Get-Member #Everything is a string
$importXml.ComputerSystem | Get-Member #Typecast is preserved
$importJson.ComputerSystem | Get-Member #Typecast is preserved
if ($psISE) {
psedit "$PSSCriptRoot\Inventory.json"
psedit "$PSSCriptRoot\Inventory.xml"
}
else {
notepad.exe "$PSSCriptRoot\Inventory.json"
notepad.exe "$PSSCriptRoot\Inventory.xml"
}
#endregion

Bottom line

Export-Csv is best when you need to report  anything in Excel workbooks and you’re not worried about type. Everyone gets Excel.

Export-Clixml isn’t pretty but excellent when it comes to keeping the data metadata in tact. You can always import preserving the metadata and process further in PowerShell.

Use Json if you want to have a structured data set à la XML. Json is a lot friendlier than XML. I was also surprised that the cmdlet interpreted values to it’s best avail. False became Boolean as you would expect. Json is growing on me…

Hope it’s worth something to you…

Ttyl,

Urv