Feb 212018
 

I plagiarized David Ott’s script for migration of Citrix Profile Manager (UPM) profiles to FSLogix and created it for Local Profiles.

NOTE: This only works between like profile versions.  eg. You can’t migrate your 2008R2 profiles to Server 2016 and expect it to work.  See this chart.

This requires using frx.exe, which means that FSLogix needs to be installed on the server that contains the profiles. The script will create the folders in the USERNAME_SID format, and set all proper permissions.

Use this script. Edit it. Run it (as administrator) from the Citrix server. It will pop up this screen to select what profiles to migrate.

  29 Responses to “FSLogix Local Profiles Migration Script”

  1. But then how do you attached this VHD to the user.


  2. #########################################################################################
    # Setup Parameter first here newprofile oldprofile subfolder1 subfolder2
    # Requires -RunAsAdministrator
    #########################################################################################
    # Example from my UPM Path "\\path_to_your_share\username\2012R2\UPM_Profile"
    # fslogix Root profile path
    $newprofilepath = "\\path_to_your_share\FSLogix"
    # UPM Root profile path
    $oldprofilepath = "\\path_to_your_share\UPM\Userprofiles"
    # Subfolder 1 - First Path to UPM_Profile Folder in UPM Profiles - see my example above
    $subfolder1 = "2012R2"
    # Subfolder 2 - First Path to UPM_Profile Folder in UPM Profiles - see my example above
    $subfolder2 = "UPM_Profile"

    #########################################################################################
    # Do not edit here
    #########################################################################################
    $oldprofiles = gci $oldprofilepath | select -Expand fullname | sort | out-gridview -OutputMode Multiple -title "Select profile(s) to convert"| %{
    Join-Path $_ $subfolder1\$subfolder2
    }

    foreach ($old in $oldprofiles) {
    $sam = Split-Path ($old -split $subfolder1)[0] -leaf
    $sid = (New-Object System.Security.Principal.NTAccount($sam)).translate([System.Security.Principal.SecurityIdentifier]).Value
    $regtext = "Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$sid]
    "ProfileImagePath"="C:\\Users\\$sam"
    "FSL_OriginalProfileImagePath"="C:\\Users\\$sam"
    "Flags"=dword:00000000
    "State"=dword:00000000
    "ProfileLoadTimeLow"=dword:00000000
    "ProfileLoadTimeHigh"=dword:00000000
    "RefCount"=dword:00000000
    "RunLogonScriptSync"=dword:00000000
    "

    $nfolder = join-path $newprofilepath ($sam+"\"+$sid+"_"+$sam)
    if (!(test-path $nfolder)) {New-Item -Path $nfolder -ItemType directory | Out-Null}
    & icacls $nfolder /setowner "$env:userdomain\$sam" /T /C
    & icacls $nfolder /grant $env:userdomain\$sam:(OI)(CI)F /T
    $vhd = Join-Path $nfolder ("Profile_"+$sam+".vhdx")

    $script1 = "create vdisk file="$vhd" maximum 30720 type=expandable"
    $script2 = "sel vdisk file=
    "$vhd"rnattach vdisk"
    $script3 = "sel vdisk file=
    "$vhd"rncreate part primrnselect part 1rnformat fs=ntfs quick"
    $script4 = "sel vdisk file=
    "$vhd"rnsel part 1rnassign letter=T"
    $script5 = "sel vdisk file
    "$vhd"rndetach vdisk"
    $script6 = "sel vdisk file=
    "$vhd"rnattach vdisk readonly"rncompact vdisk"

    if (!(test-path $vhd)) {
    $script1 | diskpart
    $script2 | diskpart
    Start-Sleep -s 5
    $script3 | diskpart
    $script4 | diskpart
    & label T: Profile-$sam
    New-Item -Path T:\Profile -ItemType directory | Out-Null

    start-process icacls "T:\Profile /setowner SYSTEM"
    Start-Process icacls -ArgumentList "T:\Profile /inheritance:r"
    $cmd1 = "T:\Profile /grant $env:userdomain\$sam:(OI)(CI)F"
    Start-Process icacls -ArgumentList "T:\Profile /grant SYSTEM
    :(OI)(CI)F"
    Start-Process icacls -ArgumentList "T:\Profile /grant Administrators:(OI)(CI`)F"
    Start-Process icacls -ArgumentList $cmd1
    } else {

    $script2 | diskpart
    Start-Sleep -s 5
    $script4 | diskpart
    }

    "Copying $old to $vhd"
    & robocopy $old T:\Profile /E /Purge /r:0 | Out-Null

    if (!(Test-Path "T:\Profile\AppData\Local\FSLogix")) {
    New-Item -Path "T:\Profile\AppData\Local\FSLogix" -ItemType directory | Out-Null
    }

    if (!(Test-Path "T:\Profile\AppData\Local\FSLogix\ProfileData.reg")) {$regtext | Out-File "T:\Profile\AppData\Local\FSLogix\ProfileData.reg" -Encoding ascii}
    $script5 | diskpart
    }

  3. to be sure, our Users where saved only with the SAMAccount Name without Domain

  4. PS C:\Windows\system32> C:\Users\adm-bart.FSL0\Desktop\fslogix migration.ps1
    processed file: \\zvb-file\profilecontainer$\adm-johan
    Successfully processed 1 files; Failed processing 0 files
    processed file: \\zvb-file\profilecontainer$\adm-johan
    Successfully processed 1 files; Failed processing 0 files

    .

    Formatting volume: \\?\Volume{5b18bc11-649f-4531-806f-b61c2b926584}\
    Copying profile for user S-1-5-21-1722534631-683760180-1736066318-1402 to volume \\?\Volume{5b18bc11-649f-4531-80
    6f-b61c2b926584}\
    Exit code: 9
    Error copying profile (0x0000001D): The system cannot write to the specified device.

  5. same problem

  6. Same issue here. Getting Error copying profile (0x0000001D)

  7. I’m also getting the 0x0000001D error. I also tried to copy the profile to the local disk (Windows 10 1903 on VMware) but this failed with the same error.

  8. The 0x0000001D error can be ignored.
    Within the user’s “AppData\Local\Microsoft\WindowsApps” folder there is a file called MicrosoftEdge.exe and also a subfolder “Microsoft.MicrosoftEdge_…” that also contains a file called MicrosoftEdge.exe, both with the size of 0 bytes.
    The frx tool uses robocopy to transfer the profile into the newly created container but fails to read/write one of those exe files mentioned above. This causes the 0x0000001D error.
    But aside from that robocopy copies the whole profile. Therefore it should be usable.

  9. If the folder “AppData\Local\Microsoft\WindowsApps” is deleted before using frx to migrate the profile then frx succeeds and the VHDX file is properly created and its security settings can be modified accordingly afterwards.

    I logged on with that user’s profile to assure that deleting the “WindowsApps” folder hasn’t any negative effect on the profile. Microsoft Edge starts without any errors, so deleting that folder doesn’t seem to have any negative impactso far.

    Maybe this does help you folks to get the migration of the profiles up and running.

  10. How would one execute this command remotely to migrate 100’s of users profiles from their persistent VDI to an FSLogix Share?
    I am a Newbie when it comes to Powershell.

  11. Any way we could use this to just migrate a named local user profile to VHD?

  12. Sorry didn’t look at the script very well and see the Out-GridView command – have changed it to set the variable to $ENV:USERNAME and it works for me.

  13. How can we do this from login as the logged in user as a batch?
    Was thinking of using
    frx create-vhd -filename=
    and frx.exe copy-profile -filename $vhd -sid $sid

  14. I’m dealing with Windows roaming profiles, and moving away from Citrix to Windows Virtual Desktop in Azure. The script will mount the Azure Files share and convert all profiles within a given path then place the FS Logix profile in the given Azure Files share.

    Modified the script to place the converted profiles in an Azure Files share.
    There are some optional areas for the drive mount, etc – edit as needed.
    Changed the split on line 43 since I’m dealing with username.v4, etc.
    Removed the option to select which profiles to convert
    Removed comments regarding the option to choose profiles to convert

    Modify lines:
    2, 6, 9, 21, 22 and 26 (as needed)

    #Requires -RunAsAdministrator
    $connectTestResult = Test-NetConnection -ComputerName StorageAccountName.file.core.windows.net -Port 445
    if ($connectTestResult.TcpTestSucceeded) {
    # Save the password so the drive will persist on reboot
    # Modify STORAGEACCOUNTNAME and Storage-Account-Access-Key
    cmd.exe /C “cmdkey /add:"STORAGEACCOUNTNAME.file.core.windows.net” /user:"Azure\STORAGEACCOUNTNAME” /pass:"Storage-Account-Access-Key“”
    # Mount the drive
    # Modify the StorageAccountName & Share-Name
    New-PSDrive -Name Z -PSProvider FileSystem -Root “\\StorageAccountName.file.core.windows.net\Share-Name” -Persist
    } else {
    Write-Error -Message “Unable to reach the Azure storage account via port 445. Check to make sure your organization or ISP is not blocking port 445, or use Azure P2S VPN, Azure S2S VPN, or Express Route to tunnel SMB traffic over a different port.”
    }

    # fslogix profile path
    $newprofilepath = “Z:\Azure-Files-Shared-Folder-Name” ##### FSLogix Root Profile Path
    $oldprofiles = get-childitem -path c:\temp\test | select name
    # foreach old profile
    foreach($old in $oldprofiles)
    {
    $sam = ($old.Name.Split(“.”))[0]
    $sid = (New-Object System.Security.Principal.NTAccount($sam)).translate([System.Security.Principal.SecurityIdentifier]).Value

    $regtext = “Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$sid]
    "ProfileImagePath“="C:\\Users\\$sam
    "FSL_OriginalProfileImagePath“="C:\\Users\\$sam
    "Flags“=dword:00000000
    "State“=dword:00000000
    "ProfileLoadTimeLow“=dword:00000000
    "ProfileLoadTimeHigh“=dword:00000000
    "RefCount“=dword:00000000
    "RunLogonScriptSync“=dword:00000000

    $nfolder = join-path $newprofilepath ($sid+”_”+$sam) ##### See note above
    # if $nfolder doesn’t exist – create it
    if (!(test-path $nfolder)) {New-Item -Path $nfolder -ItemType directory | Out-Null}
    & icacls $nfolder /setowner “$env:userdomain\$sam” /T /C
    & icacls $nfolder /grant $env:userdomain\$sam:(OI)(CI)F /T
    # sets vhd to \\nfolderpath\profile_username.vhd
    $vhd = Join-Path $nfolder ("Profile_"+$sam+".vhd")
    # diskpart commands
    $script1 = "create vdisk file=
    “$vhd" maximum 30720 type=expandable"
    $script2 = "sel vdisk file=
    “$vhd"rnattach vdisk"
    $script3 = "sel vdisk file=
    “$vhd"rncreate part primrnselect part 1rnformat fs=ntfs quick"
    $script4 = "sel vdisk file=
    “$vhd"rnsel part 1rnassign letter=T"
    $script5 = "sel vdisk file
    “$vhd"rndetach vdisk"
    $script6 = "sel vdisk file=
    “$vhd"rnattach vdisk readonlyrncompact vdisk”

    if (!(test-path $vhd)) {
    $script1 | diskpart
    $script2 | diskpart
    Start-Sleep -s 5
    $script3 | diskpart
    $script4 | diskpart
    & label T: Profile-$sam
    New-Item -Path T:\Profile -ItemType directory | Out-Null
    # set permissions on the profile
    start-process icacls “T:\Profile /setowner SYSTEM”
    Start-Process icacls -ArgumentList “T:\Profile /inheritance:r”
    $cmd1 = “T:\Profile /grant $env:userdomain\$sam:(OI)(CI)F"
    Start-Process icacls -ArgumentList "T:\Profile /grant SYSTEM
    :(OI)(CI)F”
    Start-Process icacls -ArgumentList “T:\Profile /grant Administrators:(OI)(CI`)F”
    Start-Process icacls -ArgumentList $cmd1
    } else {
    # if the vhd does exist then attach, wait 5 seconds, assign letter T
    $script2 | diskpart
    Start-Sleep -s 5
    $script4 | diskpart
    }

    # copies in the UPM profile to the Profile directory on the vhd /E /Purge – this is so it will update with the latest info
    “Copying $old to $vhd”
    & robocopy $old T:\Profile /E /Purge /r:0 | Out-Null
    # creates the %localappdata%\FSLogix path if it doesnt exist
    if (!(Test-Path “T:\Profile\AppData\Local\FSLogix”)) {
    New-Item -Path “T:\Profile\AppData\Local\FSLogix” -ItemType directory | Out-Null
    }
    # creates the profiledata.reg file if it doesn’t exist
    if (!(Test-Path “T:\Profile\AppData\Local\FSLogix\ProfileData.reg”)) {$regtext | Out-File “T:\Profile\AppData\Local\FSLogix\ProfileData.reg” -Encoding ascii}
    $script5 | diskpart
    }

  15. How would one do this from VMware Horizon persistent disks to FSLogix Profiles?

    • I’m not familiar with Horizon persistent disks, sadly. Jump into the IRC channel at join.citrixirc.com and perhaps one of the other guys knows the answer.

  16. Hey,
    really nice scripts. But I need help for the first one, who migrate profiles from Citrix profile manager to vhdx.

    I want to migrade 2012r2 profiles to vhdx, but I get everytime that error:

    Error copying profile (0x00000002): The system cannot find the file specified.

    The newest version of FSlogix is intalled. I run the script on a 2012r2 Citrix server.
    Do you have any idea of that?
    Thanks

    • First one? Do you mean this article? http://www.citrixirc.com/?p=848

      • Thanks for the very fast response.

        I talk from that script with the popup:

        #### EDIT ME
        $newprofilepath = “\\domain.com\share\path”

        #### Don’t edit me
        $ENV:PATH=”$ENV:PATH;C:\Program Files\fslogix\apps\”
        $oldprofiles = gci c:\users | ?{$_.psiscontainer -eq $true} | select -Expand fullname | sort | out-gridview -OutputMode Multiple -title “Select profile(s) to convert”

        # foreach old profile
        foreach ($old in $oldprofiles) {

        $sam = ($old | split-path -leaf)
        $sid = (New-Object System.Security.Principal.NTAccount($sam)).translate([System.Security.Principal.SecurityIdentifier]).Value

        # set the nfolder path to \\newprofilepath\username_sid
        $nfolder = join-path $newprofilepath ($sam+”_”+$sid)
        # if $nfolder doesn’t exist – create it with permissions
        if (!(test-path $nfolder)) {New-Item -Path $nfolder -ItemType directory | Out-Null}
        & icacls $nfolder /setowner “$env:userdomain\$sam” /T /C
        & icacls $nfolder /grant $env:userdomain\$sam:(OI)(CI`)F /T

        # sets vhd to \\nfolderpath\profile_username.vhdx (you can make vhd or vhdx here)
        $vhd = Join-Path $nfolder (“Profile_”+$sam+”.vhdx”)

        frx.exe copy-profile -filename $vhd -sid $sid
        }

        It starts to create the vhdx file and at the end the error message comes and the profile disc is gone.

  17. Hello,

    Script is working well.

    We encountered a Problem with Send to One Note Printer. It is not working anymore after Profile Migration.

    Any suggestions are welcome.

    THX

  18. Hi All,

    I am running FSLogix already and profiles are in VHD. Now we are moving from one domain to another. So profile will have to be migrated from domainA.com to domainB.com. Can we do it via any script?

    • That’s a tough one. It could be, but you’d have to map the users from one domain to another and figure out how to reset the permissions and owner on the files/directories for each user.

  19. […] There is already a good article posted on this website for those who want to use the original script from David Ott:FSLogix Local Profiles Migration Script […]

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

(required)

(required)

This site uses Akismet to reduce spam. Learn how your comment data is processed.