Last time I wrote about the magic at work when OneDrive performs its Known Folder Move (KFM). This time, Iâll show you how to get your overalls dirty and tinker under the hood of this beast. Buckle up, itâs going to be a wild ride.
Also, please be kind to me in the comments. This is my first real adventure into the depths of SharePoint and its PowerShell Possibilities tm.
| I’ve grown up a little… Since embarking on my first adventures in blogging, with the gracious help of Oktay, I’ve created my own blog: threeisacloud.tech. This post was re-published there (albeit in slightly redacted form). The version here will stay, forever reminding me of my roots. |
Did you know?
MS Word marks Onedrive and Sharepoint (without a capital D or P) as a spelling error. Nice one, Microsoft!
You might want to read the previous post
You can still read it here.
Here’s the gist of it: OneDrive uses a SharePoint List called âDocumentsâ (conveniently named to avoid any confusion). All folders, including the âKnownâ ones, live inside this List. To keep track of which folders are âKnownâ, some metadata is published inside the Listâs properties. OneDrive clients use this metadata during KFM which can cause issues in multi-lingual environments.
To use, or not to use
Letâs just make this clear upfront: if you need to use this information, youâre probably suffering from some technical debt. KFM is a wonderful thing, but you really should have been using it from the get-go.
So, when would this blog come in handy? Imagine someone moved (letâs say 10.000) home folders (with English names) to OneDrive, using SharePoint Migration Tool (SPMT). Now imagine someone else having to redirect a Dutch endpoints Known Folders to those OneDrive folders.
Oh, and someone else is not allowed to change folder names or the display language because the fate of the universe depends on it.
Now, say hello to someone else (I’ll wave backđ).
Not Plug ânâ Play

