TeamsBot.psm1
function Send-TeamsBotMessage () { <# .Synopsis Send messages to a Teams Channel using Powershell! .Description This module allows you to send messages to Teams channels using the Webhooks Feature of Microsoft teams. It supports sending customized cards for more advanced scenarios. .Parameter Message The message to be sent to the Teams channel Some markdown features are possible, see here: https://support.microsoft.com/en-us/office/use-markdown-formatting-in-teams-4d10bd65-55e2-4b2d-a1f3-2bebdcd2c772 .Parameter Title A title to be included with the message .Parameter AppName Optionally include the app name and make it clickiable using markdown .Parameter SubTitle Optionally include a Subtitle which will appear bolded .Parameter ActionButtonTitle Optionally include a button with this title .Parameter ActionButtonLink Link for the button .Parameter Card For more advanced scenarios, a custom card object can be created and then passed with this parameters See $GitHubLink for more information .Parameter WebhookURL The WebhookURL to send the message to. The Url can also be persisted using Set-TeamsBotWebhookUrl or specified using Environment variable TeamsBot_WebHookUrl .Example # Preconfigure the WebhookUrl Set-TeamsBotWebhookUrl -WebhookURL 'https://url' .Example # Send a basic message Send-TeamsBotMessage -Message "Hello" -Title "My Title" -WebhookUrl .Example # Send a basic message including the WebhookUrl inline Send-TeamsBotMessage -Message "Hello" -Title "My Title" -WebhookUrl 'https://url' .Example # Send a basic message and include an action button Send-TeamsBotMessage -Message "Hello" -Title "My Title" -ActionButtonTitle "View site" -ActionButtonLink "https://bing.com" .Example # Use a customized card and send the message $SampleCard=New-TeamsBotCard $SampleCard.AddTitle("Test Title") $SampleCard.AddAppName("[Created with TeamBot Powershell module]($GitHubRepo)") $SampleCard.AddSubTitle("Test SubTitle") $SampleCard.AddTextBlock(@" *This is the main textblock which supports Markdown* - section 1 - section 2 - section 3 "@ ) $SampleCard.AddAction("Action 1","https://bing.com") $SampleCard.AddAction("Action 2","https://bing.com") Send-TeamsBotMessage -Card $SampleCard #> param( [Parameter(Mandatory = $true, ParameterSetName = 'Directmessage')] [String]$Message, [Parameter(Mandatory = $true, ParameterSetName = 'Directmessage')] [String]$Title, [Parameter(Mandatory = $false, ParameterSetName = 'Directmessage')] [String]$AppName, [Parameter(Mandatory = $false, ParameterSetName = 'Directmessage')] [String]$SubTitle, [Parameter(Mandatory = $false, ParameterSetName = 'Directmessage')] [Parameter(Mandatory = $false, ParameterSetName = 'IncludeAction')] [String]$ActionButtonTitle="View Details", [Parameter(Mandatory = $true, ParameterSetName = 'IncludeAction')] [Parameter(Mandatory = $false, ParameterSetName = 'Directmessage')] [String]$ActionButtonLink, [Parameter(Mandatory = $true, ParameterSetName = 'UsingCard')] [PsCustomObject]$Card, [Parameter(Mandatory = $false)] [String]$WebhookURL, [Parameter(Mandatory = $false)] [switch]$WhatIf ) if ($Message) { # Lets use the default template and card setup Write-Verbose -Message "Using Default template" $DefaultCard=New-TeamsBotCard $DefaultCard.AddTitle($Title) if ($AppName -ne $null) { $DefaultCard.AddAppName($AppName)} if ($SubTitle -ne $null) { $DefaultCard.AddSubTitle($SubTitle)} $DefaultCard.AddTextBlock($Message) if ($ActionButtonTitle -ne $null -and $ActionButtonLink ) { $DefaultCard.AddAction($ActionButtonTitle,$ActionButtonLink) } try { $UseThisCard = $DefaultCard.GetCard() } catch { Write-Error "The card could not be rendered, check the template file $CustomTemplatePath -or if you suspect a bug, please file an issue at $GitHubRepo" } } if ($Card) { Write-Verbose -Message "Using a pre created Card" # This will take in a Card object directly and use it. try { $UseThisCard = $Card.GetCard() } catch { Write-Error "The card could not be rendered, for assistance or to file an issue, please visit $GitHubRepo" } } if ($WebhookURL) { Write-Verbose -Message "Using WebhooUrl from command line parameter" } else { # If webhook was not specified then # check for other sources Write-Verbose -Message "Obtaining configured WebHookUrl" $WebHookURL = Get-TeamsBotWebhookUrl } # If we got this far, lets send the message # Prepare the complete payload, and convert to JSON format $jsonPayload=@{ type="message" attachments=@(@{ contentType="application/vnd.microsoft.card.adaptive" contentUrl="https://github.com/luisfeliz79/TeamBotPowerShellModule" content=$UseThisCard }) } | ConvertTo-Json -Depth 99 if ($jsonPayload -ne $null) { #Write-Verbose "Payload:" #Write-Verbose $jsonPayload if ($WhatIf) { Write-Host $jsonPayload Write-warning "WhatIf: I would had sent the message with the payload above" } else { Write-Verbose "Sending message...." $response=Invoke-RestMethod -Method Post -Uri $WebHookURL -ContentType 'application/json' -Body $jsonPayload -UserAgent "TeamBotPowerShellModule/$Version" Write-Verbose ($response | ConvertTo-Json -Depth 99) } } } function New-TeamsBotCard() { <# .Synopsis Functions to create an Adaptive card. for Help see "https://github.com/luisfeliz79/TeamsBotPowerShellModule" Some markdown features are possible, see here: https://support.microsoft.com/en-us/office/use-markdown-formatting-in-teams-4d10bd65-55e2-4b2d-a1f3-2bebdcd2c772 .Example # Use a customized card and send the message $SampleCard=New-TeamsBotCard $SampleCard.AddTitle("Test Title") $SampleCard.AddAppName("[Created with TeamBot Powershell module]($GitHubRepo)") $SampleCard.AddSubTitle("Test SubTitle") $SampleCard.AddTextBlock(@" *This is the main textblock which supports Markdown* - section 1 - section 2 - section 3 "@ ) $SampleCard.AddAction("Action 1","https://bing.com") $SampleCard.AddAction("Action 2","https://bing.com") Send-TeamsBotMessage -Card $SampleCard #> # Define some functions for this object type $AddTextBlock={ param ([string]$value) $This.body+=( @{ type="TextBlock" text=$value isSubtle="true" wrap="true" } ) } $AddSubTitle={ param ([string]$value) $This.body+=( @{ type="TextBlock" text=$value isSubtle="true" wrap="false" weight='Bolder' } ) } $AddTitle={ param ([string]$value) $This.body+=( @{ type="TextBlock" text=$value isSubtle="true" wrap="false" size='Large' weight='Bolder' } ) } $AddAppName={ param ([string]$value) $This.body+=( @{ type="TextBlock" text=$value isSubtle="true" color='Accent' weight='Bolder' size='Small' spacing='None' } ) } $AddCustomBodyPart={ param ($value) $This.body+=( $value ) } $AddAction={ param ([string]$value1,[string]$value2) $This.actions+=( @{ type='Action.OpenUrl' title=$value1 url=$value2 } ) } $GetCard={ return $This } # Create the high level object $NewTeamsBotCard=[PsCustomObject]@{ '$schema'="http://adaptivecards.io/schemas/adaptive-card.json" type="AdaptiveCard" version='1.4' body=@() actions= @() } # Add functions $NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddTextBlock -Value $AddTextBlock -Force $NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddSubTitle -Value $AddSubTitle -Force $NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddTitle -Value $AddTitle -Force $NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddAppName -Value $AddAppName -Force $NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddAction -Value $AddAction -Force $NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name GetCard -Value $GetCard -Force $NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddCustomBodyPart -Value $AddCustomBodyPart -Force return $NewTeamsBotCard } function Set-TeamsBotWebhookUrl () { <# .Synopsis Persists the WebHookUrl securely to an encrypted file - $HOME/TeamsBotEncryptedStorage.enc After this step has been completed, the WebHookUrl does not have to specified on Send-TeamsBotMessage commands #> param( [Parameter(Mandatory = $true)] [String]$WebhookURL ) try { Write-Verbose "Saving WebhookURL as a SecureString to $HOME/TeamsBotEncryptedStorage.enc ..." $WebhookURL| ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "$HOME/TeamsBotEncryptedStorage.enc" -ErrorAction Stop } catch { Write-Error "Unable to save WebhookURL To file $HOME/TeamsBotEncryptedStorage.enc" } } function Clear-TeamsBotWebhookUrl () { <# .Synopsis Clears the WebHookUrl by deleting file $HOME/TeamsBotEncryptedStorage.enc #> try { Write-Verbose "Removing file $HOME/TeamsBotEncryptedStorage.enc ..." Remove-item -Path "$HOME/TeamsBotEncryptedStorage.enc" } catch { Write-Error "Unable to remove file $HOME/TeamsBotEncryptedStorage.enc" } } function Get-TeamsBotWebhookUrl () { <# .Synopsis Gets the WebHookUrl either from Environment variable TeamsBot_WebHookUrl (first) or if it exists, from $HOME/TeamsBotEncryptedStorage.enc (second) #> # This function will try several methods to obtain the WebhookURL # First try checking for an Environment variable if ($Env:TeamsBot_WeBHookURL) { Write-Verbose "Using WebhookUrl found in TeamsBot_WEBHookURL environment variable" return $Env:TeamsBot_WebHookURL } if ((Test-Path -Path $HOME/TeamsBotEncryptedStorage.enc) -eq $true) { Write-Verbose "Using WebHookURL found in $HOME/TeamsBotEncryptedStorage.enc" try { $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR((Get-Content -Path "$HOME/TeamsBotEncryptedStorage.enc" | ConvertTo-SecureString)) $URL=[System.Runtime.InteropServices.Marshal]::PtrToStringUni($BSTR) return $URL } catch { Write-Error "Could not read from $HOME/TeamsBotEncryptedStorage.enc" Exit } } Write-error "WebhookURL has not been configured, use Set-TeamsBotWebhookUrl, or environment variable TeamsBot_WEBHookURL" break } $GitHubRepo="https://github.com/luisfeliz79/TeamsBotPowerShellModule" $Version="1.0.0" # Export-ModuleMember -Cmdlet * -Function * Export-ModuleMember -Function Send-TeamsBotMessage Export-ModuleMember -Function Set-TeamsBotWebhookUrl Export-ModuleMember -Function Clear-TeamsBotWebhookUrl Export-ModuleMember -Function New-TeamsBotCard |