Setup Powershell Actions for Torii

Torii Integration for Azure Advanced Automation

Overview

Some of Torii’s Entra Microsoft 365 actions leverage Azure’s advanced automation capabilities. Additional installation steps are required in order to execute these actions.

The guide below describes how to create an Azure Automation Runbook, and securely enable Torii to execute it via webhooks.

Please follow the steps below to fully leverage Torii’s Entra Microsoft 365 offering. Skipping any of these steps may prevent you from using said actions. In case you encounter difficulties during the installation process, don’t hesitate to reach out to Torii’s Customer Support [[email protected]](mailto:[email protected])

1. Service Account Setup

To begin, you'll need a Service Account without Multi-Factor Authentication (MFA) with the permissions outlined below. You may use an existing account that fits these criteria or create a new one by following these steps:

  1. Access the Admin Portal: Navigate to admin.microsoft.com.

  2. Create a New User:

    • Select "Users" from the left-hand menu.
    • Click on "Add a single user".
      • This new user will be associated with your Azure Automation account.
      • Password Policy: If your organization enforces a password policy, ensure that you update the credential password in Azure Automation whenever it changes to prevent any disruptions in script execution.
    image.png
  3. Configure the New Service Account User

    1. When setting up the new user, fill out the following fields:

      • Display Name: ToriiUser
      • Username: ToriiUser
      • Keep the “Automatically create a password” checkbox unchecked.
      • Password: Generate a strong password and store it securely, preferably using a password manager.
    2. click "Next" to continue.

      image.png
    3. Choose "Create user without product license".

    4. Click "Next".

      image.png
    5. Select the "Admin center access" radio button.

    6. Under "Admin center access", assign the following roles:

      • Exchange admin
      • Global admin
    7. Then, proceed by clicking "Next".

      image.png
    8. Review all the information to ensure accuracy, then click "Finish adding".

      image.png
    9. Important: This is your last chance to view the generated password. Save it securely, as you'll need it later when creating a credential in Azure Automation.

      image.png

2. Create an Azure Automation account

  1. Start the Creation Process:

    • Go to the Azure portal at portal.azure.com.
    • Click on "Create" in the upper-left corner.
    image.png
  2. Fill the following fields:

    • Subscription: Choose the subscription you want to use for the new Automation account.

      • Resource Group:

        • Click on "Create new".

        • Name it "Torii".
          image.png

        • Ensure that this new resource group is selected.
          image.png

    • Automation Account Name: Enter "Torii Automation".

    • Location: Choose the region that best fits your needs.

    • Click "Next" to continue.
      Screenshot 2024-11-20 at 9.06.27.png

  • On the Advance section:
    • Check the "System Assigned" option.
    • Click "Next".
      image.png
  • On the Networking page:
    • Select "Public access".
    • Click "Review + Create"
  • Note: Tags are optional and can be left blank.
    image.png
  • Review and Create:
    • Double-check all your entries.
    • Click "Create" to finalize.
      image.png
  • Completion:
    • Wait for the deployment to finish.
    • Your new Automation account will now appear in your resource list.
      image.png

3. Assign Microsoft Entra Roles and Administrators to the Automation Account

  1. Navigate to Microsoft Entra Roles and Administrators:

  2. Assign the Exchange Administrator Role:

    • In the Roles and Administrators section, search for Exchange Administrator.

    • Click on the role to open its settings.
      image.png

    • Select "Add Assignment".
      image.png

    • Search for your Automation account's name (e.g., "ToriiAutomationAccount").
      image.png

    • Check the box next to it and click "Add".
      image.png

    • Confirm that your Automation account now appears under the Exchange Administrator role.
      image.png

  3. Assign the Global Administrator Role:

    • Repeat the steps above, but this time search for Global Administrator.
    image.png

