Permissions error upon running Add-DistributionGroupMember PS cmdlet on Exchange Online - azure

I'm currently trying to automate the user creation in Azure AD, and addition to a distribution group in Exchange Online using a PowerShell script. I've followed this guide for that - I've set up an app registration with a certificate and that's how I'm authenticating to both Azure AD and Exchange Online - without human intervention.
The specific Exchange cmdlet I'm running in the script (for the EXO part) is Add-DistributionGroupMember -member "user#domain.com" -identity "dlist" -BypassSecurityGroupManagerCheck, and once I run it I receive the following error output:
Active Directory operation failed on XXXXXXXXXXXXXXX.XXXXXXXXXXX.PROD.OUTLOOK.COM. This error is not retriable. Additional information: Insufficient access rights to perform the operation.
Active directory response: 00002098: SecErr: DSID-XXXXXXXX, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0
+ CategoryInfo : NotSpecified: (:) [Add-DistributionGroupMember], ADOperationException
+ FullyQualifiedErrorId : [Server=XXXXXXXXXXXXX,RequestId=8ac3130a-4bbe-41a0-b062-4768b6f51234,TimeStamp=1/3/2021 2:18:13 PM] [FailureCategory=Cmdlet-ADOperationException] XXXXXXX,Microsoft.Exchange.Management.RecipientTasks.AddDistribu
tionGroupMember
+ PSComputerName : outlook.office365.com
Other cmdlets such as
Get-Mailbox work correctly, but this specific one is giving me problems constantly. I've tried giving all API permissions I can think of in Azure to the application, both Delegated and Application permissions, and yet I'm still facing the error. Here's the current full list and I've had no success whatsoever:
I also tried replacing some of the Delegated permissions with Application permissions to no avail either. I tried assigning a variety of roles to the application as mentioned in the article too and every single time I get that Insufficient access rights to perform the operation error.
Could someone tell me why? Where and how am I supposed to grant the necessary permissions for the app to add a user to a distribution (mailing) list?
I've been searching around and found no answer to it for that last few days. Any help would be greatly appreciated.

Based on my test, adding Exchange.ManageAsApp Application permission and assigning Exchange Service administrator role is enough.
Create the AAD app with adding Exchange.ManageAsApp Application permission.
$appName = 'Exo_V2_App'
$api = (Get-AzureADServicePrincipal -Filter "AppID eq '00000002-0000-0ff1-ce00-000000000000'")
$permission = $api.AppRoles | Where-Object { $_.Value -eq 'Exchange.ManageAsApp' }
$apiPermission = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]#{
ResourceAppId = $api.AppId ;
ResourceAccess = [Microsoft.Open.AzureAD.Model.ResourceAccess]#{
Id = $permission.Id ;
Type = "Role"
}
}
$myApp = New-AzureADApplication -DisplayName $appName -ReplyUrls 'http://localhost' -RequiredResourceAccess $apiPermission
$mySP = New-AzureADServicePrincipal -AppID $myApp.AppID
$myApp | Format-List DisplayName,ObjectID,AppID
Assign the service principal to Exchange Service administrator role.
$directoryRole = 'Exchange Service Administrator'
$RoleId = (Get-AzureADDirectoryRole | Where-Object {$_.displayname -eq $directoryRole}).ObjectID
Add-AzureADDirectoryRoleMember -ObjectId $RoleId -RefObjectId $mySP.ObjectID -Verbose
You can try to create a new clean Azure AD app without adding additional configuration to have a test.

If I am not wrong, you should be part of the ManagedBy of the group before adding the members.
Step 1 :
First execute one of the below commands :
Set-DistributionGroup <NameOfGroup> -ManagedBy "<Your Alias>" -BypassSecurityGroupManagerCheck
Or :
Set-DistributionGroup Accounting -ManagedBy #{Add="< Your Alias>"} -BypassSecurityGroupManagerCheck
Step 2 :
Then execute the command to add the user to the group.
Add-DistributionGroupMember -Identity <NameOfGroup> -Member user#contoso.com

