azurepowershellmicrosoft-graph-apiazure-automation

How can I add email recipients to a Graph API request programmatically?


I have some runbooks running in Azure Automation. I am adding email notifications to the runbooks. I've configured a simple runbook to send emails. Rather than adding an email "section" to the end of each runbook, I would like to have a single "email" runbook that can be called from the other runbooks. I've run into a problem with the number of email recipients. How can I dynamically change the number of email recipients in the Graph API request to match the number of recipients that would be passed from the other runbook?

Here's the email runbook. It works great as written.

# Import variables from Azure Automation account
$client_id = Get-AutomationVariable -Name 'Azure Automation Emails Application Client ID'
$client_key = Get-AutomationVariable -Name 'Azure Automation Emails Application Key'
$tenant_id = Get-AutomationVariable -Name 'Azure Automation Emails Application Tenant ID'

# Get an access token to send the email
$request = @{
    Method = 'POST'
    URI    = "https://login.microsoftonline.com/$tenant_id/oauth2/v2.0/token"
    body   = @{
        grant_type    = "client_credentials"
        scope         = "https://graph.microsoft.com/.default"
        client_id     = $client_id
        client_secret = $client_key
    }
}
$token = (Invoke-RestMethod @request).access_token
# DEBUGGING - view the token value
#$token

# Provide the sender and recipient email addresses
$fromAddress = 'azureautomation@company.com'
$toAddress1 = 'user1@company.com'
$toAddress2 = 'user2@company.com'

# Specify the email subject and the message
$mailSubject = 'Test email'
$mailMessage = 'this is a test'

# Build the Graph API request and send the message
$params = @{
    "URI"         = "https://graph.microsoft.com/v1.0/users/$fromAddress/sendMail"
    "Headers"     = @{
      "Authorization" = ("Bearer {0}" -F $token)
    }
    "Method"      = "POST"
    "ContentType" = 'application/json'
    "Body" = (@{
        "message" = @{
            "subject" = $mailSubject
            "body"    = @{
                "contentType" = 'Text'
                "content"     = $mailMessage
            }
            "toRecipients" = @(
                @{
                    "emailAddress" = @{
                        "address" = $toAddress1
                    }
                }
                @{
                    "emailAddress" = @{
                        "address" = $toAddress2
                    }
                }
            )
        }
    }) | ConvertTo-JSON -Depth 10
  }
  # Send the message
  Invoke-RestMethod @params -Verbose

The email runbook will fail if I null or blank $toAddress2, or if I have anything other than a valid email address. I've tried converting $toAddress1 to an array, like so, $toAddress1 = @{"address" = "user1@company.com"; "address" = "user2@company.com"}, but that fails because you cannot have duplicate keys in an array.

Or is the best option to simply build the Graph API request params at the end of each runbook, then pass that as a variable to the email runbook?


Solution

  • You can use a single array and then have a loop in the toRecipients property to dynamically handle the recipients:

    $toAddress = 'user1@company.com', 'user2@company.com'
    
    if ($toAddress.Count -eq 0) {
        # you should exit early here since there are no recipients
        throw 'No rescipients...'
    }
    
    $params = @{
        URI         = "https://graph.microsoft.com/v1.0/users/$fromAddress/sendMail"
        Headers     = @{
            Authorization = 'Bearer {0}' -f $token
        }
        Method      = 'POST'
        ContentType = 'application/json'
        Body        = @{
            message = @{
                subject      = $mailSubject
                body         = @{
                    contentType = 'Text'
                    content     = $mailMessage
                }
                toRecipients = @(
                    # here you can add a loop to create a new hashtable
                    # per recipient in `$toAddress`
                    $toAddress | ForEach-Object {
                        @{
                            emailAddress = @{
                                address = $_
                            }
                        }
                    }
                )
            }
        } | ConvertTo-Json -Depth 10
    }
    

    You could also set up input parameters in your runbook instead of hardcoding the recipients, so you can pass them in when calling your runbook:

    param([Parameter(Mandatory)] [string[]] $Recipients)
    
    $params = @{
        URI         = "https://graph.microsoft.com/v1.0/users/$fromAddress/sendMail"
        Headers     = @{
            Authorization = 'Bearer {0}' -f $token
        }
        Method      = 'POST'
        ContentType = 'application/json'
        Body        = @{
            message = @{
                subject      = $mailSubject
                body         = @{
                    contentType = 'Text'
                    content     = $mailMessage
                }
                toRecipients = @(
                    $Recipients | ForEach-Object {
                        @{
                            emailAddress = @{
                                address = $_
                            }
                        }
                    }
                )
            }
        } | ConvertTo-Json -Depth 10
    }