How to get all Graph API permissions required to run selected code using PowerShell
Now that Microsoft Graph API is the main management tool for most of the Microsoft Cloud services, more and more admins will need to be able to work effectively with it.
Graph API can be quite hard to understand, mainly the scope/permission part of it. One thing is to write the correct code and the second is knowing, what permission will you need to run it successfully ๐
Not to mention running some not-very-well-documented 3rd party code.
In this post, I will show you my solution to this problem. And that is my PowerShell function Get-CodeGraphPermissionRequirement
(part of the module MSGraphStuff).
Introduction
Function Get-CodeGraphPermissionRequirement
gets Graph API permissions (scopes) that are needed to run selected code.
Under the hood, it uses my other, more universal function Get-CodeDependency
(part of DependencySearch module) that returns all code dependencies by analyzing its AST and doing some other magic, to search for all commands interacting with the Graph API.
Official Graph SDK commands and direct Graph API calls are both processed ๐
Get-CodeGraphPermissionRequirement
is part of the module MSGraphStuff.
Main features
Supports getting permissions for official Mg* Graph SDK commands
Get-MgUser
,Update-MgDevice
, ...
Supports getting permissions for direct API calls invoked via
Invoke-MsGraphRequest
,Invoke-RestMethod
,Invoke-WebRequest
and their aliasesa.k.a. calling GET, POST, ... requests against
https://graph.microsoft.com/v1.0/users
and suchsupports also usage of variables in place of IDs in the URI
- a.k.a.
v1.0/groups/$groupId/settings
will be correctly recognized and processed
- a.k.a.
Supports recursive search across all code dependencies
- so you can get the complete permissions list not just for the code itself, but for all its dependencies too
Recognizes
v1.0
vsbeta
API calls
Drawbacks
Official command
Find-MgGraphCommand
is used to translate command/URI calls to required permissionsdoesn't contain permissions for all commands/URIs (but this will be hopefully solved in the future)
returns all permissions that can be used, not just the least one (but I am trying to solve this on my own)
URIs passed via parameter splatting or through variables aren't detected right now
- but you will be notified about such issue, so you can solve this manually
The output of the Get-CodeGraphPermissionRequirement
If we send the function results to Out-GridView
to get a graphical representation, we can get results similar to this
As you can see there are several properties returned:
Command - detected command that interacts with Graph API
- official Mg* commands or direct API web requests
Name - name of the Graph permission/scope that the command needs
Description - Graph permission description
FullDescription - Graph permission full description
Type - Graph permission type (application, delegated)
InvokedAs - the original code line where the command was found
- helpful if some command was found multiple times to identify the calls, also in cases where URI cannot be recognized, to find such line and do the manual code analysis
DependencyPath - the whole path to the found command
- useful when using
goDeep
parameter to understand where this command was found
- useful when using
ApiVersion - detected Api version (
v1.0
orbeta
)Method - request method (
GET
,POST
,DELETE
, ...)Error - error message if there was some problem
Use cases
The following examples will be made against this test code
Can be downloaded from GitHub Gist.
Return Graph permissions required by selected code
The following code will return only application
permissions for the selected script.
If there are some indirect dependencies (like calling another function that invokes some Graph API itself), they won't be returned!
Get-CodeGraphPermissionRequirement -scriptPath C:\scripts\someGraphRelatedCode.ps1 -permType "application" | Out-GridView
The result will look like this ๐
Except for two command calls the Get-CodeGraphPermissionRequirement
function resolved all needed permissions for us.
The first problematic one is
Invoke-MgGraphRequest -Method PATCH -Uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies" -Body $body
where the officialFind-MgGraphCommand
function doesn't return anything for this particular URI and PATCH method.The second one is
Invoke-MgGraphRequest -OutputType PSObject -Uri $msGraphPermissionsRequestUri
where instead of plaintext URI is used some variable which is currently not supported by my function.
The last thing that may grab your attention is the missing output for the custom function Remove-O365OrphanedMailbox
. Trust me, this function uses Graph API, but because we haven't specified goDeep
parameter when calling Get-CodeGraphPermissionRequirement
, just the specified code was checked, but none of the used functions/modules. We will look into this in the next example though.
Return ALL Graph permissions required to run selected code (direct and indirect)
The following code will return delegated
and application
permissions for selected script and all its dependencies (used functions/modules)
$availableModules
variable, you can use such a variable in the next Get-CodeGraphPermissionRequirement
calls to speed it up# cache available modules to speed up repeated 'Get-CodeGraphPermissionRequirement' function invocations
$availableModules = @(Get-Module -ListAvailable)
Get-CodeGraphPermissionRequirement -scriptPath C:\scripts\someGraphRelatedCode.ps1 -goDeep -availableModules $availableModules -permType "application", "delegated" | Out-GridView
The result is very similar to the first example.
As you can see there are two differences though.
Delegated
permissions are returned tooA lot of new commands were detected!
If we scroll to the right, we can see in the
DependencyPath
column that all these commands were found in theRemove-O365OrphanedMailbox
function.This function is defined outside the code we've analyzed, but thanks to
goDeep
parameter it was processed too!
Get-CodeGraphPermissionRequirement
to get more details about what is going on under the hoodReturned permission optimization
As I said, my function uses an official Find-MgGraphCommand
under the hood to retrieve command/URI permissions and this function is chatty. It returns more permissions that are needed to be more precise.
For example Get-MgUser
command, do you really think, Directory.ReadWrite.All
or Directory.ReadWrite.All
are needed? I don't think so.
Therefore I remove such permission from the output automatically.
But if you for some reason want to retrieve all these permissions, just use dontFilterPermissions
parameter.
Now that you know how to use this function don't be afraid to test it against your code. Hopefully, this will help you on your Graph API journey ๐
Subscribe to my newsletter
Read articles from Ondrej Sebela directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ondrej Sebela
Ondrej Sebela
I work as System Administrator for more than 10 years now and I love to make my life easier by automating work & personal stuff via PowerShell (even silly things like food recipes list generation).