4. Add PowerShell Modules to The Automation Account

  1. Navigate to Automation Accounts:

    • Follow this link: Automation Accounts.
      • Alternatively, use the search bar at the top of the Azure portal to search for Automation Accounts.
    • Select the Automation Account you created in Step 2 (referred to as ToriiAutomationAccount in these instructions).
      image.png
  2. Import Modules:

    • Go to Shared Resources > Modules.
    • Click on "Browse Gallery".
    image.png
  3. Search and Import Modules:

    • Look for the following modules and import them one by one, ensuring you set the Runtime Version to 5.1 for each:

      • Microsoft.Graph.Authentication
      • PackageManagement
      • PowerShellGet
      • ExchangeOnlineManagement
    • Note: The order in which these modules are imported is important.

    • Import Example: Microsoft.Graph.Authentication.

      • Search for the Microsoft.Graph.Authentication module and click on it.
        image.png

      • Click on “Select”
        image.png

      • Set the Runtime Version to 5.1 and click Import.

        • Note: Importing may take several minutes.
          image.png
      • Wait until each module's status changes to "Available" before proceeding to the next.
        image.png
        image.png

  • Now you can continue to perform the same steps for the modules: PackageManagement , PowerShellGet,ExchangeOnlineManagement (Remember: The order is important!):
image.png image.png image.png

5. Create Credential

  1. Navigate to Automation Accounts:
    • Follow this link: Automation Accounts.
      • Alternatively, use the search bar at the top of the Azure portal to search for Automation Accounts.
    • Select the Automation Account you created in Step 2 (referred to as ToriiAutomationAccount in these instructions).

2. Access Credentials:

  • In your Automation account, go to Shared Resources > Credentials.
  • Click on "Add a credential".
image.png
  1. Enter Credential Details:

    Use the service account credentials created in Step 1 (Service Account Setup).

    • Name - Enter the Display name created in Step 1.
      • Remember, the Name you assign here will be needed later when connecting Microsoft Entra ID to Torii.
    • User name - Enter the email address created in Step 1
    • Password - Enter the password created in Step 1
  • Click "Create" to save the credential.
    image.png
    image.png
  • The value entered in the Name field will be used later to connect the Microsoft Entra ID integration to Torii.
    image.png

6. Create a Runbook

  1. Navigate to Automation Accounts:

    • Follow this link: Automation Accounts.
      • Alternatively, use the search bar at the top of the Azure portal to search for Automation Accounts.
  2. Select the Automation Account you created in Step 2 (referred to as ToriiAutomationAccount in these instructions).

  3. In the Automation Account, navigate to Process Automation, select Runbooks, and then click Create a runbook.

    image.png
  4. Configure Runbook Settings:

    • Name: Enter "ToriiAutomationRunbook".
    • Runbook Type: Select "PowerShell".
    • Runtime Version: Choose "5.1".
    • Click "Review + Create"
image.png
  • Click “Create”
image.png
  • After creating the Runbook, you'll be directed to the PowerShell editor.
image.png

