> ## Documentation Index
> Fetch the complete documentation index at: https://bloodhound.specterops.io/llms.txt
> Use this file to discover all available pages before exploring further.

# AzureHound Enterprise Azure Configuration

> This section details creating and configuring an Enterprise Application for AzureHound within Microsoft Entra ID, including API permissions, roles, and authentication certificate.

<img noZoom src="https://mintcdn.com/specterops/tTIczgde9H07oLXf/assets/enterprise-edition-pill-tag.svg?fit=max&auto=format&n=tTIczgde9H07oLXf&q=85&s=b682a26b342bde12302ec829e265bdb6" alt="Applies to BloodHound Enterprise only" width="225" height="45" data-path="assets/enterprise-edition-pill-tag.svg" />

## Create the AzureHound Enterprise app

1. Log into the [Microsoft Entra admin center](https://entra.microsoft.com/) as a user with the [Global Administrator] role,
   or the following less privileged roles:

   * [Privileged Role Administrator] AND
   * [Application Administrator] OR [Cloud Application Administrator]

[Global Administrator]: https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#global-administrator

[Privileged Role Administrator]: https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#privileged-role-administrator

[Cloud Application Administrator]: https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#cloud-application-administrator

[Application Administrator]: https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#application-administrator

2. In the left menu, select **App registrations**.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/azurehound-install-app-registrations.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=a4e9c9aa120f9e62249bd377535295de" alt="" width="399" height="499" data-path="assets/azurehound-install-app-registrations.png" />
   </Frame>

3. Click **New registration**.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/image-103.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=df84018a2dd31413f6d857718188e04c" alt="" width="656" height="168" data-path="assets/image-103.png" />
   </Frame>

4. In the **Name** field, give the application an identifying name in your organization. Make sure the supported account type is set to the "Accounts in this organizational directory only (Single tenant)" option. A URI is not required. Then click **Register**.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/image-104.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=3d5e010ba126385566d1cc4e856ef96f" alt="" width="904" height="466" data-path="assets/image-104.png" />
   </Frame>

5. In the **Overview** menu, copy the **Application (client) ID** and **Directory (tenant) ID** to be used later in [AzureHound Enterprise Local Configuration](/install-data-collector/install-azurehound/create-configuration).
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/image-105.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=8535693cfc0a2063b15891015d41f434" alt="" width="904" height="432" data-path="assets/image-105.png" />
   </Frame>

6. Continue to the next section: "Grant Microsoft Graph Permissions".

## Grant Microsoft Graph Permissions

1. In the AzureHound application, select **API Permissions**.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/image-106.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=6e021f7e8ce220017a717e0af25719b0" alt="" width="488" height="722" data-path="assets/image-106.png" />
   </Frame>

2. Remove the default **User.Read** delegated permission from the application, as it is not needed for data collection. Confirm the operation in the dialog window that appears after selecting the **Remove permission** option from the context menu.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/azurehound-install-remove-user-read-permission.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=521609a401d2d6a29cd6f9e2a9c6e9f5" alt="" width="1508" height="363" data-path="assets/azurehound-install-remove-user-read-permission.png" />
   </Frame>

3. Select **Add a permission**.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/image-107.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=c236d5e3f707cca44b61bdd3c5c8112c" alt="" width="446" height="336" data-path="assets/image-107.png" />
   </Frame>

4. Click on **Microsoft Graph**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-108.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=1f85bfda6d47f5cafc107dd02e21a68c" alt="" width="892" height="274" data-path="assets/image-108.png" />
   </Frame>

5. Select **Application permissions**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-109.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=e8c8e74175a87b01acc9e06ac8e998cf" alt="" width="878" height="248" data-path="assets/image-109.png" />
   </Frame>

6. Search for the **Directory.Read.All** permission and check the box next to it.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-110.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=d13b8b8a106a24251335966812115d2d" alt="" width="688" height="268" data-path="assets/image-110.png" />
   </Frame>

7. Search for the **RoleManagement.Read.All** permission and check the box next to it.
   <Frame>
     <img src="https://mintcdn.com/specterops/Nu4joEwQOPBqRMJT/images/data_collectors/rolemanagement_read_all.png?fit=max&auto=format&n=Nu4joEwQOPBqRMJT&q=85&s=f412cea32cb18564cdf7804d437bca49" alt="" width="884" height="492" data-path="images/data_collectors/rolemanagement_read_all.png" />
   </Frame>

8. (Optional step to collect AZUser.LastSuccessfulSignInDateTime) Search for the **AuditLog.Read.All** permission and check the box next to it.
   <Frame>
     <img src="https://mintcdn.com/specterops/LiLBlmBO1w5tejs8/images/data_collectors/auditlog-read-all.png?fit=max&auto=format&n=LiLBlmBO1w5tejs8&q=85&s=67ad0a0670d05ad8f4bbc80d6f194f89" alt="" width="675" height="342" data-path="images/data_collectors/auditlog-read-all.png" />
   </Frame>

9. In the bottom of the window, select **Add permissions**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-111.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=83bb35fa9d4adb2560937aab179529b7" alt="" width="388" height="110" data-path="assets/image-111.png" />
   </Frame>

10. Click on **Grant admin consent for \<your\_tenant\_name>**.

<Frame>
  <img src="https://mintcdn.com/specterops/Nu4joEwQOPBqRMJT/images/data_collectors/grant_admin_consent.png?fit=max&auto=format&n=Nu4joEwQOPBqRMJT&q=85&s=dbee7e7c1aba11566b1ca4afe17ea38f" width="1721" height="667" data-path="images/data_collectors/grant_admin_consent.png" />
</Frame>

11. Click **Yes** on the confirmation dialog.

<Frame>
  <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-113.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=322625926c0260d3fbd87481ca484295" alt="" width="872" height="208" data-path="assets/image-113.png" />
</Frame>

12. After being redirected to API Permissions again, you should see both permissions as **Granted**.

<Frame>
  <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/azurehound-install-consent-granted.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=072f5cba762113a9c82265aa407351c4" alt="" width="1527" height="390" data-path="assets/azurehound-install-consent-granted.png" />
</Frame>

13. Continue to the next section: "Add application authentication certificate".

## Add application authentication certificate

This section requires you have authentication material.

We highly recommend using certificate-based authentication. If you do not already have a certificate created, follow the article [AzureHound Enterprise Local Configuration](/install-data-collector/install-azurehound/create-configuration) and then return back here.

1. Select the **Certificates & secrets** section on the left.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-138.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=c0d3f4ff5ed6ebd7199a12c460d6245a" alt="" width="396" height="440" data-path="assets/image-138.png" />
   </Frame>

2. Click on **Certificates**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-139.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=3964b1c6976b3bf2c0d334fbcbd1d64f" alt="" width="736" height="308" data-path="assets/image-139.png" />
   </Frame>

3. Click **Upload certificate**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-140.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=e5c525ce1a8f6c40420c7622eb49d012" alt="" width="836" height="270" data-path="assets/image-140.png" />
   </Frame>

4. Locate the **cert.pem** file created during AzureHound setup (either on your own, or utilizing the instructions at [AzureHound Enterprise Local Configuration](/install-data-collector/install-azurehound/create-configuration)).

5. Click the folder icon and locate the "cert.pem" file. Add a description if desired.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-141.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=d77903e276e9e9a3c9e185b5e5c41a3f" alt="" width="880" height="266" data-path="assets/image-141.png" />
   </Frame>

6. In the bottom of the window, select **Add**.

7. Continue to the next section to optionally configure application branding.

## Configure application branding (optional)

*Note: All steps in this section are optional and do not affect the functionality of the collector.*

1. Download the [AzureHound Enterprise icon](/assets/icons/entra-bhe-app-icon.png) to your computer.

2. Still on the AzureHound application in the Entra ID admin center, open the **Branding & properties** section.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/azurehound-install-branding.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=0252134259f3a6e829ead8b6e1f36cf2" alt="" width="363" height="501" data-path="assets/azurehound-install-branding.png" />
   </Frame>

3. Click the **Select a file** button and browse to the file you previously downloaded.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/azurehound-install-upload-logo.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=571584c10bde3203c3dfab9a82a81ad4" alt="" width="919" height="245" data-path="assets/azurehound-install-upload-logo.png" />
   </Frame>

4. Provide a human-readable **Name** for the application, e.g., **BloodHound Enterprise Collector (AzureHound)**.

5. Type your BloodHound Enterprise tenant URL into the **Home page URL** field. This is for record keeping only.

6. Click the **Save** button and review the results.
   <Frame>
     <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/azurehound-install-branding-result.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=03b80003e6801473d1db6abf4e2b3d13" alt="" width="919" height="301" data-path="assets/azurehound-install-branding-result.png" />
   </Frame>

7. Continue to the next section to assign the Directory Readers role on your Entra ID tenant.

## Assign "Directory Readers" role on the Entra ID tenant

1. In the left menu, select **Roles & admins**.

<Frame>
  <img src="https://mintcdn.com/specterops/WEkd5VoEgwJOJjlW/assets/azurehound-install-entra-id-roles.png?fit=max&auto=format&n=WEkd5VoEgwJOJjlW&q=85&s=b0f94acb510167e287fea0ae9e0e2c77" alt="" width="399" height="549" data-path="assets/azurehound-install-entra-id-roles.png" />
</Frame>

2. Search for the role **Directory Readers** and click the role name or description.
   *Note: Clicking the checkbox sometimes prevents clicking on the role itself.*
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-117.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=47ced2659e5ebeb3c96507d0d5924f55" alt="" width="532" height="292" data-path="assets/image-117.png" />
   </Frame>

3. In the "Directory Readers" role, select **Add assignments**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-118.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=466b82f60e7630a5546ec56497020705" alt="" width="540" height="176" data-path="assets/image-118.png" />
   </Frame>

4. Click **No member selected** to open the search window.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-119.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=38d982f8656c9d4bbcbb5a79c49a8a47" alt="" width="562" height="576" data-path="assets/image-119.png" />
   </Frame>

5. Search for the previously created service principal with either its name, application ID, or object ID. Select it by clicking on it.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-120.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=fedfe8b322ccc8d69d57154786282581" alt="" width="668" height="282" data-path="assets/image-120.png" />
   </Frame>

6. Click **Select**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-121.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=35d0be9c46281daba5ad6454ca4f1686" alt="" width="584" height="266" data-path="assets/image-121.png" />
   </Frame>

7. Validate that your principal is displayed and click **Next**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-122.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=b1f466467a89a9be090c49a5c2257a83" alt="" width="574" height="294" data-path="assets/image-122.png" />
   </Frame>

8. Ensure that the Assignment type is **Active** and the **Permanently assigned** box is checked. Provide a justification and click **Assign**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-123.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=f685d7d68c5166fc37d2e1d12299f593" alt="" width="560" height="668" data-path="assets/image-123.png" />
   </Frame>

9. Confirm the service principal is a Directory Reader by refreshing this view.

10. Continue to the next section to assign the Reader role on your Azure subscriptions.

## Grant "Reader" role on all Azure subscriptions

*Note: If you do not have any management groups, you may either create your Tenant Root Group following the prompts in the middle of the screen to ensure future visibility if another administrator begins use of subscriptions, or you may skip this section altogether. If you skip this section, you will see a warning in the logs for each collection indicating the lack of ability to collect this data accordingly.*

1. Log into the [Azure portal](https://portal.azure.com/) as a user with the [User Access Administrator](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/privileged#user-access-administrator) role.

2. Search for and select the **Management groups** item in the top search bar.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-124.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=9fb5079386412b14dd66c68f1f464e6f" alt="" width="560" height="284" data-path="assets/image-124.png" />
   </Frame>

3. Select **Tenant Root Group**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-125.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=81d12d325e77962f5aaa824fce47aad9" alt="" width="656" height="522" data-path="assets/image-125.png" />
   </Frame>

4. Select **Access control (IAM)**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-126.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=e6cac97b5e1248d6d8defcb09df09881" alt="" width="334" height="370" data-path="assets/image-126.png" />
   </Frame>

5. Select **Role assignments**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-127.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=ff8d9a0af027d00649d2e95a4ac2b69f" alt="" width="642" height="246" data-path="assets/image-127.png" />
   </Frame>

6. Click **Add**, then **Add role assignment**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-128.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=578782f34dbd9614bc5e69bf7cc7498f" alt="" width="696" height="308" data-path="assets/image-128.png" />
   </Frame>

7. Find the **Reader** role and select it.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-129.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=39e9ef55ac49b031ff221a415fbbd31a" alt="" width="548" height="288" data-path="assets/image-129.png" />
   </Frame>

8. Click **Members**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-130.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=2d275360ab8ef54c598d4168b665e292" alt="" width="480" height="196" data-path="assets/image-130.png" />
   </Frame>

9. Click **Select members**.
   <Frame>
     <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-131.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=57de5ece40ffd1cde30bff363f2eaf28" alt="" width="420" height="252" data-path="assets/image-131.png" />
   </Frame>

10. Search for and click on your previously created service principal.

<Frame>
  <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-132.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=d531d45dbd80db7845f8988ec3b1049a" alt="" width="492" height="226" data-path="assets/image-132.png" />
</Frame>

11. Validate the principal selected, then click **Select**.
    <Frame>
      <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-133.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=86120fa8ad87a876d9e576f7078f9087" alt="" width="392" height="300" data-path="assets/image-133.png" />
    </Frame>

12. Click the tab **Review + Assign**.
    <Frame>
      <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-134.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=e863d7bf2125b71aa486dedbdf18260a" alt="" width="476" height="248" data-path="assets/image-134.png" />
    </Frame>

13. Click **Review + Assign** at the bottom of the page.
    <Frame>
      <img src="https://mintcdn.com/specterops/dSyPFnFn7QBl0TvL/assets/image-135.png?fit=max&auto=format&n=dSyPFnFn7QBl0TvL&q=85&s=696d9929cb9f2deb230ad936541cf93f" alt="" width="476" height="130" data-path="assets/image-135.png" />
    </Frame>

14. Confirm the role is present by refreshing this view. You may need to alter the filter to see this role.

15. Continue to [Run and Upgrade AzureHound (Windows, Docker, or Kubernetes)](/install-data-collector/install-azurehound/installation-options)

## Scripted app registration

As an alternative to the manual app registration process described in this document, you can use **PowerShell** to achieve the same.
Below is a sample PowerShell script that performs all the required steps,
with the exception of [configuring the authentication certificate](#add-application-authentication-certificate).

```powershell theme={null}
<#
.SYNOPSIS
Registers the Azure Data Exporter for BloodHound Enterprise (AzureHound)
as an application in Entra ID.

.DESCRIPTION
This script registers the Azure Data Exporter for BloodHound Enterprise (AzureHound)
as an on-prem application in Microsoft Entra ID and Azure,
including all the necessary read permissions.

The required PowerShell modules can be installed
from the PowerShell Gallery using the following command:

Install-Module -Scope AllUsers -Repository PSGallery -Force -Name @(
    Microsoft.Graph.Applications,
    Microsoft.Graph.Authentication,
    Microsoft.Graph.Identity.DirectoryManagement,
    Az.Resources,
    Az.Accounts
)

.NOTES
Version: 1.1
#>

#Requires -Version 5
#Requires -Modules Microsoft.Graph.Applications,Microsoft.Graph.Authentication
#Requires -Modules Microsoft.Graph.Identity.DirectoryManagement
#Requires -Modules Az.Resources,Az.Accounts

#region Entra ID

# Connect to Microsoft Entra ID through the Microsoft Graph API
# Note: The -TenantId parameter is also required when using an External ID.
Connect-MgGraph -NoWelcome -ContextScope Process -Scopes @(
   'User.Read',
   'Application.ReadWrite.All',
   'AppRoleAssignment.ReadWrite.All',
   'RoleManagement.ReadWrite.Directory'
)

# Register the AzureHound application
[string] $appName = 'BloodHound Enterprise Collector'
[string] $appDescription =
  'Azure Data Exporter for BloodHound Enterprise (AzureHound)'
# TODO: Optionally provide the actual URL your BloodHound Enterprise tenant
[string] $homePage = 'https://specterops.io/bloodhound-enterprise'
[hashtable] $infoUrls = @{
    MarketingUrl      = 'https://specterops.io/bloodhound-enterprise'
    TermsOfServiceUrl = 'https://specterops.io/terms-of-service'
    PrivacyStatementUrl = 'https://specterops.io/privacy-policy'
    SupportUrl = 'https://support.bloodhoundenterprise.io/'
}
[hashtable] $webUrls = @{
    HomePageUrl = $homePage
}

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphApplication] $registeredApp =
   New-MgApplication -DisplayName $appName `
                     -Description $appDescription `
                     -Info $infoUrls `
                     -Web $webUrls `
                     -SignInAudience 'AzureADMyOrg'

# Configure the application logo
[string] $logoUrl =
  'https://bloodhound.specterops.io/assets/icons/entra-bhe-app-icon.png'
[string] $tempLogoPath = New-TemporaryFile

Invoke-WebRequest -Uri $logoUrl `
                  -OutFile $tempLogoPath `
                  -UseBasicParsing `
                  -ErrorAction Stop
try {
    Set-MgApplicationLogo -ApplicationId $registeredApp.Id `
                          -ContentType 'image/png' `
                          -InFile $tempLogoPath
}
finally {
    # Delete the local copy of the logo from temp
    Remove-Item -Path $tempLogoPath
}

# Make sure the app instance property lock is enabled
Update-MgApplication `
  -ApplicationId $registeredApp.Id `
  -ServicePrincipalLockConfiguration @{
    IsEnabled = $true
    AllProperties = $true
}

# Create the associated service principal object
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphServicePrincipal] $servicePrincipal =
   New-MgServicePrincipal -DisplayName $appName `
                          -AppId $registeredApp.AppId `
                          -AccountEnabled `
                          -ServicePrincipalType Application `
                          -Notes $appDescription `
                          -Homepage $homePage `
                          -Tags 'WindowsAzureActiveDirectoryIntegratedApp','HideApp'

# Fetch the Microsoft Graph applicaton ID,
# which should be 00000003-0000-0000-c000-000000000000
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphServicePrincipal] $microsoftGraph =
    Get-MgServicePrincipal -Filter "DisplayName eq 'Microsoft Graph'"

# Fetch the Directory.Read.All scope ID,
# which should be 7ab1d382-f21e-4acd-a863-ba3e13f7da61
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRole] $readDirectoryScope =
    $microsoftGraph.AppRoles | Where-Object Value -eq 'Directory.Read.All'

