I had built a pipeline which scans the Keyvaults and sends a Microsoft Teams notification using Webhook(Eonos Office Webhook) incase any Key/Certificate has expired/about to Expire. And the pipeline worked perfectly, however since O365 connectors are deing depreciated, I am forced to use Microsoft Workflows to post a message from a Webhook Request.
For that I created a Workflow which ‘Post to a channel when a webhook request is received’ but when I replaced my current Eonos WebhookURL with the new Workflow URL, my notification layout is completely changed and I am getting more of a text than a proper notification.
This is how my notifications used to look like:
and I just replaced the URL with the new Workflow Webhook URl, I am getting the following output:
So, It is just printing the value that it is being provided.
This is my Workflow Configuration:
and this is how I am sending the Webhook request from my Powershell skript:
and this is my Send-Notification function:
I believe that I need to change the configuration of my Flow (maybe) but I am not sure. Please help me with this :’)
update from 18.09.2024:
Now I am get the links (of the secrets) as a Text instead of clickable links eventhough I enabled the Code view in the message:
and this is how I am getting the notification now:
Do you know how to solve this?
when I save it in code view and refresh it and check it again, it shows me in normal mode:
this is my code, where I check secret and create the URL for it:
function Check-Secrets {
param(
[string]$keyVault,
[string]$globalSubscription,
[string]$resourceGroup
)
$expiringSecrets = @()
$noExpirySecrets = @()
$secrets = az keyvault secret list --vault-name $keyVault --query "[].id" -o tsv 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Output "Unable to access Key Vault: $keyVault"
$global:inaccessibleKeyVaults += $keyVault
continue
}
foreach ($secret in $secrets) {
$secretAttributesJson = az keyvault secret show --id $secret --query "attributes" -o json
$secretAttributes = $secretAttributesJson | ConvertFrom-Json
$secretName = az keyvault secret show --id $secret --query "name" -o tsv
$secretUrl = "https://portal.azure.com/#view/Microsoft_Azure_KeyVault/ListObjectVersionsRBACBlade/~/overview/objectType/secrets/objectId/https%3A%2F%2F$keyVault.vault.azure.net%2Fsecrets%2F$secretName/vaultResourceUri/%2Fsubscriptions%2F$globalSubscription%2FresourceGroups%2F$resourceGroup%2Fproviders%2FMicrosoft.KeyVault%2Fvaults%2F$keyVault/vaultId/%2Fsubscriptions%2F$globalSubscription%2FresourceGroups%2F$resourceGroup%2Fproviders%2FMicrosoft.KeyVault%2Fvaults%2F$keyVault"
if ($null -ne $secretAttributes.expires -and $secretAttributes.expires -ne '') {
$expiryDate = [DateTime]::Parse($secretAttributes.expires)
$oneMonthFromNow = (Get-Date).AddMonths(1)
if ($expiryDate -lt $oneMonthFromNow) {
$expiringSecrets += "Secret ID: [$secret]($secretUrl), Expiry Date: $expiryDate"
}
}
else {
$noExpirySecrets += "Secret ID: [$secret]($secretUrl)"
}
}
return @{
"ExpiringSecrets" = $expiringSecrets
"NoExpirySecrets" = $noExpirySecrets
}
}
and this is how I called the function:
$expiringSecretsMessage = if ($expiringSecrets.Count -gt 0) { "The following secrets are expiring:<br />" + ($expiringSecrets -join "<br />") }
$noExpirySecretsMessage = if ($noExpirySecrets.Count -gt 0) { "The following secrets have no expiry date:<br />" + ($noExpirySecrets -join "<br />") }
$expiringCertificatesMessage = if ($expiringCertificates.Count -gt 0) { "The following certificates are expiring:<br />" + ($expiringCertificates -join "<br />") }
$noExpiryCertificatesMessage = if ($noExpiryCertificates.Count -gt 0) { "The following certificates have no expiry date:<br />" + ($noExpiryCertificates -join "<br />") }
Send-Notification -keyVault $keyVault -WebhookURL $WebhookURL -messageParts @($expiringSecretsMessage, $noExpirySecretsMessage, $expiringCertificatesMessage, $noExpiryCertificatesMessage)
my notification layout is completely changed and I am getting more of a text than a proper notification.
I can reproduce the similar situation when using the Post message in a chat or channel action in Microsoft flow.
The cause of the issue is that the Post message in a chat or channel action will send the content as plain text format to teams by default.
To let the message show as the HTML format, you can refer to the following steps:
Step1: Add HTML tag to your message.
Step2: When use the Post message in a chat or channel action, you need to first click the option: Toggle code view and then input the required message contains HTML tag.
For example:
Result:
10
As far as I have tested, to send clickable hyperlink as parts of your Teams message requires your context to use the valid HTML hyperlink syntax like Secret ID: <a href="URL">ALIAS</a>
. Here is a sample YAML pipeline that is to generate the webhook payload with hyperlink syntax.
pool:
vmImage: ubuntu-latest
variables:
myTestKV: xxxmytestkvxxx
TeamsWebhookURL: https://xxxxxx
steps:
- task: AzureCLI@2
inputs:
azureSubscription: 'ARMSvcCnnSub0'
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
$myTestKV = "$(myTestKV)"
# Fetch secrets using Azure CLI command
$secrets = az keyvault secret list --id https://$myTestKV.vault.azure.net/ | ConvertFrom-Json
$currentDate = (Get-Date).ToUniversalTime()
$expiringSecrets = @()
$noExpirySecrets = @()
foreach ($secret in $secrets) {
$expires = $secret.attributes.expires
if ($expires) {
$expiryDate = [datetime]::Parse($expires)
$daysRemaining = ($expiryDate - $currentDate).Days
if ($daysRemaining -le 30) {
$expiringSecrets += $secret
}
} else {
$noExpirySecrets += $secret
}
}
Write-Output "expiringSecrets - $($expiringSecrets | ConvertTo-Json -Depth 100)"
Write-Output "noExpirySecrets - $($noExpirySecrets | ConvertTo-Json -Depth 100)"
$expiringSecretsText = ""
foreach ($secret in $expiringSecrets) {
$expiryDate = [datetime]::Parse($secret.attributes.expires).ToUniversalTime().ToString("MM/dd/yyyy HH:mm:ss")
$expiringSecretsText += "Secret ID: <a href=``"$($secret.id)``">$($secret.name)</a>Expiry Date (UTC): <span style=``'color: red;``'>$expiryDate</span><br />"
}
$noExpirySecretsText = ""
foreach ($secret in $noExpirySecrets) {
$noExpirySecretsText += "Secret ID: <a href=``"$($secret.id)``">$($secret.name)</a><br />"
}
$testMessageJSON = @"
{
"text": "<b>The following secrets are expiring:</b><br />$expiringSecretsText<br /><b>The following secrets have no expiry date:</b><br />$noExpirySecretsText<br />",
"title": "Key Vault: $myTestKV"
}
"@
Write-Output $testMessageJSON
$WebhookURL = "$(TeamsWebhookURL)"
Write-Host "WebhookURL - $WebhookURL"
Invoke-RestMethod -Method Post -Uri $WebhookURL -Body $testMessageJSON -ContentType 'application/json'
Sample webhook payload
{
"text": "<b>The following secrets are expiring:</b><br />Secret ID: <a href="https://xxxmytestkvxxx.vault.azure.net/secrets/secret1">secret1</a>Expiry Date (UTC): <span style='color: red;'>09/22/2024 16:00:00</span><br />Secret ID: <a href="https://xxxmytestkvxxx.vault.azure.net/secrets/secret3">secret3</a>Expiry Date (UTC): <span style='color: red;'>09/30/2024 15:59:59</span><br /><br /><b>The following secrets have no expiry date:</b><br />Secret ID: <a href="https://xxxmytestkvxxx.vault.azure.net/secrets/secret2">secret2</a><br />Secret ID: <a href="https://xxxmytestkvxxx.vault.azure.net/secrets/secret4">secret4</a><br /><br />",
"title": "Key Vault: xxxmytestkvxxx"
}
6