Category Archives: Azure AD Privileged Identity Management

How to Use Azure AD Privileged Identity Management PowerShell and Graph API

A while back I wrote a blog post on how you could download, install and use a separate Azure AD PIM PowerShell Module for managing Privileged Roles, https://gotoguy.blog/2018/05/22/getting-started-with-azure-ad-pim-powershell-module/. With the recent update of the AzureADPreview Module, the cmdlets for managing Privileged Roles are now included in the module, so there is no longer required to install a separate module for this!

In this blog post I will explain and show how these commands can be used. These PowerShell CmdLets are also at parity with the Graph API, so I will also show equivalent methods for this.

Install or Update AzureADPreview Module

First you need to either install or update the AzureADPreview Module, so that you are running on version 2.0.2.27 or newer.

Update November 23 2020: Latest version of AzureADPreview Module is 2.0.2.129.

The AzureADPreview Module can be installed from PowerShellGallery using Install-Module or Update-Module, and you can verify which version you have installed using Get-Module <modulename> –ListAvailable like this:

image

With that requirement out of the way we can proceed to look at the commands.

Privileged Role Management Commands

Currently in the AzureADPreview Module, there are 13 commands related to Privileged Roles:

Get-Command -Module AzureADPreview | Where-Object {$_.Name -like “*privileged*”}

image

The new cmdlets in AzureADPreview Module related to PIM are documented here, https://docs.microsoft.com/en-us/powershell/module/azuread/?view=azureadps-2.0-preview#privileged_role_management.

Note that some of the above commands are not in that documentation, all the new commands have a *MS* which means it is mapped to equivalent Microsoft Graph API’s.

In the interest of this blog post, here is a quick explanation of each of the available commands:

  • Add-AzureADMSPrivilegedResource. Use this API to add a new azure AD MS privileged resource.
  • Close-AzureADMSPrivilegedRoleAssignmentRequest. Cancel a AzureADMSPrivilegedRoleAssignmentRequest.
  • Get-AzureADMSPrivilegedResource. Get azure AD MS privileged resource.
  • Get-AzureADMSPrivilegedRoleAssignment. Get role assignments for a specific provider and resource.
  • Get-AzureADMSPrivilegedRoleAssignmentRequest. Get role assignment request for a specific resource.
  • Get-AzureADMSPrivilegedRoleDefinition. Get role definitions.
  • Get-AzureADMSPrivilegedRoleSetting. Get role settings.
  • Open-AzureADMSPrivilegedRoleAssignmentRequest. Create a role assignment request.
  • Set-AzureADMSPrivilegedRoleAssignmentRequest. Update a role assignment request.
  • Set-AzureADMSPrivilegedRoleSetting. Update role setting.

The other 3 Privileged Role commands that are still available to use, but currently are not documented on the above link to docs are:

  • Get-AzureADPrivilegedRole. List all Directory Roles available for Privileged Roles assignments.
  • Get-AzureADPrivilegedRoleAssignment. List active and eligible privileged role assignments.
  • New-AzureADPrivilegedRoleAssignment. Creates a new privileged role assignment for specified role and user.

(*) As soon as your tenant is upgraded to using the updated Privileged Identity Management experience for Azure AD roles (see below) these three commands will be outdated and should not be used anymore.

Further on in this blog post I will provide some more examples and usage scenarios for the new Azure AD Privileged Role Management commands, and their equivalent Microsoft Graph API methods, but first something on the difference between Azure Resources and Azure AD, changes in management experience and current limitations in the PowerShell commands.

Azure Resources vs. Azure AD

As you might know, Azure AD PIM can be used for managing privileged role assignments to both Azure AD roles and Azure Resources:

image

The new PowerShell commands that follows the syntax verb-AzureADMSPrivilegedRole…. all require a parameter called ProviderId, which as per today only support “AzureResources”. This means that currently you can only use the new Azure AD PowerShell commands for managing PIM for Azure resources, not for Azure AD roles yet! I had this confirmed with the Microsoft Program Manager for Azure AD PIM, as you can see from the conversation https://twitter.com/stevemsft/status/1143977432690466816?s=20 and shown in the below image:

image

This is related to the following notice from the Azure AD PIM Microsoft Graph documentation, stating that Azure AD roles will move to the Azure resource API in the coming months:

image

Update March 19 2020: Tenants are now starting to get migrated to the new Azure AD PIM provider similar to Azure Resources! If you log in to your tenant and see the following info in the Privileged Identity Management blade, then you can also use the new Azure AD provider, as I will show in the examples below:

As the new PowerShell commands are built on Microsoft Graph, this also means that they will work for Azure AD roles depending o the move to the Azure resources API.

Explore Privileged Resources

image

There are two commands for exploring and adding Privileged Azure Resources:

  • Get-AzureADMSPrivilegedResource –ProviderId azureResources
  • Add-AzureADMSPrivilegedResource –ProviderId azureResources

If you want to explore Privileged Azure AD roles you have to change the ProviderId like this:

  • Get-AzureADMSPrivilegedResource -ProviderId aadroles
  • Add-AzureADMSPrivilegedResource –ProviderId aadroles
g-raph

Their equivalent Microsoft Graph API methods for Azure Resources are (Beta endpoint only as per july 2019):

  • List: GET /privilegedAccess/azureResources/resources
  • Get: GET /privilegedAccess/azureResources/resources/{id}
  • Register: POST /privilegedAccess/azureResources/resources/register

Getting or listing Privileged Resources is based on that you have onboarded to Azure AD PIM for Azure Resources, as explained here: https://docs.microsoft.com/en-us/azure/active-directory/privileged-identity-management/pim-resource-roles-discover-resources. You can also add a privileged resource by ExternalId, which I will show an example of later.

The equivalent Graph API methods for Azure AD roles are (Beta endpoint only as per march 2020):

  • List: GET /privilegedAccess/aadRoles/resources
  • Get: GET /privilegedAccess/aadRoles/resources/{tenantid}
  • Register: POST /privilegedAccess/aadRoles/resources/register (Note per march 2020: There are currently no way to programmatically onboard tenants to PIM for Azure AD roles)

Getting or listing Privileged Azure AD roles requires that you have signed up for PIM for Azure AD roles: https://docs.microsoft.com/en-us/azure/active-directory/privileged-identity-management/pim-getting-started#sign-up-pim-for-azure-ad-roles

Examples of Exploring Privileged Azure Resources

To get a list over all privileged Azure resources, just run:

Get-AzureADMSPrivilegedResource –ProviderId AzureResources

This will return a list (capped at max 200 results), with the Id, ExternalId, Type, DisplayName and more for each resource that have been registered to Azure AD PIM:

image

As mentioned above the list is capped at max 200 results, which is a Microsoft Graph limitation for this privileged resource API. You can use the –Top parameter to specify a lower number of returned results, like –Top 50,  but it will just ignore and cap at 200 if you for example type –Top 300.

