Invite-AzureADUserToApplication.ps1
<#PSScriptInfo .VERSION 1.0.1 .GUID ceed3727-5009-43f0-ac9a-31f5f1dea88f .AUTHOR Chris Martin .COMPANYNAME Microsoft .COPYRIGHT .TAGS AzureAD Application ServicePrincipal .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES AzureAD .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .PRIVATEDATA #> #Requires -Module AzureAD <# .SYNOPSIS Add a collection of users (represented by email addresses) to an Enterprise Application role in Azure AD. .DESCRIPTION Add a collection of users (represented by email addresses) to an Enterprise Application role in Azure AD. External users that are not already represented in the directory will be invited. Invitation details can be exported by supplying -LogFilePath .PARAMETER EmailAddress One or more email addresses of users to add to the directory. .PARAMETER Application Will take either the ServicePrincipal TenantId or DisplayName. If the string evaluates to a GUID it will attempt to find it with TenantId, otherwise searches for DisplayName. .PARAMETER Role The name of the role to which the users will be added. .PARAMETER InternalDomains The list of InternalDomains to match so you don't try to invite internal users. .PARAMETER TenantId The ID of the tenant to access. If you leave this out, it will connect to your default tenant. .PARAMETER LogFilePath Path where the system will export the invited user details. .PARAMETER SuppressLogin Don't log in (Use this if you've already connected in the session and don't want to be prompted again.) .EXAMPLE Invite-AzureADUserToApplication.ps1 -EmailAddress 'mickey.mouse@externaldomain.com','minnie.mouse@externaldomain.com','donald.duck@internaldomain.com' -Application 'My Application' -Role User -InternalDomains 'internaldomain.com' -LogFilePath C:\users\mousem\Documents\InvitedUsers.csv Script would log you in to your default tenant, then check if 'mickey.mouse@externaldomain.com' and 'minnie.mouse@externaldomain.com' are registered in the directory. If they are not, they will invite them, and details about that invitation will be found at 'C:\users\mousem\Documents\InvitedUsers.csv' All specified users will then be added to the directory. If any internal users are on the list and not in the directory, the script will report an error. .EXAMPLE Import-Csv -Path 'C:\Users\MouseM\Documents\UsersToAddToApplication.csv' | Select-Object -ExpandProperty 'Email' | Invite-AzureADUserToApplication.ps1 -Application 'My Application' -Role User -InternalDomains 'internaldomain.com' -LogFilePath C:\users\mousem\Documents\InvitedUsers.csv Import all rows from a CSV, then isolate the 'Email' column. This becomes the -EmailAddress input, and the script would then log you in and add users to 'My Application'. If email addresses supplied are external and not in the directory, they will be invited, and invitation details will be found at 'C:\users\mousem\Documents\InvitedUsers.csv'. If any internal users are on the list and not in the directory, the script will report an error. #> [CmdletBinding()] Param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string[]] $EmailAddress, [Parameter(Mandatory = $true, Position = 1)] [string] $Application, [Parameter(Mandatory = $true, Position = 2)] [string] $Role, [Parameter(Mandatory = $false, Position = 3)] [string[]] $InternalDomains, [Parameter(Mandatory = $false, Position = 4)] [Guid] $TenantId, [Parameter(Mandatory = $false, Position = 5)] [ValidateScript({$_ -like "*.csv"})] [string] $LogFilePath, [switch] $SuppressLogin ) Begin { if (-not $SuppressLogin) { $connectParams = @{ ErrorAction = 'Stop' } if ($PSBoundParameters.ContainsKey('TenantId')) { $connectParams['TenantId'] = $TenantId } Connect-AzureAD @connectParams } $getAdspParams = @{ ErrorAction = 'SilentlyContinue' } $appId = [Guid]::Empty if ([Guid]::TryParse($Application, [ref] $appId)) { $getAdspParams['ObjectId'] = $appId } else { $escapedApplicationName = $Application.Replace("'","''") $getAdspParams['Filter'] = "DisplayName eq '$escapedApplicationName'" } $sp = Get-AzureADServicePrincipal @getAdspParams if ($null -eq $sp) { Write-Error -Message "No application found matching $Application in the directory." } $roleToAdd = $sp.AppRoles | Where-Object -Property DisplayName -EQ $Role if ($null -eq $roleToAdd) { Write-Error -Message "No role found on application $Application matching name $Role" -ErrorAction Stop } } Process { function Send-NewExUserInvitation { [CmdletBinding()] Param($EmailAddress) $exUser = New-AzureADMSInvitation -InvitedUserDisplayName $EmailAddress -InvitedUserEmailAddress $EmailAddress -SendInvitationMessage $false -InviteRedirectUrl "https://portal.azure.com" $escapedEmailAddress = $email.Replace("'","''") $user = Get-AzureADUser -Filter "mail eq '$escapedEmailAddress'" -ErrorAction Stop $csvInfo = [PSCustomObject]@{ DisplayName = $exUser.InvitedUserDisplayName EmailAddress = $exUser.InvitedUserEmailAddress InvitationRedeemUrl = $exUser.InviteRedeemUrl } Out-Log -InputObject $csvInfo Write-Output -InputObject $user } function Test-IsExternalEmail { [CmdletBinding()] Param($EmailAddress, $InternalDomains) $external = $true foreach ($domain in $InternalDomains) { if ($EmailAddress -like "*$($domain)") { $external = $false } } return $external } function Out-Log { Param($InputObject) if (-not [string]::IsNullOrWhiteSpace($LogFilePath)) { $InputObject | Export-Csv -Path $LogFilePath -Append } } foreach ($email in $EmailAddress) { $escapedEmailAddress = $email.Replace("'","''") $user = Get-AzureADUser -Filter "mail eq '$escapedEmailAddress'" -ErrorAction Stop if ($null -eq $user) { if (Test-IsExternalEmail -EmailAddress $email) { $user = Send-NewExUserInvitation -EmailAddress $email -ErrorAction Stop } else { Write-Error -Message "Internal email address $($email) that is not in the directory cannot be added. Only external users can be added to the directory with this script." continue } } New-AzureADUserAppRoleAssignment -ObjectId $user.ObjectId -PrincipalId $user.ObjectId -ResourceId $sp.ObjectId -Id $roleToAdd.Id -ErrorAction Continue } } |