7. Add a PowerShell Script

  1. Open the Editor

  2. Insert the Script:

    • Copy your PowerShell script and paste it into the editor.
      • Note - as Torii adds more Powershell-based actions, this script may change.
    Param
    (
        [object]$WebhookData
    )
    
    function Logger {
        param (
            [string]$Level,
            [string]$Message
        )
        $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
        Write-Output "$timestamp [$Level] - $Message"
    }
    
    function ConvertMailboxToShared {
        param (
            [string]$Email
        )
    
        Logger -Level "INFO" -Message "Starting conversion of mailbox '$Email' to shared mailbox."
    
        # Convert mailbox type
        Set-Mailbox -Identity $Email -Type Shared -ErrorAction Stop
    
        Logger -Level "INFO" -Message "Set-Mailbox command executed successfully for '$Email'."
    
        # Verify conversion
        $mailbox = Get-Mailbox -Identity $Email -ErrorAction Stop
    
        if ($mailbox.RecipientTypeDetails -eq "SharedMailbox") {
            Logger -Level "INFO" -Message "Successfully converted mailbox '$Email' to shared mailbox."
        } else {
            $errorMessage = "Verification failed: Mailbox '$Email' is not a shared mailbox. Current Type: $($mailbox.RecipientTypeDetails)"
            Logger -Level "ERROR" -Message $errorMessage
            throw "Mailbox conversion failed - $errorMessage"
        }
    }
    
    function AddUserToExchangeGroups {
        param (
            [string]$UserEmail,
            [string[]]$GroupsEmailsList
        )
    
        $TotalGroups = $GroupsEmailsList.Count
        Logger -Level "INFO" -Message "Starting adding user '$UserEmail' to '$TotalGroups' groups."
    
        $Results = @{}
    
        foreach ($groupEmail in $GroupsEmailsList) {
            try {
                # Attempt to add the user to the current group
                Add-DistributionGroupMember -Identity $groupEmail -Member $UserEmail -BypassSecurityGroupManagerCheck -Confirm:$false -ErrorAction Stop
                Logger -Level "INFO" -Message "User ($UserEmail) successfully added to group ($groupEmail)."
                $Results[$groupEmail] = "Success"
            } catch {
                # Capture any errors for each group and continue
                Logger -Level "ERROR" -Message "Failed to add user ($UserEmail) to group ($groupEmail). Error: $_"
                $Results[$groupEmail] = "Failed. Error: $_"
            }
        }
    
        $ResultsJson = $Results | ConvertTo-Json -Depth 5 -Compress
        Logger -Level "INFO" -Message "AddUserToExchangeGroups function completed with the results: $ResultsJson"
    }
    
    function RemoveUserFromExchangeGroups {
        param (
            [string]$UserEmail,
            [string[]]$GroupsEmailsList
        )
    
        $TotalGroups = $GroupsEmailsList.Count
        Logger -Level "INFO" -Message "Starting removing user '$UserEmail' from '$TotalGroups' groups."
    
        $Results = @{}
    
        foreach ($groupEmail in $GroupsEmailsList) {
            try {
                # Attempt to remove the user from the current group
                Remove-DistributionGroupMember -Identity $groupEmail -Member $UserEmail -BypassSecurityGroupManagerCheck -Confirm:$false -ErrorAction Stop
                Logger -Level "INFO" -Message "User ($UserEmail) successfully remove from group ($groupEmail)."
                $Results[$groupEmail] = "Success"
            } catch {
                # Capture any errors for each group and continue
                Logger -Level "ERROR" -Message "Failed to remove user ($UserEmail) from group ($groupEmail). Error: $_"
                $Results[$groupEmail] = "Failed. Error: $_"
            }
        }
    
        $ResultsJson = $Results | ConvertTo-Json -Depth 5 -Compress
        Logger -Level "INFO" -Message "RemoveUserFromExchangeGroups function completed with the results: $ResultsJson"
    }
    
    # Initialize logging
    Logger -Level "INFO" -Message "Runbook execution started."
    
    # Validate and parse webhook data
    if (-not $WebhookData) {
        Logger -Level "ERROR" -Message "No WebhookData provided. Exiting runbook."
        throw "Missing WebhookData."
    }
    
    Logger -Level "INFO" -Message "Webhook data received. Parsing request body."
    $WebhookBody = ConvertFrom-Json -InputObject $WebhookData.RequestBody
    $UserEmail = $WebhookBody.email
    $Operation = $WebhookBody.operation
    $CredentialName = $WebhookBody.credentialName
    
    Logger -Level "INFO" -Message "Parsed UserEmail: $UserEmail, Operation: $Operation, CredentialName: $CredentialName"
    
    # Validate required fields
    if (-not $UserEmail -or -not $Operation -or -not $CredentialName) {
        Logger -Level "ERROR" -Message "Invalid webhook data: Missing 'email' or 'operation'."
        throw "Invalid webhook data."
    }
    
    # Disconnect existing PowerShell sessions
    Logger -Level "INFO" -Message "Disconnecting existing PowerShell sessions."
    Get-PSSession | Remove-PSSession -ErrorAction SilentlyContinue
    
    # Authentication
    Logger -Level "INFO" -Message "Authenticating to Exchange Online and Microsoft Graph."
    
    $UserCredential = Get-AutomationPSCredential -Name $CredentialName
    if (-not $UserCredential) {
        throw "Failed to retrieve credentials from Automation Account."
    }
    
    Connect-ExchangeOnline -Credential $UserCredential -ShowProgress $false
    
    Logger -Level "INFO" -Message "Successfully authenticated to Exchange Online and Microsoft Graph."
    
    switch ($Operation) {
        "CONVERT_MAILBOX_TO_SHARED" {
            ConvertMailboxToShared -Email $UserEmail
        }
        "ADD_USER_TO_EXCHANGE_GROUPS" {
            $GroupsEmailsList = $WebhookBody.exchangeGroupsEmailsList
            AddUserToExchangeGroups -UserEmail $UserEmail -GroupsEmailsList $GroupsEmailsList
        }
        "REMOVE_USER_FROM_EXCHANGE_GROUPS" {
            $GroupsEmailsList = $WebhookBody.exchangeGroupsEmailsList
            RemoveUserFromExchangeGroups -UserEmail $UserEmail -GroupsEmailsList $GroupsEmailsList
        }
        default {
            Logger -Level "WARNING" -Message "Unsupported operation '$Operation' requested."
            throw "Unsupported operation."
        }
    }
    
    Logger -Level "INFO" -Message "Disconnecting from Exchange Online."
    
    Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue
    Get-PSSession | Remove-PSSession -ErrorAction SilentlyContinue
    
    Logger -Level "INFO" -Message "Runbook execution completed successfully."
    
    

