I’ve covered the topic of inventorying Azure AD integrated applications multiple times already, most recently in this article, where we switched to using the Graph API directly. The script remains relevant, as Microsoft is yet to cover application permissions in their OAuth inventory (part of Defender for Cloud apps/MCAS), and only offer this as part of the new App governance SKU, and add-on to the already expensive MCAS.
Another similar scenario that you’d likely want to address is to inventory all the first-party applications, or the app registrations for your tenant. Those are represented by an application object within Azure AD, and have most of the same properties as the service principal objects. There are however few differences, and important ones at that. As you “own” the application object, you are in charge of defining permissions (AppRoles and Scopes) as well as API integrations for it. And, you are also in charge of managing the credentials for the application. Last but not least, you can have the application verified or certified by Microsoft. Those are all details that the new, Azure AD app registration inventory script covers. Let’s dig into the details a bit.
First and foremost, the script will again use Graph API calls directly, which in turn means that you have to take care of authentication. The example I’ve used within the script leverages application permissions (client secret) and expects you to have an app prepared, with Directory.Read.All permissions granted. Make sure to fill in the relevant details on lines 67-79, or feel free to replace the whole connectivity block with your own preferred method.
Once authentication has been taken care of and valid token is obtained, the script will proceed with enumerating all the application objects within the organization. It will then iterate over each application to prepare the output object. As simple as that really, a single call against the Graph API is all we need, the rest is just “cosmetics”. Well, to present you with “human readable” values for the permissions (“Roles” and “Scopes”) required by the application, we will have to make few additional calls, one per each “resource”. This is utilized by the parse-AppPermissions helper function, which breaks down the permission entries into “application” and “delegate” ones, and prepares a concatenated string of each. In turn, the Get-ServicePrincipalRoleById function “translates” those pesky GUIDs into values such as “User.Read”.
Lastly, we utilize the parse-Credential function, which takes a look at the key/password credential objects for each application and provides some additional info. Don’t worry, the script does not access the actual values here, they’re not exposed (still, it goes without saying that you should not be blindly running scripts you downloaded from the internet!). It will however report on the number of such credentials configured per app, whether any of them has expired already, and whether their validity is set to over 1 year (365 days, if you want to change the value edit line 55). Those are all good practices to follow in securing access to your applications, and part of the “zero trust” approach.
And that’s pretty much all there is to it, the rest is just handling the output and exporting it to a CSV file. I’d recommend using Excel’s conditional filtering functionality to then highlight entries that need attention, such as those using client secret instead of certificate, expired credentials, those requiring excessive permissions, using deprecated permissions, and so on. Here’s an example:
You can find the script over at my GitHub repo. As usual, comments and suggestions are welcome.