I was playing around with LINQPad today and wrote this C# code to export all attachments from CRM. You can customise the query to export only certain attachments if required. You could also modify the code to gather the output location from the user, instead of asking them to choose between “My Documents” or “Desktop”. This could also be potentially written as an XrmToolBox tool.
I executed the code in LINQPad v5.26 and Dynamics CRM 2016 OnPremise 8.1 environment. I tried to retrieve the attachment using LINQ, but decided to use normal QueryByAttribute with paging for performance reasons.
Util.RawHtml(" <h4>Choose an output path</h4> ").Dump(); var folders = new List<Environment.SpecialFolder> { Environment.SpecialFolder.Desktop, Environment.SpecialFolder.MyDocuments }; folders.ForEach(x => new Hyperlinq(() => DumpFiles(Environment.GetFolderPath(x)), x.ToString()).Dump()); void DumpFiles(string selectedFolder) { Util.ClearResults(); new Hyperlinq(selectedFolder).Dump("Chosen output path"); var progress = new Util.ProgressBar("Writing files: ").Dump(); progress.HideWhenCompleted = true; var retrieveQuery = new QueryByAttribute("annotation") { ColumnSet = new ColumnSet("documentbody","filename"), PageInfo = new PagingInfo{ Count = 500, PageNumber = 1 } }; retrieveQuery.AddAttributeValue("isdocument", true); var resultsDc = new DumpContainer().Dump($"Results"); EntityCollection results; int totalRecordCount = 0; do { results = ((RetrieveMultipleResponse)this.Execute(new RetrieveMultipleRequest { Query = retrieveQuery })).EntityCollection; var files = results.Entities.Cast<Annotation>(); totalRecordCount += results.Entities.Count; resultsDc.Content = $"Completed Page {retrieveQuery.PageInfo.PageNumber}, Files: {totalRecordCount}"; int fileNumber = 0; foreach (var f in files) { fileNumber++; var fileContent = Convert.FromBase64String(f.DocumentBody); File.WriteAllBytes(Path.Combine(selectedFolder, f.FileName), fileContent); progress.Caption = $"Page {retrieveQuery.PageInfo.PageNumber} - Writing files: {fileNumber}/{retrieveQuery.PageInfo.Count}"; progress.Percent = fileNumber * 100 / retrieveQuery.PageInfo.Count; } retrieveQuery.PageInfo.PageNumber++; retrieveQuery.PageInfo.PagingCookie = results.PagingCookie; } while (results.MoreRecords); resultsDc.Content = $"{totalRecordCount} files saved."; }
Interesting post, i have never heard or seen this kind of requirement. I would like to get my hands dirty too. How do i start? Is this code is part of the project or it is a complete solution? I am not sure how to start, can you upload the whole project/solution or some step by step process how to build this.
Thank you.
This was a quick snippet I wrote for a once off export. You need to download the CRM Driver for LinqPad (https://github.com/kenakamu/CRMLinqPadDriver). Once you do this, you would be able to execute the snipper from LinqPad. The advantage with LinqPad C# code is that, you don’t need to “build” anything. You just execute code fragments as and when required.
[…] https://dreamingincrm.com/2018/01/18/export-all-attachments-using-linqpad/ […]