CSOM
25 TopicsProject Online (CSOM): Encountering 'User Not Found in Active Directory or Project DB'
Issue We are attempting to access Project Online data in Project Permission mode using app-only authentication, specifically to bypass MFA for programmatic access, as we aim for continuous, automated access without any user-interaction. We are using CSOM, using Microsoft.ProjectServer.Client.ProjectContext in .NET 4.8 to connect to Project Online. Despite following several documented approaches with client certificates, client secrets, and OAuth configurations, we keep encountering errors like 401 Unauthorized and User not found in Active Directory or in project db. Below is a summary of our steps. Despite multiple attempts, we consistently receive errors blocking access. We have followed recommended documentation for client credentials, certificates, and permissions but still face access issues. Technology Project Online CSOM in .NET 4.8 Microsoft.ProjectServer.Client.ProjectContext Azure AD (Entra ID) Solutions Attempted Client Certificate Authentication: Configuration: Registered an app in Azure AD (Entra) with a client certificate and set permissions including Sites.FullControl.All. NOTE: we could not select Project permissions (Project.Read, etc.) in the Application Permissions screen, only within the delegated permissions screen. Token Acquisition: We acquired an access token using az account get-access-token --resource=https://.sharepoint.com. Request Attempted: URL: https://%3Ctenant%3E.sharepoint.com/sites/%3cproject-site%3e/_api/ProjectData/Projects Outcome: {"error":"invalid_request","error_description":"App is not allowed to call SPO with user_impersonation scope"} Client Secret with Client Credentials: App Registration: Configured client ID and client secret in Azure AD with permissions for Project.ReadWrite.All and Sites.Selected. Token Acquisition: Called the token endpoint: Endpoint: https://login.microsoftonline.com/%7bTENANT_ID%7d/oauth2/v2.0/token Parameters: client_id, scope= https://%3Ctenant%3E.sharepoint.com/.default, client_secret, grant_type=client_credentials Access Attempt: URL: https://%3Ctenant%3E.sharepoint.com/sites/%3cproject-site%3e/_api/ProjectData/Projects Response: HTTP/1.1 401 Unauthorized Response Body: " " Outcome: Despite obtaining a valid token, the request returns a “Please sign in” page, rather than an access token. SharePoint AppPermissionRequest Configuration using /sites/pwa/layouts/15/appinv.aspx: Configuration: Set up AppPermissionRequest XML in SharePoint for permissions like: Outcome: This configuration did not make any differences, and did not grant the required permissions in Project Permission mode, as SharePoint app permissions do not seem to cover Project-specific access, it seems. Project Online access remains blocked. <AppPermissionRequest Scope="[http://sharepoint/content/sitecollection]" Right="FullControl"/> Microsoft Graph API Exploration: Goal: Investigated Graph API as an alternative. Outcome: Microsoft Graph lacks Project Online-specific permissions, limiting access to SharePoint and directory data, which does not meet our need for project-specific data access. Microsoft.Identity.Client and client certificate Configuration: CSOM using the following code to login: Outcome: Access fails with User:<customercontent></customercontent> not found in Active Directory or in project db public static void Login(this ProjectContext context) { var clientId = "xxx"; var clientSecret = "xxx"; var authority = "https://login.microsoftonline.com/xxx"; var scope = "https://xxx.sharepoint.com/.default"; var certificate = new X509Certificate2("c:\\temp\\cert.pfx", "xx"); var app = ConfidentialClientApplicationBuilder.Create(clientId) .WithCertificate(certificate) .WithAuthority(new Uri(authority)) .Build(); AuthenticationResult result = TaskHelper.BlockingAwait(() => app.AcquireTokenForClient(new[] { scope }).ExecuteAsync()); string accessToken = result.AccessToken; context.ExecutingWebRequest += (sender, e) => { e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessToken; }; } Key Questions: Is there a method for app-only authentication in Project Online in Project Permission mode__ that bypasses MFA for automated access? Has anyone succeeded in applying app-only credentials for Project Online access__, specifically in Project Permission mode? Are there any alternative permission configurations__ (like Azure AD settings, conditional access policies, or app permissions) that could facilitate this access? Thank you in advance! Edit: Sorry for the bad formatting.130Views0likes0CommentsUpdating Editor field on SharePoint Online using the CSOM with App Only Auth
I have the following issue. I work with CSOM and I want to update the Author and Editor field on a List Item object. The actual problem is that the Editor is not updated and the value is set to the SharePoint App user. The problem occurs after using the App Only Authentication. The following method is used to update Author, Editor, Creation Date and Modified Date. List<SP.ListItemFormUpdateValue> values = new List<SP.ListItemFormUpdateValue>(); foreach (ItemProperty property in properties) { property.AddPropertyToUpdateList(ctx, item, info, values); } IList<SP.ListItemFormUpdateValue> results = item.ValidateUpdateListItem(values, true, string.Empty); ctx.ExecuteQuery(); info.Log("<--// Called \'ValidateUpdateListItem\'. //-->"); // check for API-failures. CheckErrors(results); Do you have any ideas why this is not working for Editor but for Author-it works? I also tried to use the Update method to edit the Author and Editor, but this is also not working for the Author field. User user = service.Ctx.Web.EnsureUser("email address removed for privacy reasons"); ctx.Load(user); ctx.ExecuteQuery(); FieldUserValue userValue = new FieldUserValue(); userValue.LookupId =user.Id; item["Editor"] = userValue; item["Author"] = userValue; item.Update(); ctx.ExecuteQuery();4.2KViews0likes3CommentsMethod Not Found when running the application after some Windows updates
Hi everybody, After some Windows updates, I encountered a really annoying error. I don't have any compile errors, but when I run the application I get 'Method Not Found' error. Method not found: 'System.Collections.Generic.IList`1<Microsoft.SharePoint.Client.ListItemFormUpdateValue> Microsoft.SharePoint.Client.ListItem.ValidateUpdateListItem(System.Collections.Generic.IList`1<Microsoft.SharePoint.Client.ListItemFormUpdateValue>, Boolean, System.String)' I checked the ListItem class and the method is there. We are using the Microsoft.SharePoint.Client, Version=15.0.0.0. Do you have any idea what could be the problem? Thanks, Cristina.Solved1.6KViews0likes1CommentRetryQuery not working after throttling
Hi everyone, We are using the recommended approach for throttling. Here is the method we are using to execute the requests: public void ExecuteQueryWithRetry(ClientContext ctx, int retryCount, int backOffInterval, ILog LOG) { DateTime startTimeStamp = DateTime.Now; try { int retryAttempts = 0; int retryAfterInterval = 0; bool retry = false; ClientRequestWrapper wrapper = null; LOG.Debug($"Client Context: {ctx.GetHashCode()}"); LOG.Debug($"Throttled : {Throttled}"); if (Throttled) { while (Throttled) { LOG.Debug("Still throttled..."); Thread.Sleep(100); } Thread.Sleep(new Random().Next(500)); LOG.Debug("Throttled finished"); } while (retryAttempts < retryCount) { try { if (retry && wrapper != null && wrapper.Value != null) { LOG.Debug("Execute request with wrapper value..."); ctx.RetryQuery(wrapper.Value); LOG.Debug("Execute request with wrapper value finished"); Throttled = false; return; } else { LOG.Debug("Execute request..."); ctx.ExecuteQuery(); LOG.Debug("Execute request finished"); Throttled = false; return; } } catch (WebException ex) { var response = ex.Response as HttpWebResponse; // Check for throttling if (response != null && (response.StatusCode == (HttpStatusCode)429 || response.StatusCode == (HttpStatusCode)503)) { Throttled = true; wrapper = (ClientRequestWrapper)ex.Data["ClientRequest"]; retry = true; string retryAfterHeader = response.GetResponseHeader("Retry-After"); if (!string.IsNullOrEmpty(retryAfterHeader)) { if (!Int32.TryParse(retryAfterHeader, out retryAfterInterval)) { retryAfterInterval = backOffInterval; } } else { retryAfterInterval = backOffInterval; } LOG.Warn($"We got throttled! Will back off for {retryAfterInterval} seconds."); } else { LOG.Debug(ex.StackTrace); throw; } } Thread.Sleep(retryAfterInterval * 1000); retryAttempts++; } throw new MaximumRetryAttemptedException($"Maximum retry attempts '{retryCount}' has been attempted."); } finally { if (LOG.IsDebugEnabled) { TimeSpan duration = DateTime.Now - startTimeStamp; LOG.Debug($"Executed CSOM query in [{duration.TotalMilliseconds.ToString("0.00")}] ms"); } } } We got the 429 error and after that we wait the recommended time until we execute again the request. The request is re-executed using the RetryQuery method. After the method is called, we got no error but the request is not executed. Do you have any ideas why we encounter this problem?1.8KViews0likes2CommentsRight User Permissions to use ListItem.GetUserEffectivePermissions method
I'm currently using a SharePoint account as a Service account to get files and share them in an application I'm working on using CSOM. I filter the files according to the logged-in user to check if the user has no access to the file, then I hide it, to prevent him from trying to access it and get "Permission Denied" error. So, I used ListItem.GetUserEffectivePermissions for this issue, but I need to grant the user only the permissions he needs to access and make that check. I checked the official documentation of ListItem.GetUserEffectivePermissions https://learn.microsoft.com/en-us/previous-versions/office/sharepoint-csom/ee536458(v=office.15) but unfortunately, I found no direct clue which permission does the job. So to recap what this service account needs to do is : Execute Search across all sharepoint files [SearchExecutor]. Get Login Name by Email using Utility.ResolvePrincipal (to be used in GetUserEffectivePermissions function). Use GetUserEffectivePermissions to check if the logged-in User has permission to view the file. I'd really appreciate your help as I'm kind of new to SharePoint and I searched a lot but found no clue about what I need.1.5KViews0likes1CommentRetrieve custom properties of Office files through API call in OneDrive
In SharePoint, we are able to retrieve custom properties of the Office files through API call using Microsoft's CSOM library. This information is usually available in the "Properties" field. However, when uploading the same file to OneDrive and doing the same request, "Properties" field does not contain this information. As an example, please find the attached "Test DOCX file with custom properties.docx" file. https://files.axiomint.com/external/folder/afvh9b9bd8d011e2540d68c5992b1a7cd07b1?layout=list It contains 2 custom properties - "TestCustom1" and "TestCustom2". When uploading to SharePoint, this information is becoming available through API. SharePoint also changes the file size, so we assume it stores this data somewhere to make it available later for API requests. When uploading to OneDrive the file size does not grow and custom properties are not available during the request. So, our questions are 1. Why it works for SharePoint and does not work for OneDrive? 2. Is there a setting or some feature in OneDrive which will make it available there? Thanks, Vahe.1.3KViews0likes2CommentsIs there any way to generate Sharing Link without breaking inheritance on file
Hello I had posted another question which i had posted here https://docs.microsoft.com/en-us/answers/questions/991989/create-sharing-link-using-csompnpframework.html?childToView=995490#comment-995490 We basically need unique link on document that does not change with a change in file location. While we got answer partly, it led to another question which is, is there any way to get sharing link of a document in SPO without breaking its inheritance. Basically to generate sharing link with option of "Peopke with existing access" ? Any way to have this by CSOM , Rest or Graph Api? There are couple of options in CSOM , Rest and Graph ApI (beta) ..however they all have option of anonymous or organization sharing link whi h caused breaking inheritance. We are going to gave large number of documents in library and unique permission will not help. https://docs.microsoft.com/en-us/graph/api/listitem-createlink?view=graph-rest-beta&tabs=http1.2KViews0likes2CommentsCopy All Files and Folder from One Library to Another Library Subfolder on Diff Site Col Not Working
I'm trying to copy all files and folder from one library to another library subfolder between different site collections using the script from https://www.sharepointdiary.com/2017/02/sharepoint-online-copy-files-between-site-collections-using-powershell.html?unapproved=6740&moderation-hash=225816fd92c7259a540ec89c5072256c#comment-6740. It works for files after I modified $TargetFileURL = $TargetFolder.ServerRelativeUrl+”/”+$SourceLibraryName+”/”+$SourceFile.Name but struggling with subfolders from the source. They copy to the root without files in them. How can I make them copy to the same subfolder in the target library? #Load SharePoint CSOM Assemblies Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll" Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll" Function Copy-Files { param ( [Parameter(Mandatory=$true)] [Microsoft.SharePoint.Client.Folder] $SourceFolder, [Parameter(Mandatory=$true)] [Microsoft.SharePoint.Client.Folder] $TargetFolder ) Try { #Get all Files from the source folder $SourceFilesColl = $SourceFolder.Files $SourceFolder.Context.Load($SourceFilesColl) $SourceFolder.Context.ExecuteQuery() #Iterate through each file and copy Foreach($SourceFile in $SourceFilesColl) { #Get the source file $FileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($SourceFolder.Context, $SourceFile.ServerRelativeUrl) #Copy File to the Target location $TargetFileURL = $TargetFolder.ServerRelativeUrl+"/"+$SourceFile.Name [Microsoft.SharePoint.Client.File]::SaveBinaryDirect($TargetFolder.Context, $TargetFileURL, $FileInfo.Stream,$True) Write-host -f Green "Copied File '$($SourceFile.ServerRelativeUrl)' to '$TargetFileURL'" } #Process Sub Folders $SubFolders = $SourceFolder.Folders $SourceFolder.Context.Load($SubFolders) $SourceFolder.Context.ExecuteQuery() Foreach($SubFolder in $SubFolders) { If($SubFolder.Name -ne "Forms") { #Prepare Target Folder $TargetFolderURL = $SubFolder.ServerRelativeUrl -replace $SourceLibrary.RootFolder.ServerRelativeUrl, $TargetLibrary.RootFolder.ServerRelativeUrl Try { $Folder=$TargetFolder.Context.web.GetFolderByServerRelativeUrl($TargetFolderURL) $TargetFolder.Context.load($Folder) $TargetFolder.Context.ExecuteQuery() } catch { #Create Folder if(!$Folder.Exists) { $TargetFolderURL $Folder=$TargetFolder.Context.web.Folders.Add($TargetFolderURL) $TargetFolder.Context.Load($Folder) $TargetFolder.Context.ExecuteQuery() Write-host "Folder Added:"$SubFolder.Name -f Yellow } } #Call the function recursively Copy-Files -SourceFolder $SubFolder -TargetFolder $Folder } } } Catch { write-host -f Red "Error Copying File!" $_.Exception.Message } } #Set Parameter values $SourceSiteURL="https://crescent.sharePoint.com/sites/sales" $TargetSiteURL="https://crescent.sharepoint.com/sites/ops" $SourceLibraryName="Project Documents" $TargetLibraryName="Documents" #Setup Credentials to connect $Cred= Get-Credential $Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.Username, $Cred.Password) #Setup the contexts $SourceCtx = New-Object Microsoft.SharePoint.Client.ClientContext($SourceSiteURL) $SourceCtx.Credentials = $Credentials $TargetCtx = New-Object Microsoft.SharePoint.Client.ClientContext($TargetSiteURL) $TargetCtx.Credentials = $Credentials #Get the source library and Target Libraries $SourceLibrary = $SourceCtx.Web.Lists.GetByTitle($SourceLibraryName) $SourceCtx.Load($SourceLibrary) $SourceCtx.Load($SourceLibrary.RootFolder) $TargetLibrary = $TargetCtx.Web.Lists.GetByTitle($TargetLibraryName) $TargetCtx.Load($TargetLibrary) $TargetCtx.Load($TargetLibrary.RootFolder) $TargetCtx.ExecuteQuery() #Call the function Copy-Files -SourceFolder $SourceLibrary.RootFolder -TargetFolder $TargetLibrary.RootFolder1.1KViews0likes0CommentsCSOM SystemUpdate() cannot update Editor field
In a SharePoint Online Document Library I've a file that is in published status (version x.0). I am updating various fields of this file with the listItem.SystemUpdate() command. I need this sort of update because is the only one that can be used on a published file that not increase the version. (UpdateOverrideVersion return an error on published documents) When I try to update the Editor fields this is not updated. (_currentItem is a File object) var user = _ctx.Web.EnsureUser(publishinfo.currentUser_email); _ctx.Load(user); _ctx.ExecuteQuery(); _currentItem.ListItemAllFields["Editor"] = user; _currentItem.ListItemAllFields.SystemUpdate(); _ctx.ExecuteQuery(); All other fields of the item can be updated. "Editor" and "Modified" are the only two that are not working. (Author for example is correctly updated in this way) Any idea? Thanks2.2KViews0likes1CommentExisting CSOM script modify from basic to modern authentication?
I have a big CSOM powershell script which is using basic authentication. This script is scheduled to run every day. This script is using credentials of a serviceaccount without MFA. We would like to disable basic authentication, but this script needs to be modified. I dont want to rewrite the whole CSOM script to Office Dev PnP Powershell because it is a big script. What is the easiest way to move from basic to modern authentication in a CSOM powershell script? See below a small part with authentication and some SPO logic: $lo_ClientContext = New-Object Microsoft.SharePoint.Client.ClientContext( https://myCompany.sharepoint.com/sites/test ) $lo_ClientContext.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials( Email address removed, myPassword ) $lo_ClientContext.ExecuteQuery() $ll_Lijst = $lo_ClientContext.Web.Lists.GetByTitle( "myList" ) $lo_ClientContext.Load( $ll_Lijst ) $lo_ClientContext.ExecuteQuery()741Views0likes0Comments