Publish an Adaptive Card in a Teams channel (with PowerShell)

Adaptive Cards can publish a message in Teams with further information and customized actions. In my case, I use an Adaptive Card to publish a message in a Teams channel via Power Automate when a new post is published on a SharePoint page.

I find how Power Automate works cumbersome, and the Power Automate Designer is not very handy. I tried the same via PowerShell. I find the way with PowerShell easier and faster to implement for reuse.

What should you consider for Adaptive Cards?

  • Note the schema for Adaptive Cards. Version 1.6 is available. You need a minimum version depending on the used methods. The standard version is often still 1.0. Works, but specific methods are not supported. I am using version 1.0 in my example.
  • There is an Adaptive Card Designer. The designer can assist in writing a block or certain functions (if someone does not want to write it themselves).
  • Incoming webhooks must be configured in Teams for the method via PowerShell. An Adaptive Card can be published via the webhooks.


Publish an Adaptive Card with PowerShell

As noted above, an incoming webhook is required in the Teams channel.

  1. The first step is manually adding the Incoming Webhook connector to a channel. Teams does not yet support adding a connector via PowerShell. Follow the instructions and copy the URL of the webhook. Keep the URL secret.
  2. Create the schema for an Adaptive Card in JSON format and add the text fields as required. You can find an example in the documentation.
    The image should be publicly available or internal images that members can read. In my demo, the image is provided via Unsplash by Greg Rakozy. You can remove the entire image section if you do not have an image. The card then only shows the text.
PowerShell
$AdaptiveCard = @" 
{
    "type": "message",
    "attachments": [
       {
          "contentType": "application/vnd.microsoft.card.adaptive",
          "contentUrl": null,
          "content": {
                "`$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.0",
                "body": [
                        {   "type": "ColumnSet",
                            "columns": 
                            [ 
                                {   "type": "Column",
                                    "width": 2,
                                    "items": [
                                        {   "type": "TextBlock",
                                            "spacing": "None",
                                            "size": "Large",
                                            "weight": "Bolder",
                                            "text": "Adaptive Card Demo"
                                        },
                                        {   "type": "TextBlock",
                                            "size": "Small",
                                            "text": "Hello World"                    
                                        },
                                        {   "type": "Image",
                                            "url": "https://images.unsplash.com/photo-1444703686981-a3abbc4d4fe3",
                                            "selectAction": {
                                                "type": "Action.OpenUrl",
                                                "url": "https://blog.topedia.com"
                                            }
                                        }
                                    ]                        
                                }
                            ]                
                        }
                    ],
                "actions": [
                    {
                        "type": "Action.OpenUrl",
                        "title": "I want to read this page",
                        "url": "https://blog.topedia.com"
                    }
                ]                  
            }
       }
    ]
}
"@

  1. The Adaptive Card is sent to the webhook and published in the Teams channel as a final step. Replace the URL with your webhook URL from step 1.
PowerShell
$WebhookUrl = "<WebhookURL>"
Invoke-RestMethod -Method POST -Uri $WebhookUrl -Body $AdaptiveCard -ContentType 'application/json'


A new message with the Adaptive Card is published in the channel.

Adaptive Card with an image from a URL
Adaptive Card with an image from a URL

It is now easy to publish dynamic values from SharePoint News using PowerShell using the text elements in the Adaptive Card.


Publish an Adaptive Card with PowerShell and base64 string

As known, the new Teams currently has a bug with some images in an Adaptive Card and does not display them correctly in some cases.
External images, as in my example from Unsplash, are unaffected. I saw the problem with images in a SharePoint library. According to the latest update a fix is being rolled out.

The post mentions a workaround via base64 string. This means that the image is not sent to Teams via a URL but the value of the image. Teams displays the static image instead of requesting it via a URL. The URL query is the current bug for the incorrect display in the new Teams.

The base64 string is formed via the image’s content and must be inserted into the JSON of the Adaptive Card. There is a restriction that the JSON must not be larger than 28 KB in total. Otherwise, Teams will reject the request with a “Too large”. So the image should not be larger than 20 KB.

In my example from Unsplash, I have to convert the image to a base64 string and know that the image should not be larger than 20 KB. It is more complex compared to the URL method.

  1. I download the image via the Unsplash API. I use the options for developers at Unsplash for this.
PowerShell
$Url = "https://api.unsplash.com/photos/oMpAz-DN-9I?client_id=<DeveloperApplicationAccessKey>"
$ImageResult = Invoke-RestMethod -Method Get -Uri $Url 