# Fetch the RoleManagement.Read.All scope ID,
# which should be c7fbd983-d9aa-4fa7-84b8-17382c103bc4
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRole] $readRolesScope =
    $microsoftGraph.AppRoles | Where-Object Value -eq 'RoleManagement.Read.All'

# Delegate the required API permissions
Update-MgApplication -ApplicationId $registeredApp.Id -RequiredResourceAccess @{
    ResourceAppId = $microsoftGraph.AppId # 00000003-0000-0000-c000-000000000000
    ResourceAccess = @(@{
        id = $readDirectoryScope.Id       # 7ab1d382-f21e-4acd-a863-ba3e13f7da61
        type = 'Role'
    },@{
        id = $readRolesScope.Id           # c7fbd983-d9aa-4fa7-84b8-17382c103bc4
        type = 'Role'
    })
}

# Approve the permissions on the tenant
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRoleAssignment] $readRolesAdminConsent =
    New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $servicePrincipal.Id `
                                            -PrincipalId $servicePrincipal.Id `
                                            -ResourceId $microsoftGraph.Id `
                                            -AppRoleId $readRolesScope.Id

[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphAppRoleAssignment] $readDirectoryAdminConsent =
    New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $servicePrincipal.Id `
                                            -PrincipalId $servicePrincipal.Id `
                                            -ResourceId $microsoftGraph.Id `
                                            -AppRoleId $readDirectoryScope.Id

