OneDrive for Business site (ODFB) is built on top of SharePoint Online (SPO). Users’ personal OneDrive site is nothing but a special site collection in SharePoint. If you have enough permission on the required user’s OneDrive site, you can do whatever operations (as like you can do with SPO site) in Powershell with the help of CSOM and SharePoint Online module. In this post, I am going to share CSOM based Powershell script to fetch documents from the local folder and upload it into a user’s OneDrive location.
Permissions Required:
By default, every user has full access permission on their personal OneDrive site. If you are going to upload it in your drive, then you don’t need extra permission. If you are going to upload files into another user’s OneDrive, then you should add yourself as a site collection admin of the particular user’s OneDrive site. Refer this post for more details: Add Site Collection Admin to OneDrive Users
Required details to upload files into OneDrive document library:
Before proceed you need to replace the following input parameters in the below script.
$LocalFolder – Specify your local folder path.
$AdminAccount – Provide admin user account.
$AdminPass – Provide admin password.
$OneDriveURL – User’s OneDrive site URL.
$TargetFolderName – OneDrive folder where you want to upload. Leave empty if you want to upload in the root folder. If you specify the target folder, then the folder should already exist in the OneDrive root folder.
Available Scripts
Upload local files into OneDrive folder
#Add required references to SharePoint client assembly to use CSOM
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
#Specify local folder path
$LocalFolder = "C:\Users\UserName\Documents\MyFiles"
#Specify the User account for an Office 365 global admin in your organization
$AdminAccount = "admin@<your tenant name>.onmicrosoft.com"
$AdminPass = "admin_password"
#Specify User's OneDrive Site URL and Folder name
$OneDriveURL = "https://<your tenant name>-my.sharepoint.com/personal/username_domainame_com"
$DocumentLibrary ="Documents"
$TargetFolderName ='' #Leave empty to target root folder
#Connect and Load OneDrive Library and Root Folder
$SecPwd = $(ConvertTo-SecureString $AdminPass -asplaintext -force)
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($OneDriveURL)
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminAccount,$SecPwd)
$Ctx.credentials = $Credentials
$List = $Ctx.Web.Lists.GetByTitle("$DocumentLibrary")
$Ctx.Load($List)
$Ctx.Load($List.RootFolder)
$Ctx.ExecuteQuery()
#Setting Target Folder
$TargetFolder = $null;
If($TargetFolderName) {
$TargetFolderRelativeUrl = $List.RootFolder.ServerRelativeUrl+"/"+$TargetFolderName
$TargetFolder = $Ctx.Web.GetFolderByServerRelativeUrl($TargetFolderRelativeUrl)
$Ctx.Load($TargetFolder)
$Ctx.ExecuteQuery()
if(!$TargetFolder.Exists){
Throw "$TargetFolderName - the target folder does not exist in the OneDrive root folder."
}
} Else {
$TargetFolder = $List.RootFolder
}
#Get files from local folder and Upload into OneDrive folder
$i = 1
$Files = (Dir $LocalFolder -File) # Read files only from root folder
#$Files = (Dir $LocalFolder -File -Recurse) # Read files both from root folder and all sub folders
$TotoalFiles = $Files.Length
ForEach ($File in $Files)
{
Try {
Write-Progress -activity "Uplading $File" -status "$i out of $TotoalFiles completed"
$FileStream = New-Object IO.FileStream($File.FullName,[System.IO.FileMode]::Open)
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $File
$Upload = $TargetFolder.Files.Add($FileCreationInfo)
$Ctx.Load($Upload)
$Ctx.ExecuteQuery()
}
catch
{
Write-Host $_.Exception.Message -Forground "Red"
}
$i++
}
Upload files recursively from local folder and subfolders with folder structure
You can use the following script to read files recursively from a local folder with a nested folder structure and upload files and subfolders into the given OneDrive folder with a complete folder hierarchy.
#Add required references to SharePoint client assembly to use CSOM
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
# Specify local folder path
$LocalFolder = "C:\Users\Username\Documents\MyFiles"
# Specify the User account for an Office 365 global admin in your organization
$AdminAccount = "admin@<your tenant name>.onmicrosoft.com"
$AdminPass = "admin_password"
# Specify User's OneDrive Site URL and Folder name
$OneDriveURL = "https://<your tenant name>-my.sharepoint.com/personal/username_domainame_com"
$DocumentLibrary ="Documents"
$TargetFolderName ='' #Leave empty to target root folder
#Connect and Load OneDrive Library and Root Folder
$SecPwd = $(ConvertTo-SecureString $AdminPass -asplaintext -force)
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($OneDriveURL)
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminAccount,$SecPwd)
$Ctx.credentials = $Credentials
$List = $Ctx.Web.Lists.GetByTitle($DocumentLibrary)
$Ctx.Load($List)
$Ctx.Load($List.RootFolder)
$Ctx.ExecuteQuery()
# Setting Target Folder
$TargetFolder = $null;
$TargetFolderRelativeUrl;
If($TargetFolderName) {
$TargetFolderRelativeUrl = $List.RootFolder.ServerRelativeUrl+"/"+$TargetFolderName
$TargetFolder = $Ctx.Web.GetFolderByServerRelativeUrl($TargetFolderRelativeUrl)
$Ctx.Load($TargetFolder)
$Ctx.ExecuteQuery()
if(!$TargetFolder.Exists){
Throw "$TargetFolderName - the target folder does not exist in the OneDrive root folder."
}
} Else {
$TargetFolder = $List.RootFolder
$TargetFolderRelativeUrl = $TargetFolder.ServerRelativeUrl
}
# Get folders and sub folders from source location
$folders= @()
foreach ($file in (Get-ChildItem -Recurse -Path $LocalFolder -Attributes Directory))
{
$folders +=($file.FullName).replace($LocalFolder+"\",'')
}
# Create folders and sub-folders in the destination location
Write-Progress -activity "Creating folder structure in OneDrive" -status "Creating Folder"
foreach ($folder in $folders)
{
$subfolder_names = $folder.split("\")
$subfolder = $TargetFolder.Folders.Add($subfolder_names[0])
$Ctx.Load($subfolder)
$Ctx.ExecuteQuery()
for ($i = 1; $i -le ($subfolder_names.Count-1) ; $i++)
{
$subfolder = $subfolder.folders.Add($subfolder_names[$i])
$Ctx.Load($subfolder)
$Ctx.ExecuteQuery()
}
}
# Read all files recursively from the local folder and upload them into the corresponding OneDrive folder.
$i = 1
$Files = (Dir $LocalFolder -File -Recurse)
$TotoalFiles = $Files.Length
ForEach($File in $Files)
{
Try {
$URL_Dest = $TargetFolderRelativeUrl +(($file.FullName).Replace($LocalFolder,'')).Replace("\","/")
Write-Progress -activity "Uplading $File" -status "$i out of $TotoalFiles completed"
$FileStream = New-Object IO.FileStream($File.FullName,[System.IO.FileMode]::Open)
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $URL_Dest
$Upload = $TargetFolder.Files.Add($FileCreationInfo)
$Ctx.Load($Upload)
$Ctx.ExecuteQuery()
}
catch {
Write-Host $_.Exception.Message -Forground "Red"
}
$i++
}
This doesn't seem to upload subfolders, or any files within subfolders.
Is there any way this can be achieved?
If you want to read files from local folder and sub folders, but upload all files into specified OneDrive directory, then you can just add -Recurse parameter while getting files.
Replace this line :
$Files = (Dir $LocalFolder -File)
With this line :
$Files = (Dir $LocalFolder -File -Recurse)
If you want to keep existing folder structure in OneDrive also, then I have added another set of commands for this case, you can refer the above post.
https://www.morgantechspace.com/2019/07/upload-files-into-onedrive-for-business-using-powershell.html#nestedfolder
I am getting problem while uploading large files more than 250 mb..can you help?
Thanks in advance
I am unable to select
$TargetFolderName ="backups" #Leave empty to target root folder
Always getting "the target folder not exist in OneDrive root folder."
how can we exclude some directories we dont want to copy to one drive
hi morgan, please can you help with my above queries, i see alot of object reference errors when using the above
Can you post the error to troubleshoot the issue.
Hello! Great Job! Is there any way to make the file shareable? As of now it is uploading but in private.
Thanks!
Works great, but I keep getting an error if I try to specify a target folder. I’ve ensured that the folder exists in the OneDrive root directory. Any thoughts?
Reports – the target folder does not exist in the OneDrive root folder.
At line:36 char:1
+ Throw “$TargetFolderName – the target folder does not exist in the OneDrive roo …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Reports – the t…ve root folder.:String) [], RuntimeException
+ FullyQualifiedErrorId : Reports – the target folder does not exist in the OneDrive root folder.
New-Object : Cannot find type [Microsoft.SharePoint.Client.ClientContext]: verify that the assembly containing this type is loaded.
At C:\Users\admin\Desktop\new_file_powershell.ps1:20 char:8
+ $Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($OneDrive …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
You cannot call a method on a null-valued expression.
At C:\Users\admin\Desktop\new_file_powershell.ps1:24 char:1
+ $Ctx.Load($List)
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Can you confirm the following commands loads the required assemblies.?
#Load required SharePoint client assemblies
[System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SharePoint.Client”)
[System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SharePoint.Client.Runtime”)