3. Save and Publish:

  • Click "Save" to store your changes.
    image.png

  • Then, click "Publish" to make the Runbook active.
    image.png

  • Confirm by clicking "Yes".
    image.png

  1. Note Essential Details:

    • After publishing, you'll be back on the Runbook's Overview page.
    • Make sure to note the following information for later use when connecting to Torii:
      • Subscription ID - (e.g., "65040bf1-caa3-4367-8e0e-7930b4efcf1f")
      • Automation Account Name (e.g., "ToriiAutomationAccount")
      • Resource Group Name (e.g., "Torii")
    image.png image.png

8. Create a Webhook

  1. Add a Webhook

    • On the Runbook's Overview page (runbook created in Step 6), click on "Add webhook".
    image.png
  2. Configure the Webhook:

    • Click "Create new webhook".
      image.png
    • Name - Enter “ToriiWebhook” in the Name field.
    • Enabled - Select "Yes" to enable the webhook.
    • Expires - Choose a date at least one year ahead. Remember to set a reminder to update it before it expires to prevent any service interruption.
    • URL - Copy the generated webhook URL and store it securely. This is the only time you'll see it.
    • Click “OK” to confirm
      image.png
      image.png
  3. Finalize Webhook Creation

    • Click "Parameters and run settings"
      image.png
  • Leave the "WEBHOOKDATA" field empty and click "OK".
    image.png
  • Click "Create" to finish setting up the webhook.
    image.png

9. Connect Entra Microsoft 365 Integration in Torii

  1. Access Torii Integrations:
    • Log in to your Torii account.
    • Navigate to the "Integrations" section.
  2. Connect Microsoft Entra ID:
    • Choose "Microsoft Entra ID" from the list.
  3. Provide Required Information:

10. Guidance for Customers Using Existing PowerShell Custom Actions

Please reconnect the integration and provide the credentials specified in Step 9, using your existing Subscription ID, Automation Account Name, and Resource Group.

  • "Credential Name” will need to be filled with your Domain Entra ID (email domain)
image.png

You can find the Domain Entra ID in your existing PowerShell script, as shown below:

image.png
  • Modify the Authentication Section in the Script we provided in step 7
$UserCredential = Get-AutomationPSCredential -Name $CredentialName
if (-not $UserCredential) {
    throw "Failed to retrieve credentials from Automation Account."
}

Connect-ExchangeOnline -Credential $UserCredential -ShowProgress $false

With that code:

Connect-ExchangeOnline -ManagedIdentity -Organization $CredentialName

The way we implemented in step 7:

image.png

The change you should be doing:

image.png