After a few set of tests, I think I finally found out the problem.
I will document what I've found and in the end you'll find the actual solution.
There's always the chance that there are other variables in your scenario, but I hope this will help in some way.
Currently there is a sort of a built-in security mechanism in which certain files and file content are being blocked, to prevent harmful code execution.
File types such as .aspx are blocked by the api, meaning you cannot create your own or upload your own files, even copying from other sites won't work while this mechanism is enabled.
SharePoint Designer, renaming .txt to .aspx
File Explorer, renaming .txt to .aspx
The same will happen if we do any file creation, copying or moving through the api (401 unauthorized).
There are 2 settings that prevent script files and script content:
You'll need to disable at least DenyAddAndCustomizePages, which will automatically stop blocking your .aspx files.
I happen to have a gist here, even though it's a one liner to set it up:
With the blocking problem out of the way, you can chose your flavor:
- Use file explorer / manual reorganization
- Code it in a method of choice
Here's a working example:
ClientContext context = GetContext(webUrl);
Web web = context.Web;
List sourceList = web.Lists.GetByTitle("Site Pages");
ListItem sourceItem = sourceList.GetItemById(3);
Web subWeb = web.Webs;
List destList = subWeb.Lists.GetByTitle("Site Pages");
string newFileUrl = destList.RootFolder.ServerRelativeUrl + "/" + sourceItem.File.Name;
Console.WriteLine("Copying " + sourceItem.File.ServerRelativeUrl + " to " + newFileUrl);
FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(context, sourceItem.File.ServerRelativeUrl);
Microsoft.SharePoint.Client.File.SaveBinaryDirect(context, newFileUrl, fileInfo.Stream, true);
Types of files that cannot be added to a list or library
Access denied when uploading page to SitePages library in SharePoint Online
SharePoint Online Management Shell
Disable DenyAddAndCustomizePages property of the SPOSite object