You canât really expect this kind of configuration to be available in a GUI, can you? So, as always, PowerShell comes to the rescue. Apparently, the library of choice is PnP.PowerShell (Iâm once again trusting the judgement of Patrick Lamber here đ). The PnP-part doesnât stand for âPlug and Playâ, as I soon found out (it stands for Patterns and Practices).
Installation of modules is easy these days (just agree to everything like you always would) and itâs probably a good idea to import it as well.
Install-Module -Name PnP.PowerShell; Import-Module -Name PnP.PowerShell;
BasicallyâŚ
I started by figuring out the basics. Apparently, you need a SharePoint Url to connect to (duh), and some credentials to authenticate. I used the -Interactive switch because my Conditional Access policies don’t want to deal with basic sign-ins.
$url = 'https://notreally-my.sharepoint.com/personal/n_scheffers_alsonotreally_nl'; Connect-PnPOnline -Url $url -Interactive;
Remember that classmate that always did just about everything in your school projects? PnP.PowerShell has one of those. Itâs called the Context. Itâs the fabric that ties everything together.
Letâs get one of those. Itâll come in handy in the future.
$siteCtx = Get-PnPContext;
There you go; thatâs the basics done. I took me way longer to read the docs than to write this code.
Also, respect this classmate. They helped get your career started.
Get all the things
Letâs move on to getting some information out of this thing. Remember that OneDrive always makes a List called âDocumentsâ?
$documentsList = Get-PnPList -Identity 'Documents';
What I really, really want is Spice Girls reference. But seriously, Iâm only interested in the RootFolder of this list. Unfortunately, at first, only some basic properties are loaded, and the metadata is far from basic. Letâs ask our favorite classmate to get some more.
Notice the ExecuteQuery()Â method: it instructs the Context to perform any outstanding operations, albeit read- or write-operations.
$siteCtx.Load($l.RootFolder.Properties); $siteCtx.ExecuteQuery();
Although this particular classmate is awesome, you always need to tell them what you want, and then tell them to go do it. Thatâs what the ExecuteQuery() method is for, it basically yells “GO!”. Weâll see that a few more times.
Now, we can get our hands on all that juicy metadata:
$documentsList.RootFolder.Properties['vti_DesktopFolderGuid']; $documentsList.RootFolder.Properties['vti_DocumentsFolderGuid']; $documentsList.RootFolder.Properties['vti_CameraRollFolderGuid']; $documentsList.RootFolder.Properties['vti_ScreenShotsFolderGuid']; $documentsList.RootFolder.Properties['vti_PhotosFolderGuid'];
Falter folder
Next up is figuring out how Iâm going to get to this Guid I keep reading about. Canât be too hard, can it now?
Itâs not. At least not if I tell you a little secret first.
Even though this metadata is named vti_SomethingFolderGuid, it doesnât really want to know the generic GUIDÂ property youâll find in each SharePoint-folder. What it does want, is the UniqueId-property. Yes, they are different. No, using the wrong one doesnât throw an error. It simply doesnât do anything. Took me a while to figure that out.
First, I tried this:
$documentsFolderGuid = (Get-PnPFolder 'Desktop').UniqueId;
It gets the job done. Sometimes. But every so often, the UniqueId-property is empty.
Next, I tried this:
$documentsFolderGuid = (Get-PnPFolder '/personal/n_scheffers_alsonotreally_nl/Documents/Documen-ta-daa').UniqueId;
Thatâs the ServerRelativeUrl, right there, so we arenât leaving anything to chance. Doesnât give me the UniqueId-property though. It exists but is always empty.
While I was trying to be funny, I somehow used an (almost) real Spanish word for my folder name.
Then thereâs that classmate, saving the day again:
$documentsFolder = (Get-PnPFolder '/personal/n_scheffers_alsonotreally_nl/Documents/Documen-ta-daa'); $siteCtx.Load($documentsFolder.ListItemAllFields); $siteCtx.ExecuteQuery(); $documentsFolderGuid = $documentsFolder.ListItemAllFields.FieldValues['UniqueId'];
Ready? Set.
You can set these properties by simply assigning data to them. Remember to cast your fresh Guid to a string. For example:
$documentsList.RootFolder.Properties['vti_DocumentsFolderGuid'] = $documentsFolderGuid.ToString();
You then need to mark the RootFolder as ready-to-update and ask the Context to commit it.
$documentsList.RootFolder.Update(); $siteCtx.ExecuteQuery();
Go!
If you put all of this together, youâll get something like this:
$siteUrl = 'https://notreally-my.SharePoint.com/personal/n_scheffers_alsonotreally_nl';
$documentsFolderName = 'Documen-ta-daa';
Import-Module -Name PnP.PowerShell;
Connect-PnPOnline -Url $siteUrl -Interactive;
$siteCtx = Get-PnPContext;
$documentsList = Get-PnPList -Identity 'Documents';
if ($siteCtx -and $documentsList) {
$documentsListUrl = $documentsList.RootFolder.ServerRelativeUrl;
$documentsFolderUrl = "$($documentsListUrl)/$($documentsFolderName)";
$documentsFolder = Get-PnPFolder -Url $documentsFolderUrl;
$siteCtx.Load($documentsFolder.ListItemAllFields);
$siteCtx.ExecuteQuery();
if ($documentsFolder) {
$documentsFolderGuid = $documentsFolder.ListItemAllFields.FieldValues['UniqueId'];
if ($documentsFolderGuid) {
$documentsList.RootFolder.Properties['vti_DocumentsFolderGuid'] `
= $documentsFolderGuid.ToString();
$documentsList.RootFolder.Update();
$siteCtx.ExecuteQuery();
}
}
}

Keep in mind that this doesnât magically change your existing OneDrive deployments. The mapping is performed by KFM, and KFM is only executed once per deployment.
As I said in the beginning: this will only be of interest when you already have data in OneDrive, and you must ensure the correct Known Folder mapping is applied on additional endpoints.
I hope you enjoyed this two-part series. I sure enjoyed writing it. If only I had some more free time to spend on this kind of stuff.
[…] Part 2 is now available. I’ll get up close and personal with this metadata and explain how to make it fall in line. […]
[…] This was originally published on December 20th, 2022 as a guest post for allthingscloud.blog. It’s been (slightly) redacted and placed here as its permanent home. You can still read the original here. […]