• Uncategorized
  • 5

Updated 2018-07 – Migrate homefolders to OneDrive

(And updated again 2018-09-07 with new Add-OneDriveSecondaryAdmin.ps1 script)

Microsoft recently released GA-version of SharePoint Migration Tool (SMT) and the version is now 2.1.

I had to update the blog post that I did a while ago with the new version of SMT and try to simply explain how we can migrate from our homefolders (homedirectories) to OneDrive.

Let’s begin!


On the machine that will handle the migration – install the following:

Then create a TXT file with the UserPrincipalName attribute for the users you want to migrate. Change the Filtering or SearchBase value after your environment. Here I will use my “OneDrive for Business Users” Security Group.

$users = Get-ADGroupMember -Identity "OneDrive for Business Users" | Get-ADUser | select -ExpandProperty UserPrincipalName
$users | Out-File C:\temp\Users.txt -NoClobber utf8

This file will be used the the BulkEnqueueOneDriveSite.ps1 script.

Then we have a total of three PowerShell scripts what we need to use.
(Please read them and understand them!)

The first script makes a pre-provisioning for each user’s OneDrive. Microsoft does not allocate space for the user until you start OneDrive (via the web or the client installed on the computer), but with the help of the script, administrators can do this.

Run .\BulkEnqueueOneDriveSite.ps1 -SPOAdminUrl <URL to SharePoint Admin> -InputFilePath <Path to Users.txt>

Then you need to enter an Global or SharePoint Admin account and password.

SetOneDriveAdminPermission.ps1 OR Add-OneDriveSecondaryAdmin.ps1
The second script sets an optional Global Admin as an additional administrator for each user’s OneDrive. If we don’t, we cannot migrate from home directory to the user’s OneDrive using the SharePoint Migration Tool.

If we want to use my new updated script (Add-OneDriveSecondaryAdmin.ps1) we need to specify the Users.txt file with users UPN.

Please edit the script to fit your tenant!

The third script retrieves the OneDrive security group and its members, then sets the members’ home directories to “Read” instead of “Full Control” so no changes are made during the migration phase.

Change the script to fit your environment!


 This script adds an entry for each user specified in the input file 
 into the OneDrive provisioning queue.
 This script reads a text file with a line for each user. 
 Provide the User Principal Name of each user on a new line.
 An entry will be made in the OneDrive provisioning queue for each
 user up to 200 users.


 .\BulkEnqueueOneDriveSite.ps1 -SPOAdminUrl https://contoso-admin.sharepoint.com -InputfilePath C:\users.txt 

 The URL for the SharePoint Admin center

.PARAMETER InputFilePath
 The path to the input file.
 The file must contain 1 to 200 users

 This script needs to be run by a SharePoint Online Tenant Administrator
 This script will prompt for the username and password of the Tenant Administrator

    #Must be SharePoint Administrator URL
    [Parameter(Mandatory = $true)]
    [string] $SPOAdminUrl,
    [Parameter(Mandatory = $true)]
    [string] $InputFilePath

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles") | Out-Null

$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SPOAdminUrl)

$Users = Get-Content -Path $InputFilePath

if ($Users.Count -eq 0 -or $Users.Count -gt 200)
    Write-Host $("Unexpected user count: [{0}]" -f $Users.Count) -ForegroundColor Red

$web = $ctx.Web
Write-Host "Please enter a Tenant Admin username" -ForegroundColor Green
$username = Read-Host

Write-Host "Please enter your password" -ForegroundColor Green
$password = Read-Host -AsSecureString

$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username,$password )

$loader = [Microsoft.SharePoint.Client.UserProfiles.ProfileLoader]::GetProfileLoader($ctx)


Write-Host "Script Completed"

#Set LogfilePath
$LogFilePath = "C:\Users\Administrator\Desktop\AdminUpdate-$(get-date -uformat '%Y-%m-%d-%H_%M').csv"


#Set Variables- AdminUPN must be a global admin account
$secondaryadmin1 = "admin@contoso.onmicrosoft.com"
#$secondaryadmin2 = "admin2@contoso.onmicrosoft.com"


$Credential = Get-Credential -UserName $adminUPN -Message "User Must be a Global Admin"
Connect-SPOService -Url https://$TennantName-admin.sharepoint.com $credential

# Specify your organisation admin central url

$AdminURI = "https://$TennantName-admin.sharepoint.com"
$siteURI = "https://$TennantName-my.sharepoint.com"

$loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
$loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")

$creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials ($credential.UserName, $credential.Password)

# Add the path of the User Profile Service to the SPO admin URL, then create a new webservice proxy to access it

$proxyaddr = "$AdminURI/_vti_bin/UserProfileService.asmx?wsdl"
$UserProfileService= New-WebServiceProxy -Uri $proxyaddr -UseDefaultCredential False
$UserProfileService.Credentials = $creds

# Set variables for authentication cookies

$strAuthCookie = $creds.GetAuthenticationCookie($AdminURI)
$uri = New-Object System.Uri($AdminURI)
$container = New-Object System.Net.CookieContainer
$container.SetCookies($uri, $strAuthCookie)
$UserProfileService.CookieContainer = $container

# Sets the first User profile, at index -1

$UserProfileResult = $UserProfileService.GetUserProfileByIndex(-1)
Write-Output "Starting- This could take a while."
$NumProfiles = $UserProfileService.GetUserProfileCount()
$i = 1