# Fetch the template ID of the Directory Readers role,
# which should be 88d8e3e3-8f55-4a1e-953a-9b9898b8876b
[Microsoft.Graph.PowerShell.Models.MicrosoftGraphDirectoryRole] $directoryReadersRole =
    Get-MgDirectoryRole -Filter "displayName eq 'Directory Readers'"

# Get the environment-specific Microsoft Graph API endpoint
# Azure Global: https://graph.microsoft.com
# Azure USGov:  https://graph.microsoft.us
[string] $graphEndpoint =
    (Get-MgEnvironment -Name (Get-MgContext).Environment).GraphEndpoint

# OData IDs need to be used when assigning role membership,
# e.g., https://graph.microsoft.com/v1.0/serviceprincipals/{46615ae4-da39-4403-8de2-606e10774ae0}
[string] $servicePrincipalOdataId =
  "$graphEndpoint/v1.0/serviceprincipals/{$($servicePrincipal.Id)}"

# Assign the Directory Readers Entra ID Role to the service principal
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $directoryReadersRole.Id `
                               -OdataId $servicePrincipalOdataId

# Fetch the info about the current user
[Microsoft.Graph.PowerShell.Models.IMicrosoftGraphDirectoryObject] $currentUser =
    Invoke-MgGraphRequest -Method GET -Uri '/v1.0/me'

# OData IDs need to be used when assigning application ownership,
# e.g., https://graph.microsoft.com/v1.0/users/{bca3617a-4c54-45eb-9a32-744c1938242e}
[string] $currentUserOdataId = "$graphEndpoint/v1.0/users/{$($currentUser.Id)}"

# Assign the current user as the application object owner
New-MgApplicationOwnerByRef -ApplicationId $registeredApp.Id `
                            -OdataId $currentUserOdataId