We had a very similar issue that was resolved by updating the Exchange Online PowerShell module version from 2.0.5 to 3.1.0.
Command to check version:
Get-InstalledModule ExchangeOnlineManagement | Format-List Name,Version,InstalledLocation
Command to update to latest version:
Update-Module -Name ExchangeOnlineManagement

Related

Automate connecting to Azure for checking and creating resources without prompt

I am required to write a PowerShell script, which can connect to my company's Azure account, check and create Azure resources (eg. Service Bus namespace, Service Bus topic, and Service Bus subscriptions). Everything worked well until I tried to deploy my script as a step in my project's on-premise TeamCity. I keep getting this error message
Exception calling "ShouldContinue" with "2" argument(s): "Windows
PowerShell is in NonInteractive mode. Read and Prompt functionality is
not available."
I investigated and found out that the problem is in this line
Connect-AzAccount
If I run the script manually, it will pop up a prompt asking me to login to Azure. I believe that's what went wrong. Because my project's on-premise TeamCity does not seem have an option to open a prompt for PowerShell command. I have read some workarounds, even on this website, but none of them is applicable to my case. Even a solution like https://stackoverflow.com/a/61099568/8213536 gave me these errors
WARNING: Unable to acquire token for tenant 'organizations' with error
'UsernamePasswordCredential authentication failed: There was an error
parsing WS-Trust response from the endpoint. This may occur if there
is an issue with your ADFS configuration. See
https://aka.ms/msal-net-iwa-troubleshooting for more details. Error
Message: Object reference not set to an instance of an object. See the
troubleshooting guide for more information.
https://aka.ms/azsdk/net/identity/usernamepasswordcredential/troubleshoot'
Connect-AzAccount : UsernamePasswordCredential authentication failed:
There was an error parsing WS-Trust response from the endpoint. This
may occur if there is an issue with your ADFS configuration. See
https://aka.ms/msal-net-iwa-troubleshooting for more details. Error
Message: Object reference not set to an instance of an object. See the
troubleshooting guide for more information.
https://aka.ms/azsdk/net/identity/usernamepasswordcredential/troubleshoot
At line:1 char:1
Connect-AzAccount -Credential $creds
+ CategoryInfo : CloseError: (:) [Connect-AzAccount], AuthenticationFailedException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand
One of the other solutions https://stackoverflow.com/a/52014189/8213536 requires an application's principal id, which is not applicable for my scenario either, as I am not creating a new application. I just need to be able to automatically connect to Azure (without prompt), check and create SB Namespace, SB Topic and SB Subscription.
Could someone please help me on this? Thanks.
As promised, I would like to post my solution. First I created a service principal with a client secret key. Then I asked my company's cloud engineer to assign it to the Azure subscription of my company and to the resource group that I intended to group all my necessary resources into. Finally in my code, I implemented something similar to https://stackoverflow.com/a/61099568/8213536
$applicationId = $azServicePrincipalId
Write-Host "Connecting to Azure using principal $applicationId"
$securePassword = $azServicePrincipalPw | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $applicationId, $securePassword
Connect-AzAccount -ServicePrincipal -TenantId $azureTenantId -Credential $credential
$azServicePrincipalId and $azServicePrincipalPw came from the Service Principal itself, while $azureTenantId came from my company's Azure subscription.
It is now working as expected.

What permissions are needed to read /write external collaboration policies?