So to return fewer results we can use the –Filter parameter which support Odata query. I have tried some different combinations, and not all will work as expected. Some examples of working filters:

Get-AzureADMSPrivilegedResource -ProviderId AzureResources -Filter “Type eq ‘resourcegroup'”

Get-AzureADMSPrivilegedResource -ProviderId AzureResources -Filter “Type eq ‘subscription'”

Get-AzureADMSPrivilegedResource -ProviderId AzureResources -Filter “DisplayName eq ‘elvsabootdiag001”

Get-AzureADMSPrivilegedResource -ProviderId AzureResources -Filter “startswith(DisplayName,’rg-‘)”

image

What I found DON’T work is filters for specific resource types like:

Get-AzureADMSPrivilegedResource -ProviderId AzureResources -Filter “Type eq ‘Microsoft.Compute/virtualMachines'”

..or any other specific resource type like Microsoft.Network/loadBalancers, Microsoft.Network/networkSecurityGroups, etc., which I find is a bit strange as I would like to filter on those as well.

If you know the specific resource id you can also get that privileged resource object directly:

Get-AzureADMSPrivilegedResource -ProviderId AzureResources –Id <resource id>

Lets compare this to the Microsoft Graph API methods, using Graph Explorer. To list all managed Azure Resources I run the GET /privilegedAccess/azureResources/resources like this:

image

Which pretty much returns the same list of resources and attributes as I did when running the PowerShell command. There is one important change though, and I mentioned earlier that the PowerShell command would only return max 200 results. In the Graph response I will receive a skip token from where if I run that I will get the next set of potentially 200 more results, and so on.

Graph can also handle filters of course, so lets try that. Here are some variations you can try out:

GET /privilegedAccess/azureResources/resources?$filter=type eq ‘resourcegroup’&$top=5

GET /privilegedAccess/azureResources/resources?$filter=displayName eq ‘rg-auth-dc’

GET /privilegedAccess/azureResources/resources?$filter=startswith(displayName,’rg-‘)

And if you want to get a specific resource with Graph, just specify the id like this:

GET /privilegedAccess/azureResources/resources/ad7327ba-50f4-4f03-a4ee-029f310b6775

Which will return the specific resource in the response:

image

Last, to add a resource as a managed resource to Azure AD PIM, using PowerShell can be done like this:

Add-AzureADMSPrivilegedResource -ProviderId AzureResources -ExternalId “/subscriptions/<your-subscription-id>”

And via Graph:

POST /privilegedAccess/azureResources/resources/register

Request Body:

{
“externalId”: “/subscriptions/<your-subscription-id>”
}

These commands are just to get a list of and adding managed Azure resources for Azure AD PIM, i the next parts we will look into actually managing assignments and settings.

Examples of Exploring Privileged Azure AD role resource

To get a list over all tenants registered for privileged Azure AD roles, just run:

Get-AzureADMSPrivilegedResource –ProviderId aadRoles

This will return a list of directories that have been onboarded for PIM for Azure AD Roles, with the Id referring to tenant id, Type, DisplayName and more:

If you know the specific tenant id you can also get that privileged resource object directly:

Get-AzureADMSPrivilegedResource -ProviderId aadRoles –Id <tenantid>

Lets compare this to the Microsoft Graph API methods, using Graph Explorer. To list all managed Azure AD roles directories I run the GET /privilegedAccess/aadRoles/resources like this:

Note that you also can specify the resource for Azure AD roles directly, by specifying the tenant id like this:

GET /privilegedAccess/aadRoles/resources/{tenant-id}

These commands are just to get a list and settings for tenant onboarded to Azure AD roles management with Azure AD PIM, i the next parts we will look into actually managing assignments and settings.

Explore Role Assignments

image

The following command can be used for listing or getting specific role assignments for Azure resources:

  • Get-AzureADMSPrivilegedRoleAssignment –ProviderId AzureResources –ResourceId <resource id>

And for Azure AD roles, the command would be the following, where the resource id is the tenant/directory id:

  • Get-AzureADMSPrivilegedRoleAssignment –ProviderId aadRoles –ResourceId <tenant id>
g-raph

The equivalent Microsoft Graph API methods for Azure Resources:

  • List: GET /privilegedAccess/azureResources/resources/{resourceId}/roleAssignments
  • List: GET /privilegedAccess/azureResources/roleAssignments?$filter=resourceId+eq+'{resourceId}’
  • List (Mine): GET /privilegedAccess/azureResources/roleAssignments?$filter=subjectId+eq+'{myId}’
  • Get: GET /privilegedAccess/azureResources/resources/{resourceId}/roleAssignments/{id}
  • Get: GET /privilegedAccess/azureResources/roleAssignments/{id}?$filter=resourceId+eq+'{resourceId}’
  • Get (Mine): GET /privilegedAccess/azureResources/roleAssignments/{id}?$filter=subjectId+eq+'{myId}’

And these are the main Graph API methods for Azure AD roles:

  • List: GET /privilegedAccess/aadRoles/resources/{tenantId}/roleAssignments
  • List (Mine): GET /privilegedAccess/aadRoles/resources/{tenantId}/roleAssignments?$filter=subjectId+eq+'{myId}’
  • List (Role): GET privilegedAccess/aadRoles/resources/{tenantId}/roleAssignments?filter=roleDefinitionId eq ‘{myRoleDefinitionId}’

Now that seems a lot of different variations for Graph calls for the one PowerShell command, but as you will see later Graph can be a little more flexible in querying in different ways.

Examples of Exploring Role Assignments for Azure Resources

Lets see some samples for PowerShell first. Now we need to supply a resource id, that can be subscription object, a resource group object, any type of resource objects like virtual machines, virtual networks and so on, and even management group objects. So based on the commands previously shown in the blog post, we should be able to get out the resource id’s first, for example like this:

$myResource = Get-AzureADMSPrivilegedResource -ProviderId AzureResources -Filter "DisplayName eq 'NetworkWatcherRG'"

Get-AzureADMSPrivilegedRoleAssignment –ProviderId AzureResources –ResourceId $myResource.Id

So this returns a list of role assignments for the specified resource, each assignment has its own id, as well as the ResourceId, the RoleDefinitionId (which role that has been assigned, like reader, contributor, owner, etc), SubjectId (which user, service principal, group, etc has been assigned the role). In addition we can get info on any linked eligible assignements, start and end time for assignements, assignment state and if the assignment is active or not, or if the type is inherited or assigned directly to the resource.

image

The same results can be retrieved by first querying for the resource id:

And then querying for the role assignments belonging to this resource:

Basically the above command returns the same as this blade in the Azure Portal:

image

Examples of Exploring Role Assignments for Azure AD roles