$ImageFilePath = ("C:\Temp\" + $ImageResult.id + ".jpg")
Invoke-WebRequest -Uri $ImageResult.links.download -OutFile $ImageFilePath


The image has been downloaded and has a size of about 3 MB. Far too big for the Adaptive Card.

Screenshot

  1. I reduce the image size to 500×333. Patrick Domingues’ post is helpful.
PowerShell
$ResizedImagePath_Resized = ("C:\Temp\" + $ImageResult.id + "-Resized.jpg")
$Image = [System.Drawing.Image]::FromFile($ImageFilePath)
$ResizedImage = New-Object System.Drawing.Bitmap(500, 333)
$ImageGraphic = [System.Drawing.Graphics]::FromImage($ResizedImage)
$ImageGraphic.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBilinear
$ImageGraphic.DrawImage($Image, 0, 0, 500, 333)
$ImageGraphic.Dispose()
$Image.Dispose()
$ResizedImage.Save($ResizedImagePath_Resized)


The image is now 335 KB in size. Still too big for the Adaptive Card.

Screenshot

  1. I reduce the quality of the image by 30%. Another post by Patrick Domingues is helpful.
PowerShell
$ResizedImagePath_LowQuality = ("C:\Temp\" + $ImageResult.id + "-LowQuality.jpg")
$CompressionQuality = 70
$jpegCodec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.MimeType -eq "image/jpeg" }
$Image = [System.Drawing.Image]::FromFile($ResizedImagePath_Resized)
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters
$Encoder = [System.Drawing.Imaging.Encoder]::Quality
$EncoderParam = New-Object System.Drawing.Imaging.EncoderParameter($Encoder, $CompressionQuality)
$EncoderParams.Param[0] = $EncoderParam
$Image.Save($ResizedImagePath_LowQuality, $jpegCodec, $EncoderParams)


The image now has a size of 18 KB and still looks suitable.

Screenshot

  1. The size of the image can be converted into a base64 string.
PowerShell
$ImageBytes = [System.IO.File]::ReadAllBytes($ResizedImagePath_LowQuality)
$ImageBase64 = [System.Convert]::ToBase64String($ImageBytes)
$base64URL = "data:image/png;base64,$ImageBase64"


The base64 URL is a long character string.

Screenshot

  1. I insert the base64 URL into the Adaptive Card as an image URL. Replace the webhook URL with your URL.
PowerShell
$WebhookUrl = "<WebhookURL>"

$AdaptiveCard = @" 
{
    "type": "message",
    "attachments": [
       {
          "contentType": "application/vnd.microsoft.card.adaptive",
          "contentUrl": null,
          "content": {
                "`$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.0",
                "body": [
                        {   "type": "ColumnSet",
                            "columns": 
                            [ 
                                {   "type": "Column",
                                    "width": 2,
                                    "items": [
                                        {   "type": "TextBlock",
                                            "spacing": "None",
                                            "size": "Large",
                                            "weight": "Bolder",
                                            "text": "Adaptive Card Demo (with base64 Image)"
                                        },
                                        {   "type": "TextBlock",
                                            "size": "Small",
                                            "text": "Hello World"                    
                                        },
                                        {   "type": "Image",
                                            "url": "$base64URL",
                                            "selectAction": {
                                                "type": "Action.OpenUrl",
                                                "url": "https://blog.topedia.com"
                                            }
                                        }
                                    ]                        
                                }
                            ]                
                        }
                    ],
                "actions": [
                    {
                        "type": "Action.OpenUrl",
                        "title": "I want to read this page",
                        "url": "https://blog.topedia.com"
                    }
                ]                  
            }
       }
    ]
}
"@

Invoke-RestMethod -Method POST -Uri $WebhookUrl -Body $AdaptiveCard -ContentType 'application/json'


A new message with the Adaptive Card is published in the channel. The card now includes the base64 image. 👍

Adaptive Card with base64 image
Adaptive Card with base64 image
Share
Avatar photo

Tobias Asböck

Tobias is a Senior System Engineer with around ten years of professional experience with Microsoft 365 products such as SharePoint Online, OneDrive for Business, Teams Collaboration, Entra ID, Information Protection, Universal Print, and Microsoft 365 Licensing. He also has 15+ years of experience planning, administering, and operating SharePoint Server environments. Tobias is a PowerShell Scripter with certifications for Microsoft 365 products. In his spare time, Tobias is busy with updates in the Microsoft 365 world or on the road with his road bike and other sports activities. If you have additional questions, please contact me via LinkedIn or [email protected].

Leave a Reply

Your email address will not be published. Required fields are marked *