Syncing SharePoint Document Libraries on Non-Persistent Virtual Computers

Copper Contributor

I have searched for ways to "sync" a SPO Document Library, particularly a Teams Document Library, in a non-persistent VDI where you have access via Windows Explorer similarly to OneDrive. While I couldn't find anything directly to accomplish this, I did piece together a method that would achieve the goal with a PowerShell script and I wanted to share in case it helped others or could be improved upon by the community. 

 

Prereqs: OneDrive "per-machine install" installed on the gold image with on-demand enabled via GPO

 

The first part of the script sets the vars needed for the SharePoint Document library. See Deploy OneDrive apps using Microsoft Endpoint Configuration Manager for information on how to find these values.

 

 

$WebURL = "https://tenant.sharepoint.com/sites/"
$SiteName = "SPOSite"
$SiteID = "<thesiteid>"
$ListID = "<thelistid>"

 

 

After these values, I use a sleep timer to give time for all services to load before proceeding.

 

 

Start-Sleep -s 20

 

 

Next is to query AD for the user's email address using Get-ADUser. The email address will be used by ODOpen to sync the library.  

 

 

$DomainServer = [System.Net.Dns]::GetHostByName($env:LOGONSERVER.Substring(2)).HostName
$UserName = [Environment]::UserName
$User = Get-ADUser -Server $DomainServer -Filter {SamAccountName -eq $UserName} -Properties *
$UserEmail = $User.EmailAddress

 

 

Next I use a "Do" loop to make sure OneDrive has started before trying to sync the library.

 

 

Do{
    $ODStatus = Get-Process onedrive -ErrorAction SilentlyContinue
    
    If ($ODStatus) 
    {

 

 

I add in another sleep timer to give OneDrive time to authenticate and start syncing the user's OneDrive.

 

 

Start-Sleep -s 30

 

 

 Next I set the path for the ODOpen command using the vars from earlier and start the process.

 

 

$odopen = "odopen://sync/?siteId=" + $SiteID + 
  "&webUrl=" + $webURL + $SiteName + 
  "&listId=" + $ListID + 
  "&userEmail=" + $User.EmailAddress + 
  "&webTitle=" + $SiteName + "
"
Start-Process $odopen

 

 

Lastly, I close out the Do loop

 

 

    }
}
Until ($ODStatus)

 

 

Save the script to a network share accessible by users and use a GPO, or a product like VMware's DEM, to place a shortcut to the script in users' Startup folder. 

 

Complete script below.

 

 

# Script for using OneDrive, with on-demand enabled, to sync SPO library at login

# Create a shortcut to this script in the user's Startup folder
# Target should be C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -File "\\server\share\SyncSPOSite.ps1"

# Update variables below for the SPO library to sync. See this link for more info
# https://docs.microsoft.com/en-us/onedrive/deploy-on-windows?redirectSourcePath=%252fen-us%252farticle%252fdeploy-the-new-onedrive-sync-client-in-an-enterprise-environment-3f3a511c-30c6-404a-98bf-76f95c519668

$WebURL = "https://tenant.sharepoint.com/sites/"
$SiteName = "SPOSite"
$SiteID = "<thesiteid>"
$ListID = "<thelistid>"

# Give Windows some time to load before getting the email address
Start-Sleep -s 20

$DomainServer = [System.Net.Dns]::GetHostByName($env:LOGONSERVER.Substring(2)).HostName
$UserName = [Environment]::UserName
$User = Get-ADUser -Server $DomainServer -Filter {SamAccountName -eq $UserName} -Properties *
$UserEmail = $User.EmailAddress

# Use a "Do" loop to check to see if OneDrive process has started and continue to check until it does

Do{
    # Check to see if OneDrive is running
    $ODStatus = Get-Process onedrive -ErrorAction SilentlyContinue
    
    # If it is start the sync. If not, loopback and check again
    If ($ODStatus) 
    {
        # Give OneDrive some time to start and authenticate before syncing library
        Start-Sleep -s 30

        # set the path for odopen
        $odopen = "odopen://sync/?siteId=" + $SiteID + "&webUrl=" + $webURL + $SiteName + "&listId=" + $ListID + "&userEmail=" + $User.EmailAddress + "&webTitle=" + $SiteName + ""
        
        #Start the sync
        Start-Process $odopen
    }
}
Until ($ODStatus)

 

13 Replies

@TonyBryant great article, thanks for sharing.

 

I am testing the script but continually get an error after OneDrive launches:

 

Sorry, OneDrive can't add your folder right now. Please try again.

 

Have you come across this? I attached the error message as well

 

Thanks

 

@JesseBoehm You will likely need to define your WebID in the script as the OP does not have that value defined in the script above

 

I was able to use this script with the additional modifications:

 

$WebID = ""

(you will need to supply the GUID for your specific WebID inside the quotes)

 

and then modify the odopen command to include the addition of the WebID:

 

I was unable to use the DomainServer, User, and UserEmail variables as we do not have RSAT for Active Directory deployed to all systems across our environment which is required to run the Get-ADUser command after loading the module in the script.

 