If i want to look at Role Assignments for Azure AD roles via PowerShell you would specify ProviderId as aadRoles and the ResourceId to be the tenant id:

$myTenant = Get-TenantDetailsFromGraph
Get-AzureADMSPrivilegedRoleAssignment -ProviderId aadRoles -ResourceId $myTenant.TenantId

This will return all Azure AD role assignments in your tenant:

To return fewer results we can use the –Filter parameter which support Odata query. I have tried some different combinations, here are some examples of working filters:

Get-AzureADMSPrivilegedRoleAssignment -ProviderId aadRoles -ResourceId $myTenant.TenantId -Filter "SubjectId eq '<myId>'"

Get-AzureADMSPrivilegedRoleAssignment -ProviderId aadRoles -ResourceId $myTenant.TenantId -Filter "RoleDefinitionId eq '<myRoleDefinitionId>'"

Get-AzureADMSPrivilegedRoleAssignment -ProviderId aadRoles -ResourceId $myTenant.TenantId -Filter "AssignmentState eq 'Eligible'"

Get-AzureADMSPrivilegedRoleAssignment -ProviderId aadRoles -ResourceId $myTenant.TenantId -Filter "AssignmentState eq 'Active'"

Using Graph API I can explore and list the role assignments using the same filter examples like with PowerShell above:

Now that we have control over role assignments, we can look into the role definitions and settings in the next part.

Explore and Manage Role Definitions and Settings

image.png

The following commands can be used to get and manage role definitions and settings for Azure Resources:

  • Get-AzureADMSPrivilegedRoleDefinition -ProviderId AzureResources -ResourceId <myResourceId>
  • Get-AzureADMSPrivilegedRoleSetting -ProviderId AzureResources -Filter “ResourceId eq ‘<myResourceId> and RoleDefinitionId eq ‘myRoleDefinitionId””
  • Set-AzureADMSPrivilegedRoleSetting -ProviderId AzureResources -Id ‘<myRoleSettingsId>’ -ResourceId ‘<myResourceId>’ -RoleDefinitionId ‘<myRoleDefinitionId>’ -UserMemberSettings -UserEligibleSettings -AdminMemberSettings -AdminEligibleSettings <Microsoft.Open.MSGraph.Model.AzureADMSPrivilegedRuleSetting>

And following commands can be used to get and manage role definitions and settings for Azure AD roles:

  • Get-AzureADMSPrivilegedRoleDefinition -ProviderId aadRoles -ResourceId <TenantId>
  • Get-AzureADMSPrivilegedRoleSetting -ProviderId aadRoles -Filter “ResourceId eq ‘<TenantId>'”
  • Set-AzureADMSPrivilegedRoleSetting -ProviderId aadRoles -Id ‘<myRoleSettingsId>’ -ResourceId ‘<TenantId>’ -RoleDefinitionId ‘<myRoleDefinitionId>’ -UserMemberSettings -UserEligibleSettings -AdminMemberSettings -AdminEligibleSettings <Microsoft.Open.MSGraph.Model.AzureADMSPrivilegedRuleSetting>
g-raph

The equivalent Microsoft Graph API methods for Azure Resources:

  • GET /privilegedAccess/azureResources/resources/{resourceId}/roleDefinitions
  • GET /privilegedAccess/azureResources/roleDefinitions?$filter=resourceId+eq+'{resourceId}’
  • GET /privilegedAccess/azureResources/resources/{resourceId}/roleDefinitions/{id}
  • GET /privilegedAccess/azureResources/roleDefinitions/{id}?$filter=resourceId+eq+'{resourceId}’
  • GET /privilegedAccess/azureResources/resources/<resourceId>/roleSettings
  • GET /privilegedAccess/azureResources/roleSettings?$filter=resourceId+eq+'<resourceId>’
  • GET /privilegedAccess/azureResources/roleSettings/{id}
  • PATCH /privilegedAccess/azureResources/roleSettings/{id}

Explore and Manage Role Assignment Requests

image.png

The following command can be used for exploring and managing role assignment requests:

  • Get-AzureADMSPrivilegedRoleAssignmentRequest. Get role assignment request for a specific resource.
  • Open-AzureADMSPrivilegedRoleAssignmentRequest. Create a role assignment
    request.
  • Set-AzureADMSPrivilegedRoleAssignmentRequest. Update a role assignment
    request.
  • Close-AzureADMSPrivilegedRoleAssignmentRequest. Cancel a
    AzureADMSPrivilegedRoleAssignmentRequest.
g-raph

The equivalent Microsoft Graph API methods:

  • GET /privilegedAccess/azureResources/resources/{resourceId}/roleAssignmentRequests
  • GET /privilegedAccess/azureResources/roleAssignmentRequests?$filter=resourceId+eq+'{resourceId}’
  • GET /privilegedAccess/azureResources/roleAssignmentRequests?$filter=subjectId+eq+'{myId}’
  • GET /privilegedAccess/azureResources/roleAssignmentRequests/{id}
  • POST /privilegedAccess/azureResources/roleAssignmentRequests
  • POST /privilegedAccess/azureResources/roleAssignmentRequests/{id}/updateRequest
  • POST /privilegedAccess/azureResources/roleAssignmentRequests/{id}/cancel

Exporting and Importing PowerApps and Flows Package that use a Custom Connector

Just recently I published a blog post on how to use PowerApps and Flow with a custom connector using Microsoft Graph API, to create an app for Azure AD PIM (Privileged Identity Management): https://gotoguy.blog/2018/09/15/create-your-own-azure-ad-pim-app-with-powerapps-and-flow-using-microsoft-graph/.

In this blog post I want to share some instructions and experiences on exporting the PowerApp and Flows to a package, and how you can export the Custom Connector definitions to a swagger file. After that I will show how you in a new environment can import these definitions, and import the PowerApp and Flow package.

Even better, based on the aforementioned blog post on the Azure AD PIM App, I will provide you with download links for the custom connector swagger defininiton for Microsoft Graph, as well as the PowerApp and Flows Package, so you can start from there without having to build all the stuff yourselves Smile!

Export the PowerApps Package

First, start in your Apps gallery of PowerApps, find the Export package (preview) button as shown below:

image

Specify a package name, environment and optionally a description as I have below:

image

Next, review the package content. For the Azure AD PIM App, I’ll change the Import Setup to “Create as new”, the same for the 3 Flows, as shown below:

image

For some of the resources you can select between Create as new or Update, and as I’m planning to import this as a new App with new Flows in the environment, I’ll change this from the default.

image

The other resources (like the connector and connections) I will select during import. This means these will have to be already existing in the environment I want to import the package to.

I can then download the package:

SNAGHTML9abd28

The package is downloaded as a zip file:

image

Inside the zip file there are some manifest json files and the PowerApps and Flows definitions:

image

Export the Custom Connector swagger file

