-
-
Save chusiang/895f6406fbf9285c58ad0a3ace13d025 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# ============================================================================= | |
# Author: Chu-Siang Lai / chusiang (at) drx.tw | |
# Filename: teams-chat-post-for-workflows.sh | |
# Modified: 2024-07-22 11:44 (UTC+08:00) | |
# Description: Post a message to Microsoft Teams via "Post to a chat when a webhook request is received" workflows. | |
# Reference: | |
# | |
# - https://gist.github.com/chusiang/895f6406fbf9285c58ad0a3ace13d025 | |
# - https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/ | |
# - https://adaptivecards.io/explorer/ | |
# - https://adaptivecards.io/designer/ | |
# | |
# ============================================================================= | |
# Help. | |
if [[ "$1" == "-h" || "$1" == "--help" ]]; then | |
echo 'Usage: teams-chat-post.sh "<webhook_url>" "<title>" "<color>" "<message>"' | |
exit 0 | |
fi | |
# Webhook or Token. | |
WEBHOOK_URL=$1 | |
if [[ "${WEBHOOK_URL}" == "" ]]; then | |
echo "No webhook_url specified." | |
exit 1 | |
fi | |
shift | |
# Title . | |
TITLE=$1 | |
if [[ "${TITLE}" == "" ]]; then | |
echo "No title specified." | |
exit 1 | |
fi | |
shift | |
# Color. | |
COLOR=$1 | |
if [[ "${COLOR}" == "" ]]; then | |
echo "No color specified." | |
exit 1 | |
fi | |
shift | |
# Text. | |
TEXT=$* | |
if [[ "${TEXT}" == "" ]]; then | |
echo "No text specified." | |
exit 1 | |
fi | |
# Escape char: `'`, `"`, `\` . | |
MESSAGE=$(echo ${TEXT} | sed "s/'/\'/g" | sed 's/"/\"/g; s/\\/\\\\/g') | |
# Adaptive Cards of TextBlock - https://adaptivecards.io/explorer/TextBlock.html | |
JSON="{ | |
\"type\": \"message\", | |
\"attachments\": [ | |
{ | |
\"contentType\": \"application/vnd.microsoft.card.adaptive\", | |
\"contentUrl\": null, | |
\"content\": { | |
\"$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\", | |
\"type\": \"AdaptiveCard\", | |
\"version\": \"1.2\", | |
\"body\": [ | |
{ | |
\"type\": \"TextBlock\", | |
\"text\": \"${TITLE}\", | |
\"color\": \"${COLOR}\", | |
\"weight\": \"bolder\", | |
\"size\": \"large\", | |
\"wrap\": true | |
}, | |
{ | |
\"type\": \"TextBlock\", | |
\"text\": \"${MESSAGE}\", | |
\"color\": \"${COLOR}\", | |
\"size\": \"small\", | |
\"wrap\": true | |
} | |
] | |
} | |
} | |
] | |
}" | |
# Post to Microsoft Teams via curl. | |
curl \ | |
--header "Content-Type: application/json" \ | |
--request POST \ | |
--data "${JSON}" \ | |
"${WEBHOOK_URL}" |
#!/bin/bash | |
# ============================================================================= | |
# Author: Chu-Siang Lai / chusiang (at) drx.tw | |
# Filename: teams-chat-post.sh | |
# Modified: 2024-07-12 18:49 (UTC+08:00) | |
# Description: Post a message to Microsoft Teams via connectors, not support | |
# Power Automate workflows. | |
# Reference: | |
# | |
# - https://gist.github.com/chusiang/895f6406fbf9285c58ad0a3ace13d025 | |
# - https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/ | |
# - Fixed for workflows edition: https://gist.github.com/chusiang/895f6406fbf9285c58ad0a3ace13d025?permalink_comment_id=5119162#gistcomment-5119162 | |
# | |
# ============================================================================= | |
# Help. | |
if [[ "$1" == "-h" || "$1" == "--help" ]]; then | |
echo 'Usage: teams-chat-post.sh "<webhook_url>" "<title>" "<color>" "<message>"' | |
exit 0 | |
fi | |
# Webhook or Token. | |
WEBHOOK_URL=$1 | |
if [[ "${WEBHOOK_URL}" == "" ]]; then | |
echo "No webhook_url specified." | |
exit 1 | |
fi | |
shift | |
# Title . | |
TITLE=$1 | |
if [[ "${TITLE}" == "" ]]; then | |
echo "No title specified." | |
exit 1 | |
fi | |
shift | |
# Color. | |
COLOR=$1 | |
if [[ "${COLOR}" == "" ]]; then | |
echo "No status specified." | |
exit 1 | |
fi | |
shift | |
# Text. | |
TEXT=$* | |
if [[ "${TEXT}" == "" ]]; then | |
echo "No text specified." | |
exit 1 | |
fi | |
# Convert formating. | |
MESSAGE=$(echo ${TEXT} | sed 's/"/\"/g' | sed "s/'/\'/g") | |
JSON="{ | |
\"title\": \"${TITLE}\", | |
\"themeColor\": \"${COLOR}\", | |
\"text\": \"${MESSAGE}\" | |
}" | |
# Post to Microsoft Teams. | |
curl -H "Content-Type: application/json" -d "${JSON}" "${WEBHOOK_URL}" | |
This is beautiful. Thank you!
How to send a message on Microsoft teams with new line character? With \n not working. What should I use?
Hi @whanklee , please try \n\n
, it's working on https://adaptivecards.io/designer .
{
"type": "TextBlock",
"text": "It doesn't wrap by\n\n default",
"weight": "bolder"
},
Hi @chusiang,
\r\n\r\n works well.
Hi @lp-maximus,
I think we need add Escape Character for
\
on L60 in teams-chat-post-for-workflows.sh.I have also escape the
\
char, maybe it can help you.- MESSAGE=$(echo ${TEXT} | sed 's/"/\"/g' | sed "s/'/\'/g") + MESSAGE=$(echo ${TEXT} | sed "s/'/\'/g" | sed 's/"/\"/g; s/\\/\\\\/g')Good luck.
Reference:
Hi,
In my case I'm passing to the script an output of another script, which takes sql query result and concats with another line having an escaped newline:
query-db-and-pass-to-teams-script.sh
MESSAGE="$SQL_RESULT" # Which is a 5 line string, 1st 4 ending with literal newlines.
MESSAGE+="\nAnother line here"
${TEAMS_SCRIPT} "$WEBHOOK_URL" "$TITLE" "$COLOR" "$MESSAGE"
So when this $MESSAGE is passed to your script, several issues occur at this line:
MESSAGE=$(echo ${TEXT} | sed "s/'/\'/g" | sed 's/"/\"/g; s/\\/\\\\/g')
- If we use echo ${TEXT} - it will eat all literal newlines. Had to use echo "${TEXT}" to avoid that.
- s/\/\\/g turns my concated escaped newline in "\nAnother line here" into
"\\\\nAnother line here"
P.S.
echo "No status specified."
Was it meant "No color specified."?
Hi @alaxelmck,
I have update to No color specified.
, it's typo with I copy from my old script like slack-chat-post.sh
.
About support output of another script part, I have no idea now.
I have done a rewrite of the script:
- Use
jq
for managing JSON - Use
getopts
- Added a bunch of optional parameters
#!/bin/bash
# =============================================================================
# Original Author: Chu-Siang Lai / chusiang (at) drx.tw
# Modifier: @emibcn https://github.com/emibcn
# Filename: teams-chat-post-for-workflows.sh
# Description: Post a message to Microsoft Teams via "Post to a chat when a webhook request is received" workflows.
# Reference:
#
# - https://gist.github.com/chusiang/895f6406fbf9285c58ad0a3ace13d025
# - https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/
# - https://adaptivecards.io/explorer/
# - https://adaptivecards.io/designer/
#
# =============================================================================
set -Eeuo pipefail
usage() {
cat <<EOF
Usage:
teams-chat-post.sh -w "<webhook_url>" -t "<title>" -x "<message>"
Optional parameters:
-h Get usage help (this text)
-c "<Color>" (default: "default")
-u "<Button URL>" If not used, no button is shown
-b "<Button Text>" (default: "URL")
-i "<IMAGE_URL>" If not used, no image is shown
-p "<Expandable title>" Used for the expand button (Default: "View more")
-e "<Expandable text>" If not used, no expandable text is shown
-l "<Expandable logo>" Used as logo for the "View more" button
EOF
exit ${1:-0}
}
# Get options into variables
while getopts :hw:c:t:x:u:b:i:p:e:l: OPTION
do
case ${OPTION} in
w) WEBHOOK_URL="${OPTARG}" ;;
t) TITLE="${OPTARG}" ;;
x) TEXT="${OPTARG}" ;;
c) COLOR="${OPTARG}" ;;
u) BUTTON_URL="${OPTARG}" ;;
b) BUTTON_TEXT="${OPTARG}" ;;
i) IMAGE_URL="${OPTARG}" ;;
p) EXPANDABLE_TITLE="${OPTARG}" ;;
e) EXPANDABLE_TEXT="${OPTARG}" ;;
l) EXPANDABLE_LOGO="${OPTARG}" ;;
h)
usage
;;
:)
echo "${0}: ERROR: Must supply an argument to -${OPTARG}" >&2
usage 2
;;
?)
echo "${0}: ERROR: Invalid option: -${OPTARG}" >&2
usage 3
;;
esac
done
#
# Verify variables
#
# Webhook or Token
if [ "${WEBHOOK_URL:-}" == "" ]
then
echo "No webhook_url specified."
echo "Visit this URL to see how to obtain one:"
echo "https://support.microsoft.com/en-us/office/creating-a-workflow-from-a-chat-in-teams-e3b51c4f-49de-40aa-a6e7-bcff96b99edc"
usage 1
fi
# Color
# https://adaptivecards.io/explorer/TextBlock.html
ALLOWED_COLORS=(
default
dark
light
accent
good
warning
attention
)
COLOR="${COLOR:-default}"
if [ "${COLOR:-}" == "" ]
then
echo "No color specified."
usage 1
fi
if ! printf '%s\0' "${ALLOWED_COLORS[@]}" | grep -qwz "${COLOR}"
then
echo "The specified color is not in the allowed list:"
echo "$(IFS="," ; echo "${ALLOWED_COLORS[*]}")"
usage 1
fi
# Title
if [ "${TITLE:-}" == "" ]
then
echo "No title specified."
usage 1
fi
# Text
if [ "${TEXT:-}" == "" ]
then
echo "No text specified."
usage 1
fi
# Generate JSON using variables
# Adaptive Cards of TextBlock - https://adaptivecards.io/explorer/TextBlock.html
JSON="$(
jq \
--null-input \
--arg COLOR "${COLOR}" \
--arg TITLE "${TITLE}" \
--arg TEXT "${TEXT}" \
'{
type: "message",
attachments: [
{
contentType: "application/vnd.microsoft.card.adaptive",
contentUrl: null,
content: {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
type: "AdaptiveCard",
version: "1.2",
actions: [],
body: [
{
type: "TextBlock",
text: $TITLE,
color: $COLOR,
weight: "bolder",
size: "large",
wrap: true
},
{
type: "TextBlock",
text: $TEXT,
color: $COLOR,
size: "small",
wrap: true
}
]
}
}
]
}'
)"
if [ "${BUTTON_URL:-}" != "" ]
then
JSON="$(
echo "${JSON}" \
| jq \
--arg URL "${BUTTON_URL}" \
--arg TEXT "${BUTTON_TEXT:-URL}" \
'.attachments[0].content.actions += [
{
type: "Action.OpenUrl",
title: $TEXT,
url: $URL
}
]
'
)"
fi
if [ "${EXPANDABLE_TEXT:-}" != "" ]
then
JSON="$(
echo "${JSON}" \
| jq \
--arg TITLE "${EXPANDABLE_TITLE:-View more}" \
--arg TEXT "${EXPANDABLE_TEXT}" \
--arg URL "${EXPANDABLE_LOGO:-}" \
'.attachments[0].content.actions += [
{
"type": "Action.ShowCard",
"title": $TITLE,
iconUrl: $URL,
"card": {
"type": "AdaptiveCard",
"body": [
{
type: "TextBlock",
text: $TEXT,
size: "small",
wrap: true
}
]
}
}
]
'
)"
fi
if [ "${IMAGE_URL:-}" != "" ]
then
JSON="$(
echo "${JSON}" \
| jq \
--arg IMAGE "${IMAGE_URL}" \
'.attachments[0].content.body = [
{
type: "ColumnSet",
columns: [
{
type: "Column",
items: .attachments[0].content.body
},
{
type: "Column",
width: "auto",
verticalContentAlignment: "center",
items: [
{
type: "Image",
url: $IMAGE
}
]
}
]
}
]
'
)"
fi
# Post to Microsoft Teams using curl
curl \
-v \
--header "Content-Type: application/json" \
--request POST \
--data "${JSON}" \
"${WEBHOOK_URL}"
I have done a rewrite of the script:
- Use
jq
for managing JSON- Use
getopts
- Added a bunch of optional parameters
#!/bin/bash # ============================================================================= # Original Author: Chu-Siang Lai / chusiang (at) drx.tw # Modifier: @emibcn https://github.com/emibcn # Filename: teams-chat-post-for-workflows.sh # Description: Post a message to Microsoft Teams via "Post to a chat when a webhook request is received" workflows. # Reference: # # - https://gist.github.com/chusiang/895f6406fbf9285c58ad0a3ace13d025 # - https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/ # - https://adaptivecards.io/explorer/ # - https://adaptivecards.io/designer/ # # ============================================================================= set -Eeuo pipefail usage() { cat <<EOF Usage: teams-chat-post.sh -w "<webhook_url>" -t "<title>" -x "<message>" Optional parameters: -h Get usage help (this text) -c "<Color>" (default: "default") -u "<Button URL>" If not used, no button is shown -b "<Button Text>" (default: "URL") -i "<IMAGE_URL>" If not used, no image is shown -p "<Expandable title>" Used for the expand button (Default: "View more") -e "<Expandable text>" If not used, no expandable text is shown -l "<Expandable logo>" Used as logoo for the "View more" button EOF exit ${1:-0} } # Get options into variables while getopts :hw:c:t:x:u:b:i:p:e:l: OPTION do case ${OPTION} in w) WEBHOOK_URL="${OPTARG}" ;; t) TITLE="${OPTARG}" ;; x) TEXT="${OPTARG}" ;; c) COLOR="${OPTARG}" ;; u) BUTTON_URL="${OPTARG}" ;; b) BUTTON_TEXT="${OPTARG}" ;; i) IMAGE_URL="${OPTARG}" ;; p) EXPANDABLE_TITLE="${OPTARG}" ;; e) EXPANDABLE_TEXT="${OPTARG}" ;; l) EXPANDABLE_LOGO="${OPTARG}" ;; h) usage ;; :) echo "${0}: ERROR: Must supply an argument to -${OPTARG}" >&2 usage 2 ;; ?) echo "${0}: ERROR: Invalid option: -${OPTARG}" >&2 usage 3 ;; esac done # # Verify variables # # Webhook or Token if [ "${WEBHOOK_URL:-}" == "" ] then echo "No webhook_url specified." echo "Visit this URL to see how to obtain one:" echo "https://support.microsoft.com/en-us/office/creating-a-workflow-from-a-chat-in-teams-e3b51c4f-49de-40aa-a6e7-bcff96b99edc" usage 1 fi # Color # https://adaptivecards.io/explorer/TextBlock.html ALLOWED_COLORS=( default dark light accent good warning attention ) COLOR="${COLOR:-default}" if [ "${COLOR:-}" == "" ] then echo "No color specified." usage 1 fi if ! printf '%s\0' "${ALLOWED_COLORS[@]}" | grep -qwz "${COLOR}" then echo "The specified color is not in the allowed list:" echo "$(IFS="," ; echo "${ALLOWED_COLORS[*]}")" usage 1 fi # Title if [ "${TITLE:-}" == "" ] then echo "No title specified." usage 1 fi # Text if [ "${TEXT:-}" == "" ] then echo "No text specified." usage 1 fi # Generate JSON using variables # Adaptive Cards of TextBlock - https://adaptivecards.io/explorer/TextBlock.html JSON="$( jq \ --null-input \ --arg COLOR "${COLOR}" \ --arg TITLE "${TITLE}" \ --arg TEXT "${TEXT}" \ '{ type: "message", attachments: [ { contentType: "application/vnd.microsoft.card.adaptive", contentUrl: null, content: { "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", type: "AdaptiveCard", version: "1.2", actions: [], body: [ { type: "TextBlock", text: $TITLE, color: $COLOR, eight: "bolder", size: "large", wrap: true }, { type: "TextBlock", text: $TEXT, color: $COLOR, size: "small", wrap: true } ] } } ] }' )" if [ "${BUTTON_URL:-}" != "" ] then JSON="$( echo "${JSON}" \ | jq \ --arg URL "${BUTTON_URL}" \ --arg TEXT "${BUTTON_TEXT:-URL}" \ '.attachments[0].content.actions += [ { type: "Action.OpenUrl", title: $TEXT, url: $URL } ] ' )" fi if [ "${EXPANDABLE_TEXT:-}" != "" ] then JSON="$( echo "${JSON}" \ | jq \ --arg TITLE "${EXPANDABLE_TITLE:-View more}" \ --arg TEXT "${EXPANDABLE_TEXT}" \ --arg URL "${EXPANDABLE_LOGO:-}" \ '.attachments[0].content.actions += [ { "type": "Action.ShowCard", "title": $TITLE, iconUrl: $URL, "card": { "type": "AdaptiveCard", "body": [ { type: "TextBlock", text: $TEXT, size: "small", wrap: true } ] } } ] ' )" fi if [ "${IMAGE_URL:-}" != "" ] then JSON="$( echo "${JSON}" \ | jq \ --arg IMAGE "${IMAGE_URL}" \ '.attachments[0].content.body = [ { type: "ColumnSet", columns: [ { type: "Column", items: .attachments[0].content.body }, { type: "Column", width: "auto", verticalContentAlignment: "center", items: [ { type: "Image", url: $IMAGE } ] } ] } ] ' )" fi # Post to Microsoft Teams using curl curl \ -v \ --header "Content-Type: application/json" \ --request POST \ --data "${JSON}" \ "${WEBHOOK_URL}"
-eight, +weight
Thanks for feedback from @cowbe0x004 and @ehouston3 ,
I have tried to remove the footer, but something is working and something not.
If we want to stop show (or remove) the footer:
I think the answer is clean now.
CC @zeyt27