{"id":6215,"date":"2021-04-13T05:02:47","date_gmt":"2021-04-13T13:02:47","guid":{"rendered":"https:\/\/officedevblogs.wpengine.com\/?p=6215"},"modified":"2021-04-13T05:02:47","modified_gmt":"2021-04-13T13:02:47","slug":"microsoft-graph-mailbag-copy-move-files-and-folders-in-sharepoint-online","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/microsoft-graph-mailbag-copy-move-files-and-folders-in-sharepoint-online\/","title":{"rendered":"Microsoft Graph Mailbag \u2013 Copy\/Move Files and Folders in SharePoint Online"},"content":{"rendered":"<p>In today\u2019s Microsoft Graph Mailbag post, we cover a customer scenario for copying and moving files between SharePoint Online sites using Microsoft Graph.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-large wp-image-6222\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/image0-1024x312.jpg\" alt=\"\" width=\"1024\" height=\"312\" srcset=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/image0-1024x312.jpg 1024w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/image0-300x91.jpg 300w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/image0-768x234.jpg 768w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/image0-1536x468.jpg 1536w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/image0-2048x624.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>Please be sure to follow this blog series using\u00a0<a href=\"https:\/\/aka.ms\/MSGraphMailbag\">https:\/\/aka.ms\/MSGraphMailbag<\/a>\u00a0or with RSS using\u00a0<a href=\"https:\/\/developer.microsoft.com\/graph\/blogs\/feed\/?tag=MSGraphMailbag\">https:\/\/developer.microsoft.com\/graph\/blogs\/feed\/?tag=MSGraphMailbag<\/a>.<\/p>\n<h4>Business Scenario<\/h4>\n<p>As a Customer Engineer (CE), I help Microsoft customers by being their trusted advisor to provide best practices, roadmap and guidance for various business scenarios. One such scenario deals with the copying and moving of files and folders between SharePoint Online (SPO) sites. The out of the box \u201cCopy To\u201d and \u201cMove To\u201d capability that SPO provides is great, but the sites that appear as the destination is based on the user signals (e.g., user followed sites, frequently accessed sites). For this customer, they want to control the sites the users see when they attempt to copy\/move files.<\/p>\n<h4>Background<\/h4>\n<p>We considered various approaches including compliance labels, PnP JS, SPO REST API and more.\u00a0 For SharePoint Online resources, Microsoft generally recommends to first use Microsoft Graph where possible.\u00a0 If Microsoft Graph does not cover specific functionality or resources, then it is recommended to fall back to SPO CSOM or another existing API. \u00a0In this scenario, the customer decided to go with Microsoft Graph and a SharePoint Framework solution after a quick proof of concept.<\/p>\n<h4>Solution<\/h4>\n<p>Let\u2019s get started.<\/p>\n<p>In this blog, I will share the various Microsoft Graph REST API calls that need to be constructed to copy\/move files from one site to another. Let\u2019s take a scenario where I need to copy\/move files from source \u201cSiteA\u201d to destination \u201cSiteB\u201d.<\/p>\n<p>Source: <a href=\"https:\/\/contoso.sharepoint.com\/sites\/SiteA\/Documents\/\">https:\/\/contoso.sharepoint.com\/sites\/SiteA\/Documents\/<\/a><\/p>\n<p>Destination: <a href=\"https:\/\/contoso.sharepoint.com\/sites\/SiteB\/Documents\/\">https:\/\/contoso.sharepoint.com\/sites\/SiteB\/Documents\/<\/a><\/p>\n<p>Here is a series of Microsoft Graph API calls. I also provided the corresponding sample response from these calls. Note that few of the responses are truncated for brevity.<\/p>\n<h4>Scenario: Copy Files<\/h4>\n<p><strong>Get source file:<\/strong><\/p>\n<ol>\n<li>Get the source site collection id:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">GET\nhttps:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com:\/sites\/SiteA?$select=id\nResponse:\n{\n\u00a0\u00a0\u00a0 \"@odata.context\": \"https:\/\/graph.microsoft.com\/v1.0\/$metadata#sites(id)\/$entity\",\n\u00a0\u00a0\u00a0 \"id\": \"contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\"\n}<\/pre>\n<p>2. Use the Site collection ID in the next query to get the list of document libraries:<\/p>\n<pre class=\"lang: decode:true\">GET https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drives?$select=id,name\n\nResponse:\n{\n\u00a0\u00a0\u00a0 \"@odata.context\": \"https:\/\/graph.microsoft.com\/v1.0\/$metadata#drives(id,name)\",\n\u00a0\u00a0\u00a0 \"value\": [\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"b!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"Documents\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"b!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9doAJ43YI-NhR6zMPnX1eLzZ\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"MyDocs1\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"b!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dr4572v55yoQo_RWg6MAlAR\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"MyDocs2\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 ]\n}<\/pre>\n<p>NOTE: The \/drives endpoint currently (as of 4\/10\/2021) is not supporting $filter or $search OData parameters.<\/p>\n<ol start=\"3\">\n<li>Now that we have the ID for \u201cDocuments\u201d library. Let\u2019s use that to enumerate all the files\/folders in this document library. Note how I am using the $select Odata parameter to limit the data in the response.<\/li>\n<\/ol>\n<pre class=\"lang: decode:true \">GET https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drives\/\nb!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\/list\/drive\/root\/children?$select=id,name,webUrl\n\nResponse:\n{\n\u00a0\u00a0\u00a0 \"@odata.context\": \"https:\/\/graph.microsoft.com\/v1.0\/$metadata#sites('contoso.sharepoint.com%2C1af9d2c5-2b3b-47d2-a167-ffd5d0c45205%2Ce748bad1-cb75-432f-8bb1-adff3b9ef5da')\/\ndrives('b%21xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-')\/list\/drive\/root\/children(id,name,webUrl)\",\n\u00a0\u00a0\u00a0 \"value\": [\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"@odata.etag\": \"\\\"{297E7CA7-4C49-440D-8E5F-84844DA865D0},1\\\"\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"017LC4LMFHPR7CSSKMBVCI4X4EQRG2QZOQ\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"Decks\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"webUrl\": \"https:\/\/contoso.sharepoint.com\/sites\/SiteA\/Shared%20Documents\/Decks\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"@odata.etag\": \"\\\"{F3226AA0-414F-4523-8364-9E03AF05801B},1\\\"\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"AuthCodePPEGuide.pdf\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"webUrl\": \"https:\/\/contoso.sharepoint.com\/sites\/SiteA\/Shared%20Documents\/AuthCodePPEGuide.pdf\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 ]\n}<\/pre>\n<ol start=\"4\">\n<li>I can improve the above query using $filter Odata parameter. Let\u2019s say I want to copy the file \u2018AuthCodePPEGuide.pdf\u2019. I can build the Microsoft Graph query as follows:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true \">GET https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drives\/\nb!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\/list\/drive\/root\/children?$filter=startswith(name, 'AuthCodePPEGuide.pdf')&amp;$select=id,name,webUrl\n\nResponse:\n{\n\u00a0\u00a0\u00a0 \"@odata.context\": \"https:\/\/graph.microsoft.com\/v1.0\/$metadata#sites('contoso.sharepoint.com%2C1af9d2c5-2b3b-47d2-a167-ffd5d0c45205%2Ce748bad1-cb75-432f-8bb1-adff3b9ef5da')\/\ndrives('b%21xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-')\/list\/drive\/root\/children(id,name,webUrl)\",\n\u00a0\u00a0\u00a0 \"value\": [\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"@odata.etag\": \"\\\"{F3226AA0-414F-4523-8364-9E03AF05801B},1\\\"\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"AuthCodePPEGuide.pdf\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"webUrl\": \"https:\/\/contoso.sharepoint.com\/sites\/SiteA\/Shared%20Documents\/AuthCodePPEGuide.pdf\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 ]\n}<\/pre>\n<ol start=\"5\">\n<li>I can now identify that specific file \/ document using its \u201cid\u201d as follows:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">GET https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drive\/items\/\n017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3<\/pre>\n<p><strong>Get destination location details:<\/strong><\/p>\n<ol start=\"6\">\n<li>Using similar queries shown earlier in steps 1 &amp; 2, I can identify the destination site collection id and the \u201cDocuments\u201d library id. Here is an example of what it looks like:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">https:\/\/graph.microsoft.com\/v1.0\/sites\/<strong>contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da<\/strong>\/drives\/\n<em>b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-<\/em><\/pre>\n<p>NOTE: <strong>Bold<\/strong> part is the site id for the destination site collection. <em>Italicized<\/em> part is for the &#8220;Documents&#8221; document library id.<\/p>\n<ol start=\"7\">\n<li>We need to build a reference notation for our destination location which could be the root of the document library or a specific folder within it. This reference is called \u201cparentReference\u201d.<\/li>\n<li>Run this Microsoft Graph query to enumerate the destination library, select the unique id and the parentReference corresponding to each entry:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">GET https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drives\/\nb!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\/list\/drive\/root\/children?$select=id,name,parentReference\n\nResponse:\n{\n\u00a0\u00a0\u00a0 \"@odata.context\": \"https:\/\/graph.microsoft.com\/v1.0\/$metadata#sites('contoso.sharepoint.com%2C1af9d2c5-2b3b-47d2-a167-ffd5d0c45205%2Ce748bad1-cb75-432f-8bb1-adff3b9ef5da')\n\/drives('b%21w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-')\/list\/drive\/root\/children(id,name,parentReference)\",\n\u00a0\u00a0\u00a0 \"value\": [\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"@odata.etag\": \"\\\"{F72ACBB9-419C-41FC-965C-F90DDE31F699},1\\\"\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>\"id\": \"01U7PKJ3NZZMVPPHCB7RAZMXHZBXPDD5UZ\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"DropFolder\",<\/strong>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em> \"parentReference\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveId\": \"b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveType\": \"documentLibrary\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"path\": \"\/drives\/b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\/root:\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/em>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"@odata.etag\": \"\\\"{08CB141D-4471-445B-B835-776E78A67C23},3\\\"\",\n\u00a0 \"id\": \"01U7PKJ3I5CTFQQ4KELNCLQNLXNZ4KM7BD\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": \"NDP462-DevPack-KB3151934-ENU.zip\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"parentReference\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveId\": \"b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveType\": \"documentLibrary\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"path\": \"\/drives\/b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\/root:\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\n\u00a0\u00a0\u00a0 ]\n}<\/pre>\n<p>NOTE: <strong>Bold<\/strong> part shows the unique ID of the entry (in this example, it\u2019s a folder with name \u2018DropFolder\u2019) and the <em>Italicized<\/em> part shows the parentReference corresponding to this document library.<\/p>\n<ol start=\"9\">\n<li>To copy the file to the root of the Document Library, I can use the parentReference from step 8 as-is.<\/li>\n<li>To copy to a specific folder within the library I must use the folders unique ID in the parent reference. From the above example, if you need to copy to \u2018DropFolder\u2019, your parentReference notation should look like this:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">\"parentReference\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveId\": \"b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ\"\n\u00a0\u00a0\u00a0 }<\/pre>\n<p>NOTE: The \u201cid\u201d corresponds to the ID of the DropFolder (see response in Step 8)<\/p>\n<p><strong>Copy the file to destination:<\/strong><\/p>\n<ol start=\"11\">\n<li>In Step 5 we identified the file to be copied with its ID. In Step 10 we identified the destination reference notation. Now to copy the file to the destination I send a POST request as follows:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">\/\/To copy the file to the root of the destination library\n\nPOST https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drive\/items\/\n017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3\/copy\n{\n\u00a0\u00a0\u00a0 \"parentReference\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveId\": -\"\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ\"\n\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0 \"name\": \"AuthCodePPEGuide.pdf\"\n}\n\/\/To copy the file to \u201cDropFolder\u201d folder in the destination library\nPOST https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drive\/items\/\n017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3\/copy\n{\n\u00a0\u00a0\u00a0 \"parentReference\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveId\": \"b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\",\n\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\"id\": \"01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ\"\n\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0 \"name\": \"AuthCodePPEGuide.pdf\"\n}\nResponse:\nHTTP 202 Accepted\n{\n \u00a0\u00a0 \"cache-control\": \"no-cache\",\n\u00a0\u00a0\u00a0 \"client-request-id\": \"0ffe0ea7-85f6-402e-f504-1a8740423832\",\n\u00a0\u00a0\u00a0 \"location\": \"https:\/\/contoso.sharepoint.com\/sites\/SiteA\/_api\/v2.1\/drive\/operations\/faa1c015-a4af-4dfb-9abf-03cd22890db3?c=ZU0xOVRzMGc4RFhJSV...\",\n\u00a0\u00a0\u00a0 \"request-id\": \"3868dff6-cdbd-45d1-bf3d-9ab98ea5491b\"\n}<\/pre>\n<ol start=\"12\">\n<li>As shown above you will get a 202 Accepted response, with a Location header that has a monitoring url. Copy that URL and open in a new tab to see the copy progress and status. Here is sample output:<\/li>\n<\/ol>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-6220 size-full\" src=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/mailbag-SPO-image.png\" alt=\"Sample output on 202 Accepted response\" width=\"624\" height=\"97\" srcset=\"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/mailbag-SPO-image.png 624w, https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-content\/uploads\/sites\/73\/2021\/04\/mailbag-SPO-image-300x47.png 300w\" sizes=\"(max-width: 624px) 100vw, 624px\" \/><\/p>\n<p>NOTE: The percentageComplete and status attributes in the JSON response.<\/p>\n<p><strong>Lessons Learned<\/strong><\/p>\n<p>Below are a few lessons learned along the way while working out the Microsoft Graph calls:<\/p>\n<ol>\n<li>Microsoft Graph calls to copy\/move work asynchronously, which means you must rely on the monitoring url that you get with the 202 Accepted response to check the status.<\/li>\n<li>You may hit issues including \u2018bad request\u2019, \u2018general error\u2019 or \u2018request malformed\u2019 in some scenarios, such as when the file that is being copied\/moved is greater than 160MB.<\/li>\n<li>I found that the above issue happens only when the \u201cname\u201d used for the destination file is different from the source file name. Ensure the destination file name is same as the source file name to resolve this issue. This issue is not reproducible with smaller files.<\/li>\n<\/ol>\n<h4>Scenario: \u00a0Move Files<\/h4>\n<ol>\n<li>To move a file from one library to another, we construct a similar request like we did in Step 5 in the above section. Here is an example for a file named \u201cProjectYRequirements.docx\u201d that exists in the source document library.<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,bc0a0284-87ff-4fcc-b039-0b7e02823759,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drive\/items\/\n01HD766IY4YTCVBFQNOBEZUBDSXXYDAQIJ<\/pre>\n<ol start=\"2\">\n<li>We also get the parentReference for the destination library\/folder. Example:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">\"parentReference\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveId\": \"b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ\"\n\u00a0\u00a0\u00a0 }<\/pre>\n<ol start=\"3\">\n<li>Then we patch the request to Microsoft Graph as follows:<\/li>\n<\/ol>\n<pre class=\"lang: decode:true\">PATCH https:\/\/graph.microsoft.com\/v1.0\/sites\/contoso.sharepoint.com,bc0a0284-87ff-4fcc-b039-0b7e02823759,e748bad1-cb75-432f-8bb1-adff3b9ef5da\/drive\/items\/\n01HD766IY4YTCVBFQNOBEZUBDSXXYDAQIJ\n\nHeaders:\nPrefer:respond-async\nRequest body:\n{\n\u00a0\u00a0\u00a0 \"parentReference\": {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"driveId\": \"b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-\",\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": \"01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ\"\n\u00a0\u00a0\u00a0 },\n\u00a0\u00a0\u00a0 \"name\": \"ProjectYRequirements.docx\"\n}\nResponse:\n{\n\u00a0\u00a0\u00a0 \"cache-control\": \"no-cache\",\n\u00a0\u00a0\u00a0 \"client-request-id\": \"8248a200-00cc-51cc-576c-b48d16109cf4\",\n\u00a0\u00a0\u00a0 \"location\": \"https:\/\/contoso.sharepoint.com\/sites\/Web03\/_api\/v2.1\/drive\/operations\/7e75fb87-07ea-4b85-8b40-369d1343ba38?c=T3QzNlIzOG1xdW1VOGR3OGlMZjFQYm5uR21...\",\n\u00a0\u00a0\u00a0 \"request-id\": \"9e419a03-4421-413a-9753-8d6dec74515d\"\n}<\/pre>\n<p><strong>Lessons Learned<\/strong><\/p>\n<p>Here are few lessons learned that are specific to moving files between sites and libraries:<\/p>\n<ol>\n<li>If destination name doesn\u2019t match, you will get HTTP 400 \u2013 Bad Request error with error message \u201cinvalid request\u201d. This is irrespective of the file size.<\/li>\n<li>If you match the file name then you will see HTTP 400 Bad Request but with error code that says: <em>Requested move requires an async response, add &#8216;Prefer: respond-async&#8217; to allow<\/em>. Ensure you add this header to the request.<\/li>\n<li>For the move to be successful the source and the destination libraries must have the same schema (Site Columns). This is because the Move action also moves the metadata along with the File.<\/li>\n<\/ol>\n<h4>Copy File using Microsoft Graph SDK<\/h4>\n<p>I can use the <a href=\"https:\/\/developer.microsoft.com\/graph\/blogs\/30daysmsgraph-day-15-microsoft-graph-in-dotnet-core-application\/\">.NET Core sample code<\/a> that we introduced in our <a href=\"https:\/\/developer.microsoft.com\/graph\/blogs\/announcing-30-days-of-microsoft-graph-blog-series\/\">#30DaysMSGraph series<\/a> to get started on how to use Microsoft Graph client library. Once I have the <a href=\"https:\/\/docs.microsoft.com\/graph\/sdks\/create-client?tabs=CS\">GraphServiceClient<\/a> object instantiated I can use below code snippet to copy a file between SPO sites.<\/p>\n<pre class=\"\">\/\/Create the destination parentReference\nvar parentReference = new ItemReference\n{\n \u00a0\u00a0\u00a0DriveId= \"b!w8qjV86a\u2026\u2026z2zXDxX4RYKTxY09UkQ-\",\n \u00a0\u00a0\u00a0Id= \"01U7PKJ3N6Y2GOV\u2026\u20265BZO354PWSELRRZ\"\n};\n\n\/\/File name to save as\nvar fileName = \"AuthCodePPEGuide.pdf\";\n\n\/\/Copy the file over to the destination library\nvar result = await graphClient.Sites[\"contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da\"]\n \u00a0\u00a0\u00a0.Drives[\"b!xdL5Gjsr0kehZ__V0MRSBd\u2026\u2026dq9z2zXDxX4RYKTxY09UkQ-\"]\n \u00a0\u00a0\u00a0.Items[\"017LC4LMFANIR\u2026\u2026CYGZE6AOXQLAA3\"].Copy(fileName, parentReference)\n \u00a0\u00a0\u00a0.Request().PostAsync();<\/pre>\n<h4>Conclusion<\/h4>\n<p>We showed the various Microsoft Graph calls required to copy\/move files and folders across SPO sites along with the lessons learned. We recommend using one of the <a href=\"https:\/\/github.com\/microsoftgraph\/msgraph-sdk-dotnet\">Microsoft Graph SDK<\/a>s rather than making REST API calls to Microsoft Graph. This is because the Microsoft Graph SDKs provide capabilities like token caching, retry calls, strongly typed resources, etc.<\/p>\n<p>&nbsp;<\/p>\n<p><em>Today\u2019s post was written by Srinivas Varukala, Sr. Customer Engineer (CE) at Microsoft.\u00a0 You can follow Srinivas on Twitter at <a href=\"https:\/\/twitter.com\/svarukala\">@Svarukala<\/a>. Join us for our next Microsoft Graph Mailbag post on April 27, 2021.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this blog, we share a scenario on constructing Microsoft Graph API calls to copy\/move files from one SharePoint Online site to another. <\/p>\n","protected":false},"author":69075,"featured_media":25159,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[17],"class_list":["post-6215","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-graph","tag-msgraphmailbag"],"acf":[],"blog_post_summary":"<p>In this blog, we share a scenario on constructing Microsoft Graph API calls to copy\/move files from one SharePoint Online site to another. <\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/6215","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/users\/69075"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/comments?post=6215"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/posts\/6215\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media\/25159"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/media?parent=6215"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/categories?post=6215"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/microsoft365dev\/wp-json\/wp\/v2\/tags?post=6215"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}