December 3, 2020

How to get the file link from a SharePoint/OneDrive Sync location

This is a technical post highlighting some implementation part in the NWS PowerTool.
This explains how to get the URL to a file in a SharePoint Online or OneDrive from its local synced location.


Main functionality is implemented in ahk/Lib/SharePoint.ahk->SharePoint_Sync2Url function.

Get OneDrive Sync root folders

You can check for the Sync location using the environment variable named onedrive.
This will return your personal onedrive location. (I recommend to move the default location from C: to D:)
For the SharePoint Sync location, it is on the same level but without "OneDrive -" in its name (at least in our company setup)

; Get File Link for Personal OneDrive
EnvGet, sOneDriveDir , onedrive

; Get File Link for SharePoint/OneDrive Synced location
sOneDriveDir := StrReplace(sOneDriveDir,"OneDrive - ","")

Personal OneDrive

This is quite an easy one. You can get the cloud onedrive location from the registry key HKEY_CURRENT_USER\Software\SyncEngines\Providers\OneDrive -> Property UrlNameSpace:

RegRead, rooturl, HKEY_CURRENT_USER\Software\SyncEngines\Providers\OneDrive, UrlNamespace

SharePoint Online

The implementation is based on this trick I've learned in StackOverflow: get-onedrive-file-url-from-a-the-locally-cached-file:
Under the registry key HKEY_CURRENT_USER\Software\SyncEngines\Providers\OneDrive you have for each folder Sync location a SubKey with 2 properties: MountPoint and UrlNameSpace. 

Unfortunately, these properties are not a point-to-point mapping i.e. if you have synced a folder not on the top level, the MountPoint does not fit to the UrlNameSpace because the UrlNameSpace always points to the root of the Document Library.

This is why I need to store the proper mapping somewhere else: I have chosen to store it in a SPsync.ini file located in the root Sync folder.

You can get the last folder name from the name of the MountPoint/ Sync location since normally it is of the form SharePoint Name - FolderName or in case of a Team Private Channel Team Name - Private Channel Name - Folder Name.

In the example above: I have synced https://tenantName.sharepoint.com/teams/team_10000778/Shared%20Documents/General/Knowledge%20Broker%20Toolkit which is 2 levels below the root level.
The MountPoint/ Sync location is: D:\user\Tenant Name\Knowledge Brokers - Knowledge Broker Toolkit
but the UrlNameSpace is https://tenantName.sharepoint.com/teams/team_10000778/Shared Documents

The guessed mapping is: https://tenantName.sharepoint.com/teams/team_10000778/Shared Documents/Knowledge Broker Toolkit but you see it missed the intermediary folders in this case there shall be the General folder in between https://tenantName.sharepoint.com/teams/team_10000778/Shared%20Documents/General/Knowledge%20Broker%20Toolkit

The guessed mapping will also not work if you have - in your folder names.

You can see the implementation guess in the ahk/Lib/SharePoint.ahk->SharePoint_UpdateSyncIniFile function.
Extract below:

SharePoint_UpdateSyncIniFile(sIniFile:=""){
; showWarn := SharePoint_UpdateSyncIniFile(sIniFile:="")
If (sIniFile="")
    sIniFile := SharePoint_GetSyncIniFile()


If Not FileExist(sIniFile)
{
    TrayTip, NWS PowerTool, File %sIniFile% does not exist! File was created in "%sOneDriveDir%"Fill it following user documentation.

    FileAppend, REM See documentation https://tdalon.github.io/ahk/Sync`n, %sIniFile% 
    FileAppend, REM Use a TAB to separate local root folder from SharePoint sync root url`n, %sIniFile%
    FileAppend, REM It might be the default mapping is wrong if you've synced from a subfolder not in the first levelUrl shall not end with /`n, %sIniFile%

}

FileRead, IniContent, %sIniFile%

showWarn := False
Loop, Reg, HKEY_CURRENT_USER\Software\SyncEngines\Providers\OneDrive, K
{
    
    RegRead MountPoint, HKEY_CURRENT_USER\Software\SyncEngines\Providers\OneDrive\%A_LoopRegName%, MountPoint
    MountPoint := StrReplace(MountPoint,"\\","\")

    ; Exclude Personal OneDrive
    If InStr(MountPoint,"\OneDrive -")
        Continue

    If Not InStr(IniContent,MountPoint . A_Tab) {
        RegExMatch(MountPoint,"[^\\]*$",sFolderName)

        RegRead UrlNamespace, HKEY_CURRENT_USER\Software\SyncEngines\Providers\OneDrive\%A_LoopRegName%, UrlNamespace
        
        sFolderName := RegExReplace(sFolderName,"^EXT - ","") ; Special case for EXT -
        

        If FolderName := RegExMatch(sFolderName,"^[^-]* - ([^-]*) - ([^-]*)$",sMatch) { ;  Private Channel
            If (sMatch1 = sMatch2) { ; root folder has same name
                UrlNamespace := SubStr(UrlNamespace,1,-1) ; remove trailing /   
            } Else {
                UrlNamespace := UrlNamespace . sMatch2
                showWarn := True
            }
        } Else {
            FolderName := RegExReplace(sFolderName,".*- ","")
            
            If Not (FolderName = "Documents") { ; not root level
                UrlNamespace := UrlNamespace . FolderName
                ; For Teams SharePoint check for General channel folder to ignore displaying warning
                If RegExMatch(UrlNamespace,"sharepoint\.com/teams/team_")
                    If Not (FolderName = "General")
                        showWarn := True
                Else
                    showWarn := True
            } Else ; root level -> remove trailing /
                UrlNamespace := SubStr(UrlNamespace,1,-1)

        }
        FileAppend, %MountPoint%%A_Tab%%UrlNamespace%`n, %sIniFile%

    }
} ; end Loop

If (showWarn) {
    sTrayTip = If you are not syncing on the root level, you need to check the default mapping!
    TrayTip Check Mapping in SPsync.ini! , %sTrayTip%,,0x2
    Run "%sIniFile%"
}

return showWarn

} ; eofun

I've tried to avoid displaying a warning if most likely the guess is right i.e. for a General folder in a Teams SharePoint or for a Private Channel root level.
In case I display a warning, the Ini File will be opened for edit.

When reading the Ini File, if the directory could not be found in it, the SPSync.ini file will be automatically updated.

References

StackOverflow: get-onedrive-file-url-from-a-the-locally-cached-file

NWS PowerTool (Homepage)

No comments:

Post a Comment