The next thing we want to do is to export the custom connector and its operations. Go to Custom connectors in the menu:

image

Find the “PowerApps Microsoft Graph” connector, and click on the down arrow as shown below. This will download a swagger definition file in JSON format:

SNAGHTMLb16f76

You can open and inspect that JSON file in your favorite JSON editor, here is mine shown in Visual Studio Code:

image

Community Download

Courtesy of gotoguy.blog, I’ll provide you with a download for both the PowerApps/Flows package, as well as the Custom Connector Swagger JSON file. This is helpful if you want to skip right ahead to the next Import section.

These files are placed at my GitHub, in the following repositories:

Import the Custom Connector swagger file

In the new/target environment we will first have to import the swagger file for the Custom Connector. Here you have 2 options:

  1. You can create a new custom connector, and Import from an OpenAPI file/URL:

    image

  2. Or, if you already have a Custom Connector for Microsoft Graph, you can select to Update the existing connector from OpenAPI file/URL:

    image

For sake of education, lets try both variants. The first time you will have to create a new custom connector anyway, but later you will only need to update if there are any changes. I will use OpenAPI URL, as the swagger file is avaiable at my GitHub here: https://raw.githubusercontent.com/skillriver/PowerAppsFlowCustomConnector/master/MicrosoftGraphApi/PowerApps-Microsoft-Graph.swagger.json

PS! Prerequisite

Remember that to be able to use a Custom Connector and Microsoft Graph, you will have to create or use an App Registration in Azure AD in your target enviroment, like I have described in this blog article, under the section “App Registration”: https://gotoguy.blog/2017/12/17/access-microsoft-graph-api-using-custom-connector-in-powerapps-and-flows/.

Take a note of the application ID and secret key:

image

Remember also to give the App the right Microsoft Graph Permissions, and give Admin grant if needed:

image

Import from OpenAPI URL

To create a new custom connector, select to import from OpenAPI URL:

  1. Type a name for the Custom connector, and paste in the URL for the swagger json file:

    image

    Verify the URL and click Continue.

  2. Following that, verify that host is graph.microsoft.com and base URL is “/”, and optionally specify a connector icon, color and description:

    image

  3. On the security page you have to specify the client id which is the app id from the registered app in your target Azure AD environment, as well as client secret and resource URL:

    image
    In my target environment I have pasted in the client id, secret, and the resource URL is https://graph.microsoft.com. Note that the Redirect URL is not available before after the custom connector is saved:

    image

    Click to go to the next Definition page.

  4. At the Definition page, the actions are already in place because they were defined in the OpenAPI swagger file:

    image

    Click “Create connector”.

  5. After the Connector is created and saved, go back to Security, and copy the Redirect URL:

    image

  6. Make sure that the Redirect URL is on the list of the Reply URLs of the Azure AD App Registration:

    image

  7. Back in the Custom Connector, lets test the connector. Go to the Test page and create a connection:

    image

  8. After establishing a connection with your user account, you can go ahead and test one or more of the operations and verify that they run successfully:

    image

After testing this the custom connector is ready to use.

Update from OpenAPI URL

I you want to update an existing custom connector, select to Update from OpenAPI URL:

  1. Provide the URL for the swagger json file:

    image

  2. As with when creating a new custom connector, verify that host is graph.microsoft.com and base URL is “/”, and optionally specify a connector icon, color and description:

    image

  3. When updating an existing connector, you only have to specify the client secret again:

    image

    If you don’t have the original secret stored securely somewhere, you have to go to the App Registration in Azure AD and generate a new one.

  4. Verify that the Operations now has been updated from the imported OpenAPI swagger json file:

    image

    Click Update Connector to save the changes.

  5. After this, go to Test, and either use an existing connection or create a new, and the Test some of the operations to verify:

    image

Now we are ready import the PowerApp and the Flows that will use this custom connector.

Import the PowerApps and Flows Package

We can now import the package we exported earlier, or if you want to use the community download from my GitHub repository, make sure that you download the zip package before this next step.

Start by selecting Import package (preview) from the PowerApps menu:

image

Then browse to the zip packaged to start uploading:

image

When the upload is complete, we can review the package content. We have to select during import the connector and connections, marked as red under here:

image

After selecting the custom connector, and changing the connections to the target environment, we are ready to Import:

image

Note that you also can change the name of the PowerApp and Flows by clicking on the wrench symbol.

Click Import when you are ready, and verify that the import is successful:

image

You can now proceed to open the app for customizations and testing. If prompted, click to Allow the permission request:

image

After opening the Azure AD PIM App, now in the target environment, hold down the ALT key and click Refresh My Roles to test. And you should get the logged on users roles:

image

Obviously, now in the target environment, you would probably start to customize the logo, colors, label texts and language, if you don’t want to proceed with the “Elven” theme 😉

For example something like this from my company:

image

With that I can conclude this blog post, we have been able to export the custom connector definition and the PowerApps package including the Flows, and import these into a new environment. Now all that is left is to publish and share the PowerApp to be used in your organization.

Thanks for reading, hope it has been helpful!

Create your own Azure AD PIM App with PowerApps and Flow using Microsoft Graph

A while back I wrote a blog post on how you could access Microsoft Graph API using a custom connector in PowerApps and Flows: https://gotoguy.blog/2017/12/17/access-microsoft-graph-api-using-custom-connector-in-powerapps-and-flows/.

In this blog article I will build on that blog post to provide a practical example of using Microsoft Graph, and create an Azure AD PIM (Privileged Identity Management) App for activating any eligible admin roles for the logged on user.

First lets look into some of the documentation and what we need to prepare.

Microsoft Graph API for Azure AD PIM

Azure AD Privileged Identity Management provides you a way to enable on-demand time limited access for administrative roles. Microsoft Graph API for Azure AD PIM is currently available under the Beta endpoint, and documented here: https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/resources/privilegedidentitymanagement_root.

If a user that has been assigned admin roles using Azure AD PIM, wants to activate any of the eligible role assignments, the user can navigate to the Azure AD PIM blade or just use this short url: https://aka.ms/myroles. In this blog post I will use my demo user account as an example, and this user has these roles assigned currently:

image

If I want to access my roles using Graph API I can use the privilegedRoleAssignment: my method (https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/privilegedroleassignment_my).