because of this I modified those areas to function differently. this is what I got working:

# Script for using OneDrive, with on-demand enabled, to sync SPO library at login

# Create a shortcut to this script in the user's Startup folder
# Target should be C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -File "\\server\share\SyncSPOSite.ps1"

# Update variables below for the SPO library to sync. See this link for more info
# https://docs.microsoft.com/en-us/onedrive/deploy-on-windows?redirectSourcePath=%252fen-us%252farticle%252fdeploy-the-new-onedrive-sync-client-in-an-enterprise-environment-3f3a511c-30c6-404a-98bf-76f95c519668

$WebURL = "https://tenantname.sharepoint.com/sites/"
$SiteName = "MySiteName"
$SiteID = "{my Site GUID}"
$WebID = "{my Web GUID}"
$ListID = "{my List GUID}"

# Give Windows some time to load before getting the email address
Start-Sleep -s 20

$UserName = $env:USERNAME
$Domain = "@yourdomain.com"

# Use a "Do" loop to check to see if OneDrive process has started and continue to check until it does

Do{
    # Check to see if OneDrive is running
    $ODStatus = Get-Process onedrive -ErrorAction SilentlyContinue
    
    # If it is start the sync. If not, loopback and check again
    If ($ODStatus) 
    {
        # Give OneDrive some time to start and authenticate before syncing library
        Start-Sleep -s 30

        # set the path for odopen
        $odopen = "odopen://sync/?siteId=" + $SiteID + "&webId=" + $WebID + "&webUrl=" + $webURL + $SiteName + "&listId=" + $ListID + "&userEmail=" + $UserName + $Domain + "&webTitle=" + $SiteName + ""
        
        #Start the sync
        Start-Process $odopen
    }
}
Until ($ODStatus)

There is probably a better way to pull the domain without the RSAT toolset, I just don't know it and this worked for the environment I plan on using it in.

 

-Jeremy

This looks very promising! Does anyone have any insight on how to modify for AzureAD users? I am specifically looking at deploying this via Intune, likely via an .intunewin file that calls a Powershell script (Intune's Win32 App package)

I have had some inconsistencies with the script and have made the following changes that seem to work very well in my environment. 

 

Change the following: 

$DomainServer = $env:LOGONSERVER.Substring(2) + '.' + $env:USERDNSDOMAIN
$UserName = $env:USERNAME

to:

$DomainServer = [System.Net.Dns]::GetHostByName($env:LOGONSERVER.Substring(2)).HostName
$UserName = [Environment]::UserName

 

I will update the OP to reflect this change. 

Thank you @TonyBryant ! I found this tutorial which has a similar script methodology for synching Sharepoint sites:

https://youtu.be/Zoac9lbUuG0?t=1050

 

It uses "whoami /upn" to set the UPN variable, which seems to be working for AzureAD accounts:

$userUPN= cmd /c "whoami /upn"

 

Their script is hosted on GitHub and seems to work well:

https://github.com/tabs-not-spaces/CodeDump/blob/master/Sync-SharepointFolder/Sync-SharepointFolder....

However it may be a bit more complex than is needed with the Error and Success messages being returned. For my purposes having the script run silently is best, so I will likely be using a combo of code from your script and the Intune Training Channel folks.

 

I have been working on deploying Sharepoint site synchronizations via Intune as a Win32App. Intune does have a feature for mapping Sharepoint sites, but it's ridiculously slow. It takes anywhere from 8 hours to 5 days before the libraries show up on the computer as Synched.

We got the script working well following the instructions of jsmithianasher. The only issue now is that with every login after the first one you get the message that library is already synced. Is there a way to check if it is synced first before syncing it?
@TonyBryant great article, thank you for this. Is there anyway to use this to sync specific folders within a document library or does it only work for syncing the entire library?

@TonyBryant  Great Script, this is the only one I have actually got to work :lol:

 

However I'm running into an issue and hope anyone here can help. When I run the script, a OneDrive sign in prompt pops up and the script will not complete unless the Sign In button is pressed. Does anyone know how to silently sign in?

 

NPerez930_0-1649716014576.png

 

 

@NPerez930 

Same problem here. Did you ever figure it out?

@JamesWood @NPerez930 I found a solution to this problem. This happens when you have an outdated version of the OneDrive sync client installed on your VDI image. This causes the OneDrive client to self-update, instead of silently logging the user in. Update to the latest version of the OneDrive client on your VDI gold image to fix this problem.

In my case, I'm not using VDI; I'm testing this manually on my physical system before deploying via GPO. We have the latest OneDrive installed via Microsoft 365.
Make sure you have enabled the GPO entitled "Silently sign in users to the OneDrive sync app with their Windows credentials"

@MikeG4936 

Using the libraries already installed, this should work.

$SysInfo = New-Object -ComObject "ADSystemInfo"
$UserDN = $SysInfo.GetType().InvokeMember("UserName", "GetProperty", $Null, $SysInfo, $Null)
$User = [ADSI]"LDAP://$UserDN"
$User.Mail

Actually, this script returns an object that has all the active properties for the user.