Creating assignments and software deployment groups for Intune mobile apps is quite a repetitive and manual task. Because of that, I want to share a PowerShell script with you which allows you to automatically create software deployment groups in Azure AD and the assignments for various intents.
The script allows you to:
Create Azure AD groups (install uninstall purpose) Pick existing groups based on displayName Assign Intune mobile apps (tested for Win32 and MSI LOB apps) You can find the script on my techblog GitHub repository.
Because of the configurable group prefixes the script helps you to keep your Intune environment clean and implement a standard app assignment configuration.
The script uses the Microsoft Graph API and the following resources
https://graph.microsoft.com/beta/deviceAppmanagement/mobileApps https://graph.microsoft.com/beta/deviceAppmanagement/mobileApps/{AppID}/Assignments https://graph.microsoft.com/beta/groups It uses the preregistered app “Microsoft Intune PowerShell” which exists by default in all tenants. If you want to run the Script with PowerShell 7 you need to create an adjust the MSAL token section with the -DeviceCode parameter.
You can bulk select the apps you want to create the assignment and AAD deployment groups:
Hope this saves you some time.
Azure functions for PowerShell natively ship without additional cmdlets or PowerShell modules. In this post, I will show you how to add both public modules from the PowerShell gallery with automatic dependency management and custom modules.
For both options, we use the Kudu tools to adjust the configuration of our function app. You can launch them from the “Advanced Tools” section of your function app:
Afterwards, launch the PowerShell debug console and navigate to the wwwroot folder of your app:
Option 1: Automatic dependency management # Note: Installing modules which require license acceptance (e.g. the MSAL.PS module) currently cannot be installed with automatic dependency management. You can track the issue status here and here. {: .notice–warning}
Azure function apps running PowerShell come with a nice feature called managed dependencies. You can specify the modules you want to import from the PowerShell Gallery and the function app host will automatically process the dependencies.
In the requirements.psd1 add the module details:
# This file enables modules to be automatically managed by the Functions service. # See https://aka.ms/functionsmanageddependency for additional information. # @{ # For latest supported version, go to 'https://www.powershellgallery.com/packages/Az'. 'Az' = '4.*' 'Microsoft.Graph.Authentication' = '0.*' } You can either specify an exact version available from the PowerShell Gallery or specify the major version with a wildcard. With the wildcard option it will use the latest version available.
The Office 365 Service Communications API provides information about Microsoft 365 service status for your tenant including service messages. I built a little PowerShell module to access the API with PowerShell cmdlets. In this post I want to show you some examples which help you to use the API.
PowerShell Module # I built a PowerShell module to access Microsoft 365 service status details natively with PowerShell. The PowerShell module and documentation is available on the PowerShell Gallery and on GitHub.
Before using the module an app registration is required. Setup instructions are also provided on GitHub.
CI/CD # By leveraging Azure DevOps I created a build and release pipeline which automatically builds the PowerShell module with Plaster.
Builds are only created if the commit on GitHub includes a version tag. This version tag gets automatically populated to the module manifest.
The build artifact gets then automatically published to the PowerShell Gallery as a new version. Furthermore, a new GitHub release including the module artifact is added to the project.
This process fully automates the publishing and build process for the module. For local development and maintenance, the module can also be built with Invoke-Build.
For larger Intune environments a solid role-based access implementation becomes crucial to ensure a secure administration. But how does Intune role-based access control (RBAC) work in combination with scope tags and how to get started? This post gets you covered with explanations and practical examples.
Role-based access control within the Microsoft 365 ecosystem # Within the Microsoft 365 ecosystem, Microsoft provides Azure AD administrative roles to administrate services like Exchange (Exchange administrator), SharePoint (SharePoint administrator), Intune (Intune administrator) and so on.
As you can see Azure AD provides (usually) only one role which grants full administrative access over a service. You can configure more fine-grained controls within the service itself - that’s where the RBAC controls of the respective service kick in.
To give you another example: You might have a 1st or 2nd level support department which needs permissions to perform remote actions on Intune managed devices. Instead of assigning them the Azure AD Intune Administrator role, it’s more convenient to assign them a fine-grained Intune RBAC role which delegates exactly the permissions needed.
As the name already indicates Intune related roles only live within the Intune tenant and cannot be managed from AAD and vice-versa:
Who invited this Azure AD guest user? Examining who invited a specific a guest account can be quite a challenging question if you don’t have a log analytics workspace in place with Azure AD Audit log forwarding configured.
Kusto queries for your log analytics workspace # The following queries help you to identify who invited a guest. If you haven’t set-up Azure AD audit log forwarding it’s the right time to do it now as described in one of my previous blogs.
To find all guest invitations:
AuditLogs | where OperationName == 'Invite external user' and Result == 'success' To find all accepted invitations:
AuditLogs | where OperationName == 'Invite external user' and Result == 'success' | extend InvitationId = tostring(AdditionalDetails[0].value) | join ( AuditLogs | where OperationName in('Redeem external user invite') | parse kind=regex TargetResources[0].displayName with * "InvitationId: " InvitationId:string "," ) on $left.InvitationId == $right.InvitationId Improving your guest user governance # To simplify the guest user review and management process I developed a solution which fully automates this process. Additionally the solution populates the user who invited a guest as the guest’s manager which allows you to easily examine the question “Who invited this Azure AD Guest Account?”.
Azure AD guest user review solution
Azure Active Directory guest users really simplify the process to collaborate with external users. Although keeping a good governance on guest accounts can become quite a challenge. The two biggest challenges I often observe are: “Who invited that guest user?” and “Does this guest user still need access to our infrastructure?”. Inspired by a recent post of Thomas Kurth regarding Azure AD Guest Account - Governance and Cleanup I also developed a solution which comes quite close to an “Azure AD Access review” like user experience.
Notable features # The ‘Manager’ attribute of your guest users get’s automatically populated with the identity of the inviter All Azure AD app registration information is stored in Azure Key Vault Almost zero touch deployment with ARM templates You can integrate existing guest users into this solution by populating the manager attribute in Azure AD You can configure the approval frequency for guest accounts Approval frequency respects last approval date for each guest account Architecture # The solution leverages function of:
Azure Logic App
Who doesn’t love a clean and tidy environment, do you? This also applies for your license assignments in Office 365 and Azure AD. As time passess it is likely to have users with direct license assignments or users which still have old trial licenses assigned. To get rid of those assignments I created a PowerShell script with removal and reporting functionality.
Direct link to the script.
Identify direct license assignments # In the Azure Portal we recognize direct license assignments on a user account by viewing the “Assignment Paths”: With the MSOnline PowerShell module we can view the Licenses property of a user and retrieve a nested property called: GroupsAssigningLicense. The GroupsAssigningLicense property contains either:
An empty array if the license was not inherited from a group -> direct assignment An array with objectId’s If the array contains the user’s objectId -> direct assignment Example 1: User with objectId 36c9b091-fe88-4dc2-a9e1-2662020b4bab has group based license assignment and direct assignment:
AccountSkuId : nicolasuter:SPE_E5 GroupsAssigningLicense : {0a918505-d0d5-4078-9891-0e8bec67cb65, 36c9b091-fe88-4dc2-a9e1-2662020b4bab} Example 2: User has no inherited licenses from a group:
AccountSkuId : nicolasuter:SPE_E5 GroupsAssigningLicense : {} PowerShell Script # You find the PowerShell script on my techblog GitHub repository.
Most of the time PowerShell is my favourite choice to automate processes and tasks. In order to improve the maintainability of my scripts I usually try to focus on some standards combined with a clean scripting style. In this post I want to show you 10 suggestions to improve your next PowerShell script. I’ve tried to order the suggestions according to an actual PowerShell starting from the very first line till the last line.
1. Script prerequisites # Your PowerShell script might need specific modules or elevated user rights to run. The #Requires statement ensures that these prerequisites are met before the actual script get’s executed. So you don’t need to implement your own checks to verify prerequisites.
Simply use the #Requires statement at the very first line of your script. Find out more about #Requires statement.
Modules # Another benefit of specifying the modules within the requires statement is that scripts hosted on the PowerShell Gallery automatically install the modules mentioned in the #Requires list.
To make sure a specific module is installed use:
#Requires -module "Microsoft.Graph.Intune" To ensure a module with a specific version is available:
Another migration of my blog? After running it for almost three years I thought it’s time for another change. The Ghost platform introduced a lot of changes and updates (with features that I don’t need) and caused me quite some expenses on my Azure subscription (around 50$ each month). Furthermore I wanted someting looking more clean with more focus on the writing part without a lot of fancy add-ons and functionalities. But it still had to cover features like tag summaries, yearly archive and a site search (Ghost doesn’t ship with those features out of the box). Because static sites seem to be a thing now I thought let’s hop onto the static site generator train.
I did some subjective research and decided that it will be Jekyll. I’ve chosen Jekyll because it’s quite easy to understand compared to hugo. Although hugo offers GraphQL which allows you to generate blog posts basically from any source including a REST API and Ghost has such an API in place which provides access to all posts.
To sum up the evolution of my blog:
2017 - 2018: Wordpress (hosted on a free hoster) 2018 - 2020: Ghost (hosted on Azure) 2020 - 20xx: Jekyll (hosted on GitHub Pages) Since the beginning of my blog I had my DNS zones running on Cloudflare including CDN features. When I migrated from Wordpress to Ghost I also migrated the comments to Disqus -> so for this migration I didn’t need to change anything regarding comments.
Microsoft is working on a new set of PowerShell modules grouped under the umbrella of Microsoft.Graph that will (hopefully) cover all the Microsoft Graph resources available. I’ve already used some of them for my Conditional Access Documentation Script and thought they have some notable features worth sharing.
Advantages and changes # The Microsoft Graph modules use the new Microsoft Authentication Library (MSAL) instead of the old Azure AD Authentication Library (ADAL). The MSAL library in the modules implements a token cache which persists the access and refresh tokens.
MSAL caches a token after it has been acquired. Application code should try to get a token silently (from the cache), first, before acquiring a token by other means. - Microsoft docs
The token cache persists system reboots and re-opening PowerShell sessions. The module allows you to obtain tokens either for authentication via client credentials (certificate only) or device code flow.
Furthermore, the new modules support a really broad spectrum of available entities on the Graph API. From an EM+S perspective this means for example: groups, users, identity protection, conditional access, and some of the Intune app management commands are also starting to appear.
Just be aware that the modules are currently published as pre-release. If you encounter any issues share them with the development team on GitHub and submit issues or even better contribute directly to the project.