Let’s try to do that using the Graph Explorer! (https://aka.ms/GE). Make sure you are signed in using your work account (normal user account), as I have in the screenshot below, and the run the GET command as shown below (https://graph.microsoft.com/beta/privilegedRoleAssignments/my):

SNAGHTML1778e65

In my case this returns the following (I have blurred out my userid for privacy):

image

Note that the response also shows if I have a current activation of any roles, and if so when that will expire. Roles that have isElevated set to “true”, and without an expirationDateTime are roles that are permanently assigned. If I want to query on that I can run the following GET command:

image

When my role assignments are returned I only get roleId’s though, so lets look at how I can get the displaynames of those roles.

For example, I see from the response above that one of the roleId’s returned is 29232cdf-9323-42fd-ade2-1d097af3e4de. In the Graph API for Azure AD PIM there is a method to list privilegedRoles (https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/privilegedrole_list), so if I run the following in Graph Explorer: https://graph.microsoft.com/beta/privilegedroles/29232cdf-9323-42fd-ade2-1d097af3e4de, I should get more role information right?

No, I don’t have permission to do that:

image

Lets look at the documentation, and it clearly states that for the requestor (my normal user account) to be able to list privilegedRoles I need to be either a Global Administrator, PIM Administrator, Security Administrator or Security Reader:

image

So that won’t work for me, as I want to let normal user accounts to be able to use my Graph API commands.

However, one thing that normal users do have access to, is listing of directoryRoles (https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/directoryrole_list). So if I run that, I will get all directory roles with their id and a roleTemplateId, and I have highlighted below the id I was looking for above, which turns out to be the Exchange Administrator role:

image

So, to get the displayName of the role I can run the following GET request: https://graph.microsoft.com/beta/directoryroles/?$filter=roleTemplateId eq ‘29232cdf-9323-42fd-ade2-1d097af3e4de’:

image

Ok, so now I have a way to query for my role assignments, and also a way to query for the display names of any roles. Now I need to see how I can activate (or deactivate) my role assignments.

I will use these methods: privilegedRole: selfActivate and privilegedRole: selfDeactivate, they are documented at https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/privilegedrole_selfactivate / https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/privilegedrole_selfdeactivate.

When I do a POST /privilegedRoles/{id}/selfActivate, I need to specify the role id in the request uri and and a request body:

{
  "reason": "reason-value",
  "duration": "duration-value",
  "ticketNumber": "ticketNumber-value",
  "ticketSystem": "ticketSystem-value"
}

For example I can try to activate the Exchange Administrator role by POST to: https://graph.microsoft.com/beta/privilegedRoles/5cfc2572-33b1-4839-8774-2bae31da1a29/selfActivate, and specify a request body like shown below. Note that all properties in the request body are optional, I can just leave them blank or provide default values:

image

Currently there is an error in the Graph Beta API for PIM that won’t let me activate roles that require MFA, so I’ll just accept this error and move on for now:

image

Before I deactivate a role I need to have it to be active, so for now I will go to https://aka.ms/myroles, and activate the Exchange Administrator role manually, promptly requiring MFA verification first:

image

And after that I can activate the role:

image

To deactivate the Exchange Administrator role via Graph API I’ll just do a POST to /privilegedRoles/{id}/selfDeactivate, specifying the role id like this: https://graph.microsoft.com/beta/privilegedRoles/29232cdf-9323-42fd-ade2-1d097af3e4de/selfDeactivate

No request body is needed, and this time I get a successful response:

image

I think these 4 methods will do for now, there are a lot of other methods for managing PIM roles and settings as well, but we are now ready to start working with our PowerApps and Flow Custom Connector.

Add Microsoft Graph Permissions to App Registration

As I mentioned in the beginning of this blog post, I previously wrote a blog post on how to set up an App Registration for a custom connector for PowerApps and Flows. I will now build on this, so if you want to follow the steps I do here, please set up the prerequisites as described in the blog post: https://gotoguy.blog/2017/12/17/access-microsoft-graph-api-using-custom-connector-in-powerapps-and-flows/.

Looking at the documentation I see that I need to add Delegated Permissions for Directory.AccessAsUser.All to be able to list my assignments:

image

Similarly, if I check the documentation for the other methods from above,  I will need also Directory.AccessAsUser.All:

image

image

image

So I will go ahead and add that permission to my App Registration from before. Logged in as a Global Admin find the App Registration, go to Settings and Permissions, and add the following delegated permission for Microsoft Graph:

image

Note that it requires an admin to consent, so remember to click on Grant permissions:

image

Now we are ready to add the PIM API methods to the Custom Connector.

Adding PIM API’s to Custom Connector Operations

Again building on my linked blog post, you should now be able to log on to PowerApps, and find your PowerApps Microsoft Graph connector:

image

If you don’t have it, just follow the steps in the linked post to create it.

Select to edit, and go to step 3. Definition and add a new action. Lets first create a new action for getting my role assignments:

image

Scroll down to Request, this is where we will provide the details for our query. The best way to do this is to select to Import from sample. I specify the Method to be GET, and then the query like this, which is the same query I ran in the Graph Explorer earlier:

image

I don’t need to specify any Header or Body for this query, so I just press Import. Now my action looks like this:

image

Scroll down to the Response section, and then click on the default response. Click on Import from sample, and this time you paste in the response body from the previous Graph Explorer query:

image

This response will help the custom connector operation so that we can get the right output values mapped in our PowerApp later. Select Import.

The response now looks like this:

image

We can also validate that the response looks ok:

image

Click on Update connector to save this operation, do not select to Test at this point. We have more to do..

Next I want to create another action for List directoryRoles. I’ll create a new Action:

image

Request and Import from sample:

image

Note that the Request now will have a $filter parameter:

image

Default Response and Import from sample:

image

Check validation and the Update Connector:

image

Next I want to create another action for

privilegedRole: selfActivate. I’ll create a new Action:

image

Request and Import from sample, this time note the POST verb, and specifying {id} in URL, as well as the request body as shown below:

image

Note now that the request will have an id parameter in the path as well as a body parameter:

image

Default Response and Import from sample (response body is copied from documentation):

image

The response looks like this now and we can check validation:

image

Click Update Connector to save our progress so far. Now we can add the last action for privilegedRole: selfDeactivate :

image

Request and Import from sample, specifying verb POST and again using {id} in URL:

image

The request will look like this now:

image

Default Response and Import from sample:

image

And we can validate the response:

image

Click on Update Connector to save. We should now have 4 actions successfully configured, in addition to the ones we had from before:

image

Now we can do some testing, close the connector for now. Under Data, find Connections. If you previously had any connections to the “PowerApps Microsoft Graph” connector, like I have here, delete the connection:

image

After clearing any existing connections, select New connection at the top and find the PowerApps Microsoft Graph connector:

image

Click create and the log in with your current user to create the connection. Now you can go back to the custom connector, click Edit and then go to Test section. Select the current connection, and select the action to test. Then click Test operation:

image

The test should complete successfully and return my role assignments:

image

Lets test the list directory roles, this time I need to specify the $filter:

image

Testing selfActivate will fail as it did with testing with Graph Explorer because of the MFA requirement: (we will explore that later)

image

image

Last test is for selfDeactivate, which willl have an empty response because the role is not active:

image

Starting with the PowerApp

Now that we have the Custom Connector Operations ready, we can proceed to create the PowerApp. We’ll begin with an empty app, create some controls and layouts before we get into the Flows needed.

Start by Create an app:

image

Then select a blank canvas, and phone layout:

image

You should now have an empty app like this:

image

Fast forward, and I’ll assume you have some basic PowerApps skills, add some controls, layout and image after your liking, ending up with something similar like this:

image

A quick summary of the above:

  • In addition to my selected logo and background, I’ve added labels for listing my roles and selected role details.
  • I’ve added three buttons, one for refreshing my roles, and one for activate and deactivate any roles.
  • I also have a text box to provide an activation reason, as well as a message label to show/hide any error message if I try to activate without a reason. We’ll get to that later.

Now we have an empty powerapp with some layouts and controls. It’s time to get into the Flows that will trigger the Microsoft Graph operations. First go to App Settings and specify an App name and choose a descriptive icon and color:

image

And then save the App:

image

Creating the Flow for Getting My Role Assignments

In the PowerApps main menu, find the link to Flows, and the select to create a Flow from blank:

image

After creating a blank Flow from here there will already be a step for input from PowerApps as shown below:

image

Click New step, add an action, and search for variables, and select the Variables – Initialize variable action:

image

Type the name MyRolesArray and select Type Array:

image

Add a new step of type action, and this time we will search for the custom connector “powerapps microsoft graph”, and that will list any operations we defined earlier. We will now select the operation for “My Privileged Role Assignments”:

image

Our Flow should look like this now:

image

When we tested via Graph Explorer earlier in this blog post, PIM role assignments returned with only role id’s, so we had to do an additional call to list directoryroles to get the displaynames of the roles. We will now implement some logic in the Flow to achieve this.

Add a new step, this time selecting More and Add an apply to each:

image

In the Apply to each, select “value” as output from the previous step as shown below:

image

It’s also a good idea to rename the step, like I have done below before you proceed:

image

Inside the For Each loop, add a new action, searching for the PowerApps Microsoft Graph connector again, this time selecting the List directoryRoles operation:

image

We need to provide a value for the $filter parameter, this is done by typing the filter definition and selecting the roleId from the dynamic content provided by previous step:

image

I also rename the step before I proceed:

image

Next, add another Apply to each section, using the value output from the List directoryRoles to get DisplayName:

image

Next add an action and search for append to array, and select that:

image

Now comes the most important part. I want to use the array variable I initialized in the beginning of the Flow, and build a custom JSON object array which integrates my role assignments as well as the displaynames in one single output. So in the following I select the array variable name, and for value I create my own custom JSON as shown below. In addition I use the dynamic content to search for the values I want to add:

image

At the end of the Flow, outside of the two nested Apply to each loops, add a Request – Response action:

image

In the Response, specify the MyRolesArray as Body, and provide a Response Body JSON Schema. The best way to get a JSON schema is to Save and Test the Flow, and look at the default Response. This is how it looks in my definition:

image

This is the JSON schema I used:

{
"type": "array",
"items": {
"type": "object",
"properties": {
"roleId": {
"type": "string"
},
"displayName": {
"type": "string"
},
"isElevated": {
"type": "boolean"
},
"expirationDateTime": {
"type": "string"
}
},
"required": [
"roleId",
"displayName",
"isElevated",
"expirationDateTime"
]
}
}

Next, Save and Test the Flow. Look for the Test button, and select like below:

image

Follow the on-screen instructions for choosing test connection, and then start the Flow. Click the link to see the Flow run activity, and you should be able to see that the Flow executed successfully and you can look at the details on each step. I’m mostly interested in the Response output at the end, and it looks like this:

image

If I scroll down I can see that the output contains all my roles, and have the display name included in the output. This is the output I eventually will work with in my PowerApp.

Remember to give the Flow a describing name, and Save it before you proceed to the next section.

image

Creating the Flows for Self Activate and Deactivate Roles

Now we need to create the Flows for self activating and deactivating the selected roles. First start by creating a new blank Flow, starting with the input from PowerApps:

image

Add a new step and action for the Microsoft PowerApps Graph connector and the Privileged Role Self Activate operation:

image

When choosing this operation we will get the opportunity to specify input fields, where id is required, as this is the role id for the role we want to activate. In addition we can specify a reason, as well as duration and ticketing info as optional fields:

image

In my solution I want to specify id and reason, and just use the default duration. For the id field and reason field, just click “Ask in PowerApps”, which will create two parameters to use from PowerApps when I will call the flow:

image

In the third step I will add a Request – Response action, and use the Body from the previous step, like this:

image

Save the Flow with a name like I have done below:

image

Then its a good idea to test the Flow, select the test button, provide the trigger for the flow, and when running we need to manually specify the role id to activate, and a reason, like shown below:

(PS! Remember to test with a role that does not require MFA on elevation, because of the previously reported bug.)

image

After clickin Run Now, verify that the Flow successfully started, and then click into the activity details. In the example below I can verify that indeed the role was activated:

image

So that is the Flow for self activating a role, now we need a similar Flow for deactivating a role. Now that we should start getting the hang of this, this is how that Flow should look after creating and saving it:

image

Deactivating a role only requires the role id as a parameter, as shown above. Lets test this as well:

image

The Flow should start successfully, and you can verify the steps like in the following:

image

So, now we have created 3 Flows that we will use in the previously created PowerApp. In the next section we will add the flows and provide some logic to the application.

Connecting the PowerApp to the Flows

Back in the PowerApp created earlier, open it in Edit mode, and select the Refresh My Roles button. Click on the Action menu, and then on Flows, and from the Data section select the Flow we created earlier for Get My Role Assignments:

image

When selecting that Flow, the OnSelect event will populate with the name of the Flow and the Run method. As this Flow doesn’t have any input arguments we can just close the parenthis after like this .Run(), as shown below:

image

So now our button will get any role assignments for the connected user, but we have store the output we get back from the Flow, and use that in the listbox and in the details labels below. So while the Refresh My Roles is still selected, add the following to the OnSelect event:

Set(wait,true);
ClearCollect(MyPIMRoles,GetMyRoleAssignments.Run());
Set(wait,!true)

Like this:

image

A little explanation, the Set(wait,true) and Set(wait,!true) are used at the beginning and end of the action for indicating that the PowerApp is busy when calling the Flow. The ClearCollect is used to store the output response we get back from the Flow in a variable; MyPIMRoles.

Next, set the Items property of the listbox for My Roles to MyPIMRoles:

image

If we now du a test run of the PowerApp, the easiest way to do that is to hold the ALT button down and then click on the Refresh My Roles button. This should return the roles you are assigned to like this:

image

If your listbox is not showing the displayname of the roles, you can change that from the advanced properties of the listbox:

image

While the listbox i still selected, change to the OnSelect method and add the following:

Set(SelectedRole,First(lstMyRoles.SelectedItems))

It should look like this:

image

A quick explanation of this: I’m setting a variable “SelectedRole”, every time I click on a role in the listbox, by getting the first instance of the lstMyRoles.SelectedItems. (In fact, as my listbox only allows to select one item at a time, the first will always be the one I selected).

This “SelectedRole” variable can now be used in my other label details. First, set the lblRoleIdValue.Text property to the following:

image

Likewise, set the lblRoleElevatedValue.Text property to the following:

image

And then set the lblRoleExpiresValue.Text property to: Text(DateTimeValue(SelectedRole.expirationDateTime), DateTimeFormat.ShortDateTime24), like this:

image

As you can see, I’ve added some format functions to display any date and time values from the selected role in the format of short datetime 24 hour clock.

Now, if you hold down the ALT button again, you can click on the selected roles in the listbox, and the labels below will update with the selected role id, if it is elevated or not, and any expiry of existing elevations:

AzureADPIMApp1

Now it’s time to add the other Flows to the Activate and Deactivate buttons, first select the Activate button, and on the Action and Flow menu, select to add the Priviliged Role Self Activate Flow:

image

This Flow needs two inputs:

image

The first input we will get from SelectedRole.roleId, and the second from the txtActivationReason.Text, so it would look like this:

image

Similarly, add the Flow for the Deactivate button, specifying the SelectedRole.roleId as input:

image

Now, at this point we should be able to get my role assignments in the list box, and also to be able to activate or deactivate the selected roles. I do want to add some more logic to the app though. Starting with activating/deactivating the buttons regarding the status of the role. On the Activate button, change the DisplayMode property to:

If(!SelectedRole.isElevated, DisplayMode.Edit, DisplayMode.Disabled)

Like this:

image

And similarly for the DisplayMode property for the Deactivate button:

If(SelectedRole.isElevated, DisplayMode.Edit, DisplayMode.Disabled)

image

Next, I want to add some hint text to the text box for activation reason, this is done this way:

image

At the bottom I have created a label with a message, this lblShowMessage control I want to set visible if I try to activate a role without specifying a reason:

image

Now I need to make some changes to the Activate button and OnSelect method to implement some logic:

image

Lets break that down: First I use the Set method to control wait to indicate that the App is busy, then I do an If check on the txtActivationReason text box, and if I have specified a reason I proceed to run the Flow to self activate the role. After that I clear the txtActivationReason text box, and call the flow for refresh the roles in the list box. At the end I use a ShowMessage variable, setting it to true or false, which in turn is connected to the Visible property of the lblShowMessage control like this:

image

Here is the Activate button OnSelect code for you to copy:

Set(wait,true);
If(!IsBlank(txtActivationReason.Text),
PrivilegedRoleSelfActivate.Run(SelectedRole.roleId,txtActivationReason.Text);
Reset(txtActivationReason);
ClearCollect(MyPIMRoles,GetMyRoleAssignments.Run());
Set(wait,!true),
UpdateContext({ShowMessage: true});
UpdateContext({ShowMessage: false}))

And for the Deactivate button I change the OnSelect to:

image

I don’t need to check the txtActivationReason text box now, so I’ll just clear it and refresh the roles. Here is the code:

Set(wait,true);
PrivilegedRoleSelfDeactivate.Run(SelectedRole.roleId);
Reset(txtActivationReason);
ClearCollect(MyPIMRoles,GetMyRoleAssignments.Run());
Set(wait,!true)

I’ll also add a reset of the activation reason text box to the Refresh My Roles button:

image

And finally, at the OnSelect method of the lstMyRoles listbox, I’ll set the ShowMessage variable to false whenever I click on different roles in the list, so that any previous activation error message is not shown.

image

That should be it! We’ve now implemented some logic to the PowerApp, and are ready to publish and run the App.

Publish and Run the Azure AD PIM App

On the File menu click Save, and the Publish:

image

You can also Share the PowerApp in your organization:

image

(please see my previous blog post https://gotoguy.blog/2017/12/17/access-microsoft-graph-api-using-custom-connector-in-powerapps-and-flows/, and the sharing section at the end for details on the experience on this).

After you have published the PowerApp, you can click the Play button to run the PowerApp. First time you will need to accept permission:

image

After that you should be able to refresh your roles:

image

Let’s try to activate a role:

image

After I click the Activate button, the role will be activated, the list will be refreshed, and I can look at the Device Administrators role that it is now elevated and with an expiry time:

image

The Activate button is now disabled for that role, and the Deactivate button is enabled. Let’s try to deactivate the role again, clicking the Deactivate button. After a short time the role is deactivated, elevation status is false:

image

So now the Azure AD PIM App is working as intended, every user that have been assigned a role can now elevate themselves using the App. Even better is that my users also now can use the mobile PowerApps app to run this from their mobile phones!

As an administrator I can also see the results of the activations in the Directory roles audit history:

image

Known issues and tips

The biggest issue right now is a problem with the Microsoft Graph beta endpoint for selfactivate the role, as it currently does not support activating roles that require MFA. So I you want to use Microsoft Graph for activating roles now, you have to disable the requirement of requiring MFA for activation, either by default for all roles or for roles individually:

image

I’ll keep you posted of any changes to this issue, and update the blog post if that changes.

Another tip is that if you want to do some reporting on how many users are using the PowerApp for activating their PIM roles, you can for example use the ticketSystem string for specifying a constant like below:

image

That should wrap up this blog post, hope this will be useful for you, thanks for reading Smile

Getting started with Azure AD PIM PowerShell Module

This is a short blog post showing how you can get started and some examples of using the PIM PowerShell Module for Azure AD Privileged Identity Management.

You can read more about Azure AD Privileged Identity Management here: https://docs.microsoft.com/en-us/azure/active-directory/active-directory-privileged-identity-management-configure, or by just using the following short URL: https://aka.ms/AzureADPIM!

Installing the Azure AD PIM PowerShell Module

Since there are no PIM related commands in the AzureAD or AzureADPreview PowerShell Modules, we will have to install a separate module for PIM. You can find this module at the PowerShell Gallery here: https://www.powershellgallery.com/packages/Microsoft.Azure.ActiveDirectory.PIM.PSModule

To install the module just run the following command in an elevated PowerShell session:

Install-Module Microsoft.Azure.ActiveDirectory.PIM.PSModule
image

After installing you can list the available commands in the PIM module:

Get-Command -Module Microsoft.Azure.ActiveDirectory.PIM.PSModule
image

Here is a short explanation of the available commands:

  • Connect-PimService. Prompts you to log on with an Azure AD Account that might have any PIM roles assigned. You can optionally specify a username, tenantname or credential object as parameters. Especially tenantname would be useful if you are a guest user with roles assigned in another tenant.
  • Show-PimServiceConnection. This will show the active PimService session details you have, after connecting with Connect-PimService.
  • Get-PrivilegedRoleAssignment. This would list any permanent or eligible role assignments the user you connected with using Connect-PimService has.
  • Enable-PrivilegedRoleAssignment. This command will enable a specified role assignments. It is required to specify which role either by RoleId or by a RoleAssignment variable. It is also required to specify a Duration for activation. Optional parameters includes Reason, TicketNumber, TicketSystem and StartTimeUtc.
  • Disable-PrivilegedRoleAssignment. If you previously have activated one or more roles with Enable-PrivilegedRoleAssignement, you can preemptively deactivate these roles again before the duration expires. You must specify a RoleId or RoleAssignment variable.
  • Disconnect-PimService. Disconnects any previous sessions to PimService.

Examples of Azure AD PIM Commands

In the following I will show some examples of using the Azure AD PIM Module.

Connect-PimService

In the following I’m connecting with a specified username, if it is required to use Azure MFA for this user I will be prompted for that as well:

Connect-PimService –UserName <username>
image
image

After authenticating, PIM service connection details are returned, here slightly masked:

image

The above returned is exactly the same as would be returned by running the command:

Show-PimServiceConnection

Get-PrivilegedRoleAssignment

This command will list any role assignments, permanent or eligible your user might have. Here is a couple of examples for outputs for two different admin users. The first user is eligible for Security Administrator and Privileged Role Administrator, and permanent for Global Administrator:

image

The second admin user is eligible for Exchange Administrator and Global Administrator:

image

If I want to assign a variable to a role assignment, I can do it like the following command:

$roleAssignment = Get-PrivilegedRoleAssignment | Where {$_.RoleName -eq "Privileged Role Administrator"}

I now have a role assignment variable I can use in the following commands.

Enable-PrivilegedRoleAssignment

To enable one of my roles, I need to specify a duration (PS! keep inside the allowed role settings for max duration!), and specify which role either by RoleId or RoleAssignment variable. Optional parameters like Reason etc can also be specified.

Here is a working example:

Enable-PrivilegedRoleAssignment –Duration 1 –RoleAssignment $roleAssignment –Reason “Add crmadmin to CRM Administrators”

After running the command, if successful it will return as a submitted request for activating role membership.

image

By running Get-PrivilegedRoleAssignment again, we can now see that the role of “Privileged Role Administrator” is indeed activated (elevated), and with a ExpirationTime (UTC time):

image

PS! If you have required MFA on activation for the role, one of two things will happen:

  1. If the user already has verified the identity with Azure MFA when authenticating with Connect-PimService, the user will not be asked again. This is the same experience as by using the Azure Portal for activating roles.
  2. If the user hasn’t verified with Azure MFA, the user will be prompted when activating the role, similar to this example:
    image

Disable-PrivilegedRoleAssignment

Any roles you have activated will automatically deactivate after the duration specified has passed. However, if you are finished doing administrative tasks with your role, you can deactivate the role manually.

To deactivate an active assignment, run the following command specifying a RoleId or RoleAssignment variable:

Disable-PrivilegedRoleAssignment –RoleAssignment $roleAssignment
image

Disconnect-PimService

To end your connection to Azure AD PIM Service, run the following command:

Disconnect-PimService

After running that command you can also see that there are no role assignments to list anymore.

image

Hope these commands and examples have been helpful, enjoy working with Azure AD PIM!

How to configure Conditional Access for Azure AD PIM

Azure AD Privileged Identity Management is a really great security feature for controlling those Azure AD and Azure Subscription administrator roles. By implementing Azure AD PIM you can let users with admin roles elevate themselves when they need to, using just in time (JIT) and eligible roles instead of permanent admin roles. You can even implement approval workflows and audit trails, so if you haven’t looked into it you should really take a look!

With Azure AD PIM you can require Azure MFA when activating admin roles, but outside that you cannot set conditions and access control scenarios like you can do with Azure AD Conditional Access.

But now recently there is a new option in public preview for assignments to users and groups for Conditional Access policies, you can assign the CA policy to directory roles!

image

So I was wondering how this would work together with Azure AD Privileged Identity Management, for example in the following scenario:

I have an Exchange Administrator that from time to time performs Exchange Online admin tasks, and have configured this admin user with Azure AD PIM and eligible for Exchange Administrator Role among others:

image

Lets say that I only want this user to perfom Exchange Administrator tasks from a Compliant Device. Even though the Azure AD PIM role is protected by MFA at activation, making the user secure and trusted, I really want the device he is using to be secure and compliant with any management profiles I have defined using Intune MDM. Especially when he is doing admin stuff in our Exchange Online tenant or even running some Exchange Online PowerShell commands.

Lets set up this scenario.

Creating Azure AD Conditional Access Policy for Directory Role

The first thing I set up is the CA policy for my specific Directory Role in this scenario. I specify a name and then select the Directory role of Exchange administrator as shown below:

image

Next for Cloud apps I select Exchange Online:

image

For Access controls I select to require the device to marked as compliant:

image

After that I enable the policy and save. We are now ready to test the user experience.

Testing Azure AD PIM Role Activation and Conditional Access

So now we can test the scenario. Remember that the idea is that the CA policy only will kick in when the user has activated his Azure AD PIM role assignment as Exchange Administrator.

PS! If this user also has a Exchange Online license and mailbox, the same CA policy will apply and require the device to be compliant as long as the Exchange Administrator role is active. That could pose some not intended side effects, requiring the devices that access Exchange Online for normal mailbox access to be compliant as well, but as long as the Exchange Online Admin isn’t available as a Cloud app in Conditional Access we have to do it this way.

With my admin user, I first go to http://aka.ms/myroles, which will redirect me to my roles defined in Azure AD PIM. Lets sign in first:

image

And here is my eligible roles:

image

I select the action link to activate my Exchange Administrator role, and then to verify my identity with Azure MFA:

image

After verifying I can specify a reason or adjust the activation duration:

image

After that I’m activated and has an access valid for the set period of time:

image

Now, let’s go to to the Exchange Online Admin portal: https://outlook.office365.com/ecp. After signing in, if I’m not already signed in, I will get this message:

image

The details will tell me that the access rules require a compliant device:

image

We could also check using Exchange Online PowerShell module, and I get the same message:

image

Note that this message only works with the Connect-EXOPSSession that use Modern Authentication. The “old” way of using remote PowerShell and credential object to Exchange Online use basic (legacy) authentication so we cannot control that information flow, but the admin user will be denied there as well:

ExoPS

To conclude this blog post, I have shown that by combining the new preview feature of Directory Roles assningments for Azure AD Conditional Access, and Azure AD Privileged Identity Management, we can implement more complex scenarios for conditions and access rules for using those directory roles. In my example I used compliant device, but you could also use any other of the conditions and access controls available.