# As long as the next User profile is NOT the one we started with (at -1)...

While ($UserProfileResult.NextValue -ne -1)


Write-Output "Examining profile $i of $NumProfiles"

"Examining profile $i of $NumProfiles" | Out-File $LogFilePath -Append

# Look for the Personal Space object in the User Profile and retrieve it

# (PersonalSpace is the name of the path to a user's OneDrive for Business site.

# Users who have not yet created a OneDrive for Business site might not have this property set.)

$Prop = $UserProfileResult.UserProfile | Where-Object { $_.Name -eq "PersonalSpace" }

$Url= $Prop.Values[0].Value

# If OneDrive is activated for the user, then set the secondary admin

if ($Url) {

$sitename = $siteURI + $Url



  #If you change the $false to $true this will add a secondary user rather than remove it

    $temp1 = Set-SPOUser -Site $sitename -LoginName $secondaryadmin1 -IsSiteCollectionAdmin $true

    #$temp2 = Set-SPOUser -Site $sitename -LoginName $secondaryadmin2 -IsSiteCollectionAdmin $true

    Write-Output "Updated Secondary Admins for:" $sitename

    "Updated Secondary Admin for: $sitename" | Out-File $LogFilePath -Append


  catch [System.Exception]


   Write-Output $Error[0].Exception

   $Error[0].Exception| Out-File $LogFilePath -Append



# And now we check the next profile the same way...

$UserProfileResult = $UserProfileService.GetUserProfileByIndex($UserProfileResult.NextValue)



Write-Output "Completed assigning secondary admin to all users"

$users = Get-ADGroupMember -Identity "OneDrive for Business Users" | select SamAccountName
foreach ($user in $users){
    $HomeFolders = Get-ADUser $user.SamAccountName -Properties homedirectory | select Homedirectory
        foreach ($HomeFolder in $HomeFolders) {
            $Path = $HomeFolder.Homedirectory
            $Acl = (Get-Item $Path).GetAccessControl('Access')
            $Username = $user.SamAccountName
            $Ar = New-Object System.Security.AccessControl.FileSystemAccessRule($Username, 'Read', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
            Set-Acl -path $Path -AclObject $Acl
            Write-Host "Replacing $Username's Full Control permission to Read on $Path."

Instead of Set-OneDriveAdminPermission.ps1 you can use Add-OneDriveSecondaryAdmin.ps1

Migration Phase

Create a .CSV mapping file containing the path to the user’s home directory and URL to the user’s OneDrive. This is the only thing that needs to be changed. Note that no header should be included in the .CSV file.

Example of the mapping file:


Read more at Microsoft regarding format the CSV file: https://docs.microsoft.com/en-us/sharepointmigration/how-to-format-your-csv-file-for-data-content-migration

Script to create the .CSV mapping file.

$users = Get-Content .\users.txt
$tenantname = "Contoso"

foreach($user in $users){
   $TOCsv = Get-ADUser -Filter {UserPrincipalName -eq $user} -properties homedirectory | select UserPrincipalName, Homedirectory
   $user = $user.Replace('@','_')
   $user = $user.Replace('.','_')
   Add-Content .\BulkUsers.csv "$($ToCSV.Homedirectory),,,https://$tenantname-my.sharepoint.com/personal/$user/,Documents,"


ii .\BulkUsers.csv

Double check that the CSV file looks correct!
Try to take one of the user’s OneDrive URL and when logged in with the Global Admin/SharePoint Admin account specified in the second script, try to reach the user’s OneDrive. If this has been done and you can access the URL, then everything is set.

Start the SharePoint Migration Tool and make sure you use the latest version of the tool. At writing the version is

with your Global Admin account for the tenant.
Choose “JSON or CSV file for bulk migration

Locate the file created in the previous script. Then click Add and the tool will check the contents of the file. If there are any errors in the file, the tool will say which row that is wrong or if you don’t have permissions to users OneDrive (Error message: Task NO. #1, You are not SharePoint Online Admin User).

If everything is correct, you will proceed to the next step.

Click Migrate and wait until migration is complete.

You’re all DONE!

Don’t forget to remove your Global Admin account from everyone’s OneDrive, just edit Set-OneDriveAdminPermission.ps1 script and set the IsSiteCollectionAdmin to $false.

$temp1 = Set-SPOUser -Site $sitename -LoginName $secondaryadmin1 -IsSiteCollectionAdmin $false

#$temp2 = Set-SPOUser -Site $sitename -LoginName $secondaryadmin2 -IsSiteCollectionAdmin $false

You may also like...

5 Responses

  1. Per says:

    Thanks for the article, been very helpful.
    I’m curious as to why you chose to not use PowerShell for the last part?

    I alos recieve an error when trying to run the GUI part, Invalid SharePoint Online list. I haven’t been able to find anything regarding this error.

    • thoor says:

      You’re welcome! I think the SharePoint Migration Tool is quite a good tool and you can do an incremental transfer also. Are you able to access the users OneDrive URL? Does the CSV file look correct?

  1. September 1, 2018

    […] UPDATED POST for migrating homefolders to OneDrive here: https://thoor.tech/2018/07/updated-2018-07-migrate-homefolders-to-onedrive/ […]

Leave a Reply to Dimitri Redant Cancel reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: