pnp / PnP-PowerShell

SharePoint PnP PowerShell CmdLets
https://pnp.github.io/powershell
Other
987 stars 662 forks source link

Get-PnPUser has no permissions when using app permission #2224

Open felix-mueller-ic opened 5 years ago

felix-mueller-ic commented 5 years ago

Reporting an Issue or Missing Feature

Issue

Expected behavior

I am using an AzureAutomation RunAs Account and extended this one with an app secret (like in https://worktogether.tech/2018/06/09/connect-to-sharepoint-online-in-azure-automation-app-credentials/) I registered the app id in the SharePoint site (/_layouts/15/AppInv.aspx) with following request:

<AppPermissionRequests AllowAppOnlyPolicy="true">
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="Read"/>
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="Read"/>
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web/list" Right="Write"/>
</AppPermissionRequests>

I also tried to grant Grap API permissions for this app (Sites.ReadWrite.All, User.Read.All) After that I can get list items with Get-PnPListItem but when I want to get user information with Get-PnPUser I get an permission denied exception

Actual behavior

$adGrpUsers +=$(Get-PnPUser -Identity $adGrpID.LookupId -Connection $globalPnPConnection)
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (:) [Get-PnPUser], ServerUnauthorizedAccessException
    + FullyQualifiedErrorId : EXCEPTION,SharePointPnP.PowerShell.Commands.Principals.GetUser

Steps to reproduce behavior

$globalPnPConnection = Connect-PnPOnline -Url $_spURL  -AppId $graphAppId -AppSecret $graphAppSecret -ReturnConnection
$groupMappings = Get-PnPListItem -List $_spListName -Connection $globalPnPConnection
$adGrp = Get-PnPUser -Identity $groupMappings[0].FieldValues.UnifiedGroup[0].LookupId -Connection $globalPnPConnection 

Which version of the PnP-PowerShell Cmdlets are you using?

What is the version of the Cmdlet module you are running?

(you can retrieve this by executing Get-Module -Name *pnppowershell* -ListAvailable) 3.12.1908.1

How did you install the PnP-PowerShell Cmdlets?

ghost commented 5 years ago

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

garrytrinder commented 5 years ago

This is an interesting one, I can replicate this issue using 3.12.1908.1 by just calling Get-PnPUser.

Get-PnPUser : Access denied. You do not have permission to perform this action or access this resource.

I don't think this is a permissions issue as I can populate the SiteUsers property on the Web and return items from that property, which the command uses behind the scenes, SelectedWeb.Context.Load(SelectedWeb.SiteUsers, u => u.Include(retrievalExpressions));

$web = Get-PnPWeb
Get-PnPProperty -ClientObject $web -Property SiteUsers
$web.SiteUsers

A workaround for this could be to use the below to get the User object, but assumes you already know the UserId rather than the account name.

$web = Get-PnPWeb
$user = $web.GetUserById(<UserId>)
$web.Context.Load($user)
$web.ExecuteQuery()

Initial thoughts are that this issue could be caused by the retrievalExpressions object.

garrytrinder commented 5 years ago

As suspected the root cause is the retrievalExpressions object passed into the load, it contains properties for Alerts which cause the error to be thrown. Removing this block from the object allows the command to successfully complete with the app permissions.

https://github.com/SharePoint/PnP-PowerShell/blob/83ad7e82ff2bd3fb5cfdf3b844e87906ae221334/Commands/Principals/GetUser.cs#L66-L68

Not sure why Alerts are returned here, maybe @erwinvanhunen can advise?

I expect that raising the Web Rights to 'Manage' or 'FullControl' will fix this though, however I don't think that is a great fix in the long run.

felix-mueller-ic commented 5 years ago

I raised the Web Rights to 'Manage' but the error persists. This workaround works:

$web = Get-PnPWeb
$user = $web.GetUserById(<UserId>)
$web.Context.Load($user)
$web.Context.ExecuteQuery()