# Assign the current user as the service principal owner
New-MgServicePrincipalOwnerByRef -ServicePrincipalId $servicePrincipal.Id `
                                 -OdataId $currentUserOdataId

# Sign out from Microsoft Graph
Disconnect-MgGraph | Out-Null

#endregion Entra ID

#region Azure (Optional)

# Optionally enable browser-based login on Windows 10 and later
Update-AzConfig -EnableLoginByWam $false

# Authenticate against Azure Resource Manager
Connect-AzAccount -Environment AzureCloud -Scope Process

# Fetch the identifier of the Reader role
[string] $rootScope = '/'
[Microsoft.Azure.Commands.Resources.Models.Authorization.PSRoleDefinition] $azureReaderRole =
    Get-AzRoleDefinition -Scope $rootScope -Name 'Reader'

if (-not (Test-Path -Path 'variable:servicePrincipal')) {
    # Fetch the service principal if the Azure part of the script is executed independently
    [Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.IMicrosoftGraphServicePrincipal] $servicePrincipal =
        Get-AzADServicePrincipal -DisplayName 'BloodHound Enterprise Collector'
}

# Fetch the Tenant Root Group
[guid] $currentTenantId = (Get-AzContext).Tenant.Id
[Microsoft.Azure.Commands.Resources.Models.ManagementGroups.PSManagementGroup] $rootManagementGroup =
    Get-AzManagementGroup -GroupName $currentTenantId

# Assign the Reader role on all Azure subscriptions to AzureHound
[Microsoft.Azure.Commands.Resources.Models.Authorization.PSRoleAssignment] $readerRoleAssignment =
    New-AzRoleAssignment -ObjectId $servicePrincipal.Id `
                         -Scope $rootManagementGroup.Id `
                         -RoleDefinitionId $azureReaderRole.Id

# Sign out from Azure Resource Manager
Disconnect-AzAccount -Scope Process

#endregion Azure (Optional)
```