I've written a powershell script that allows me to query azure for my azure ad policies like this:
Connect-AzureAD
$currentpolicy = Get-AzureADPolicy -All $true | ?{$_.Type -eq 'B2BManagementPolicy'} | select -First 1
$currentpolicy
$newPolicyValue = #("{`"B2BManagementPolicy`":{`"InvitationsAllowedAndBlockedDomainsPolicy`":{`"AllowedDomains`": [`"a.com`",`"b.org`",`"c.org`",`"d.com`"],`"BlockedDomains`": []}}}")
}
#update existing. This works. tested.
Set-AzureADPolicy -Definition $newPolicyValue -Id $currentpolicy.Id
This works because I'm signing in with an account that's got "owner" / global admin permissions. Now we wnat to try to figure out the specific permissions that are needed and just assign those to a new AD app registration.
I've created a service principal with a cert, and I changed my code like this:
Connect-AzureAD -TenantId $tid -ApplicationId $appid -CertificateThumbprint $thumb
$currentpolicy = Get-AzureADPolicy -All $true | ?{$_.Type -eq 'B2BManagementPolicy'} | select -First 1
$currentpolicy
I didn't add any specific permissions yet, and so when I run my script, I see the following error:
Get-AzureADPolicy : Error occurred while executing GetPolicies
Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.
InnerError:
RequestId: d88cd5d5-f8c9-4a4d-928b-986e0d5c25eb
DateTimeStamp: Thu, 16 Jun 2022 19:06:45 GMT
HttpStatusCode: Forbidden
HttpStatusDescription: Forbidden
HttpResponseStatus: Completed
At C:\Users\me\Documents\src\test\setPolicy.ps1:4 char:18
+ $currentpolicy = Get-AzureADPolicy -All $true | ?{$_.Type -eq 'B2BMan ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-AzureADPolicy], ApiException
+ FullyQualifiedErrorId : Microsoft.Open.MSGraphBeta.Client.ApiException,Microsoft.Open.MSGraphBeta.PowerShell.GetPolicy
Ideally, we want to use MS Graph permissions to do this. So i've been poking around in Azure, under the "API Permissions" for this application registration, but so far I haven't figured out which permission I need to add.
PS I know that the AzureADPreview and AzureAD is going away. But so far, it's the only way that I can automate these tasks. I have another stack question open about how to get this entire thing working via Graph
EDIT 1
I've tried the following permissions and none of them work so far...
EDIT 2
I've granted Policy.Read.All and now I can read the policies. Now it fails trying to update the existing policy.
It'd be nice to know specificially which read permission is needed so I don't have to grant all.
As far as write permissions, I've granted everything that comes up when I search for "policy" but none of them allow me to write!
EDIT 3
I've added the policy.readwrite.applicationconfiguration but that doesn't allow me to write. I'm still get the insufficient privleges error when I try to call Set-AzureADPolicy.
I don't know if you have found an answer, but as this is one of the first results that came up, I will add my findings.
I could get nowhere from giving specific permissions to the Service Principal but adding the Security Administrator role to the app did the trick. I didn't want to give the service principal so much access, but I tried a lot of roles and permission combinations, and none were sufficient.
Apparently, the documentation states that the least privileged role that is able to configure B2B external collaboration settings is the Global Administrator. Although for this case specifically, of changing the B2BManagementPolicy via PowerShell with a service principal, the Security Administration role was enough in my testing.
Looking at the actions that this role can perform I suspect it's because it has access to microsoft.directory/policies/basic/update, but I can't be sure.
Note: When adding a role to an App registration in Azure AD you need to search for its name when selecting the members, as they don't show by default.
Thanks for reaching out , with the help you read access , you will only able to get the data ,if you want to add or update you should have write permission as well , please add permission Policy.ReadWrite.ApplicationConfiguration and try again .
ref doc - https://learn.microsoft.com/en-us/graph/api/tenantappmanagementpolicy-update?view=graph-rest-beta&tabs=http
Edit 2
Update policy is available for PowerShell 2.0 preview
To update you need to use
Set-AzureADPolicy -ObjectId -DisplayName
To learn more about Set-AzureADPolicy, please checkout - https://learn.microsoft.com/en-us/powershell/module/azuread/set-azureadpolicy?view=azureadps-2.0-preview&viewFallbackFrom=azureadps-2.0
Thanks

Unable to Access SharePoint using PowerShell

I have registered an Application on Azure and I am trying to get an access token using the following command.
$Auth=Get-ODAuthentication -ClientId 01xex4x7-f0e2-xbx4-8aa3-1ac7a46c784c -AppKey "Xm1234~x555Sr-ATtpyCBOzkYiakI.PCVkEuBZ" -RedirectURI "http://localhost/login" -ResourceId "https://xyz.sharepoint.com/" -RefreshToken $LastAuth.refresh_token .
I am getting the following error.
Add-Member : Cannot bind argument to parameter 'Name' because it is an
empty string. At
C:\Users\Administrator\Documents\WindowsPowerShell\Modules\OneDrive\2.2.7\OneDrive.psm1:127
char:47
... thentication | add-member Noteproperty $element.split("=")[0] $elemen ..
However, when I save the command to a script and add a timeout, I am able to get the access token.
I have set the REDIRECT URI as http://localhost/login (Not an actual working URL). Can this be the reason. I tried to look this up but a little confused about the value this should have. Any pointers are greatly appreciated.
We have tested the same in our environment to access the sharepoint by using powershell and it works fine at our end. Below is the workaround :-
Register an application in Azure AD , Added redirect uri as http://localhost/ and enabled ID token .
Given the below permissions to our application and granted admin consent in Azure Ad.
Installed the one drive module by using Install-Module -Name OneDrive -Scope CurrentUser -force
Used the below command to get the access token after login with connect-azaccount , Ensure that you have provided all the permissions as mentioned above and added the correct resource ID of your sharepoint application and redirect uri as followed.
Cmdlt:-
$Auth=Get-ODAuthentication -ClientId "60xxxxxxxxxxxxxxxxx" -AppKey "3aXXXXXXXXXXXXXXXXXXXXXXXXXX=" -RedirectURI "http://localhost/" -ResourceId "https://mytest-admin.sharepoint.com/" -RefreshToken $LastAuth.refresh_token
OUTPUT DETAILS :-
POWERSHELL VERSION:
For more information please refer this GitHub| OneDrive for Business

Set-AzSqlServerActiveDirectoryAdministrator : Cannot find the Azure Active Directory object 'service_principal_name'

I am running the following command
$sp = az ad sp show --id $env:ARM_CLIENT_ID --query '{objectId: objectId, displayName: displayName}'
az sql server ad-admin create --resource-group data-eastus2 `
--server-name data-eastus2-sqlsvr `
--display-name $sp.name `
--object-id $sp.id
which works perflecty fine without providing any Graph API permissions to service principal.
Trying to mimick this functionality using Az Powershell module, by running the following
Set-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName 'data-eastus2' -ServerName 'data-eastus2-sqlsvr' -DisplayName $sp.name -ObjectId $sp.id
yields an exception
Set-AzSqlServerActiveDirectoryAdministrator : Cannot find the Azure Active Directory object
'service_principal_name'. Please make sure that the user or group you are authorizing is registered in the
current subscription's Azure Active directory. To get a list of Azure Active Directory groups use Get-AzADGroup, or
to get a list of Azure Active Directory users use Get-AzADUser.
At line:1 char:1
+ Set-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName 'data ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Set-AzSqlServer...ryAdministrator], ArgumentException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Sql.ServerActiveDirectoryAdministrator.Cmdlet.SetAzureSqlServerActiveDirectoryAdministrator
Providing Azure Active Directory Graph - Directory.Read.All and Microsoft Graph - Directory.Read.All
API Permissions didn't help.
The Azure CLI az sql server ad-admin create will not call Azure AD Graph to validate the parameters you passed, it just calls the REST API Server Azure AD Administrators - Create Or Update to set the admin. Even if you pass wrong --display-name and --object-id(also need to be Guid format), the command will also work fine. You could check the details with --debug parameter.
The Azure powershell Set-AzSqlServerActiveDirectoryAdministrator will call Azure AD Graph getObjectsByObjectIds: Get objects from a list of object IDs to validate if the object is correct or not. And if the result's type is not an Azure AD security group, it will further call Get a user. So if the result's type is a service principal, it will also call Get a user, then it will cause the issue. You could use fiddler tool to catch the reuqest like below.
So if you want to use the Set-AzSqlServerActiveDirectoryAdministrator, you could create a security group(not office group) in Azure AD, add the service principal to the group, then add the group to the sql server admin, as mentioned in #alphaz18's reply.
$sp = Get-AzADServicePrincipal -ObjectId "<object-id>"
$group = Get-AzADGroup -DisplayName "joysec"
Add-AzADGroupMember -TargetGroupObjectId $group.Id -MemberObjectId $sp.Id
Set-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName "<groupname>" -ServerName "<servername>" -DisplayName $group.DisplayName -ObjectId $group.Id
Note: To run the script above, you need to give a
Directory.ReadWrite.All Application permission of Azure Active Directory Graph(not Microsoft Graph) for your AD App, and there is some delay, wait for a while and test.
Most likely though i can't confirm this as i'm not 100% sure, but I think the set-azsqlserveractivedirectoryadministrator, only filters by azaduser or azadgroup. it probably won't search for service principals.
as a workaround though, if you want to accomplish this. you could create an azure ad group something called dbas or something. and add the service principal to that group. then add the group to the sql server using that set-azsqlcommand.
so something like this:
$sp = Get-AzADServicePrincipal -DisplayName "theserviceprincipalname"
Add-AzADGroupMember -MemberObjectId $($sp.id) -TargetGroupDisplayName "AAD Group Name"
Set-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName 'data-eastus2' -ServerName 'data-eastus2-sqlsvr' -DisplayName "AAD Group Name"
Hope that works for you, not 100% directly answer what you were asking, but I believe it is a viable workaround per your requirements hopefully.

Insufficient privileges assigning Azure Active Directory premissions to an MSI enabled Azure function?

We have two azure resources in the same directory. A webAPI set of APIs behind Azure API Management and an Azure Function. We want the azure function to be able to call the APIs. We've enabled MSI on the azure function as described in How to use managed identities for App Service and Azure Functions. We've created an App Registration in AAD for the API, created a role permission to be accessed. Following Calling your APIs with Azure AD Managed Service Identity using application permissions we run into errors attempting to assign the permission/role to the azure function:
in powershell:
New-AzureADServiceAppRoleAssignment -ObjectId 8XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -Id 3XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -PrincipalId 8XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -ResourceId 9XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
New-AzureADServiceAppRoleAssignment : Error occurred while executing NewServicePrincipalAppRoleAssignment
Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.
HttpStatusCode: Forbidden
HttpStatusDescription: Forbidden
HttpResponseStatus: Completed
At line:1 char:1
+ New-AzureADServiceAppRoleAssignment -ObjectId 8XXXXXX-XXXX-XXXX-XXXX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-AzureADServiceAppRoleAssignment], ApiException
+ FullyQualifiedErrorId : Microsoft.Open.AzureAD16.Client.ApiException,Microsoft.Open.AzureAD16.PowerShell.NewServ
icePrincipalAppRoleAssignment
is giving us a permission error, even when an AAD Admin (member of AAD DC Administrators I think) runs it. Has anyone run into this before? Why is this throwing a permissions error? We have verified that the ids are correct with 3 different people.
The problem you're probably facing is that, despite naming your app registration the same thing as your MSI-enabled app, the two end up representing different service principals in AAD. Using app registrations with MSI isn't currently supported.
Try running the powershell commands using the object id of the MSI identity instead. I was able to get this to work, and granted my MSI-enabled app access to the Graph Api.
Here is the PS I used to assign the GraphApi roles my function app required:
$functionAppName = "My-FANCY-FUNC"
$context = Get-AzureRmContext -ErrorAction SilentlyContinue #this lets you search AAD for func
if(!$context){
$login = Connect-AzureRmAccount | Out-Null
Connect-AzureAD #needed this for Graph API
$context = $login
} else { Write-Host "Login session already established for " $context.Subscription.SubscriptionName }
#get the SP associated with the MSI
$MSIPrincipal = Get-AzureRmADServicePrincipal -SearchString $functionAppName | Where-Object DisplayName -eq $functionAppName
#get the SP associatesd with the MS Graph
$graph = Get-AzureADServicePrincipal -All $true | ? { $_.DisplayName -match "Microsoft Graph" }
#find the target app roles in the graph
$targetRoles = $graph.AppRoles | Where-Object Value -in "Group.ReadWrite.All", "Directory.ReadWrite.All"
#iterate throgh the known roles and add the MSI SP to them
$targetRoles | ForEach-Object {New-AzureADServiceAppRoleAssignment -Id $_.Id -PrincipalId $MSIPrincipal.Id -ObjectId $MSIPrincipal.Id -ResourceId $graph.ObjectId}
I suspect, based on your question, that this line will return more than one entity:
Get-AzureRmADServicePrincipal -SearchString $functionAppName | Where-Object DisplayName -eq $functionAppName
Deleting your extraneous app registration should clear that up

Resources