Oct 242017
 

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.

I moved from UPM to FSLogix earlier this year, and decided to write my own powershell script to convert the UPM profiles to .vhd.  FSLogix has its own conversion process (which I didn’t find a whole lot of info on), but I decided to create my own.

What this script does:

  1. Gets a list of all UPM profile directories in the root path (that you supply) and displays them to you to select which one(s) you would like to convert via out-gridview
  2. For each profile you select:
    1. Gets the username from the profile path – you will have to edit this part for your environment… explanation in the script
    2. Use the username to get the SID (FSLogix profiles use the username and sid to name the profile folder)
    3. Creates the FSLogix profile folder (if it doesn’t exist)
    4. Sets the user as the owner of that folder, and gives them full control
    5. Creates the .vhd (my default is 30GB dynamic – edit on line 70 if you wish to change it) – if it doesn’t exist (if it does skip 7, 9-10)
    6. Attaches the .vhd
    7. Creates a partition and formats it ntfs
    8. Assigns the letter T to that drive (edit on line 73 if you wish to change that)
    9. Creates the T:\Profile directory
    10. Grants System/Administrators and the user full control of the profile directory
    11. Copies the profile from the UPM path to the T:\Profile directory with /E /Purge – if you are re-running this script on a particular profile it will overwrite everything fresh
    12. Creates T:\Profile\AppData\Local\FSLogix if it doesnt exist
    13. Creates T:\Profile\AppData\Local\FSLogix\ProfileData.reg if it doesn’t exist (this feeds the profilelist key at logon)

Here is the script!

  14 Responses to “Citrix UPM Profiles to FSLogix Profiles Conversion Powershell Script”

  1. Hi David,

    I´m trying to migrate some UPM profiles to FSLogix profiles with your script but I cannot get further. I´ve edit the $newprofilepath and $oldprofile variable as needed for our environment, but I do not get any respsone from the script. Actually nothing happens. In general I just want to ask you for help.

    Regards
    Martin

    • Martin there is more to it than just changing the $newprofilepath and the $oldprofiles variables. Read through the commented sections.

  2. […] some research I choose to try out a script created by David Ott. You can check the original post here, or on the FSLogix […]

  3. […] Citrix UPM Profiles to FSLogix Profiles Conversion Powershell Script […]

  4. How does the User profile know which disk to attached. Could you please clarify.

  5. $sid = (New-Object System.Security.Principal.NTAccount($sam)).translate([System.Security.Principal.SecurityIdentifier]).Value

    reports:

    New-Object : Ausnahme beim Aufrufen von “.ctor” mit 1 Argument(en): “Die Zeichenfolge kann keine Länge von 0 (null)
    haben.
    Parametername: name”
    In C:\batch\Migrate.ps1:43 Zeichen:9
    + $sid = (New-Object System.Security.Principal.NTAccount($sam)).transla …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

    Any Ideas? I´m stucked at the moment and can´t find the error.

    Without this $sid I get a profile-folder called “_” and a “Profile.vhd”

    Is it possible to create VHDX instea of VHD?

    Thanks a lot
    Marc


  6. #########################################################################################
    # Setup Parameter first here newprofile oldprofile subfolder1 subfolder2
    # Requires -RunAsAdministrator
    # My Userprofiles come only with SAMAccount Name without Domain "\Username\2012R2\UPM_Profile
    #########################################################################################
    # 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`"`r`nattach vdisk"
    $script3 = "sel vdisk file=`"$vhd`"`r`ncreate part prim`r`nselect part 1`r`nformat fs=ntfs quick"
    $script4 = "sel vdisk file=`"$vhd`"`r`nsel part 1`r`nassign letter=T"
    $script5 = "sel vdisk file`"$vhd`"`r`ndetach vdisk"
    $script6 = "sel vdisk file=`"$vhd`"`r`nattach vdisk readonly`"`r`ncompact 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
    }

    • Thank you so much. Your script worked. However, when I run the script, the end result is “Profile_Username.vhdx”. is there a way i can modify the script so that end result is “Username.vhdx”? without the “Profile_”?
      Thanks

  7. The script works fine, except at the permissions files/ownership.

    On Windows, the ownership of the users folder are Administrators, after that, it is the user for subfolders+files.
    With FSLogix, is it SYSTEM not administrators, the same thing, the user is owner.

    With the original script, the owner is the group administrators, not the user. I had errors on loading ntuser.dat, folder desktop,etc.
    I moved the line about Removing the inheritance (T:\profile), looks it breaks some permissions while copying, the logic we should add permissions before removing ?

    Robocopy copy attributes don’t work well (/DATO, /DATSOU, etc.) on my testings, I wanted to copy the owner attribute, but i had some strange permissions added (user LogonsessionID).

    After the robocopy, I added a line to make the user full owner with the command /T, and then I change T:\profile’s owner as system.
    Also adding the user permissions after copying the files with /T to be recursive, sometimes, the user wasn’t included in the permissions (?)

    I modified a bit the script and it works now, it respects the permissions for the profile. It might look not optimized, but 100% covered. I don’t want to get support calls for profile users that failed on migration.

    $cmd1 = “T:\Profile /grant ${env:userdomain}\${sam}:(OI)(CI)F /T”
    $cmd2 = “T:\Profile /setowner ${env:userdomain}\${sam} /T”
    Start-Process icacls -ArgumentList “T:\Profile /grant SYSTEM:(OI)(CI)F”
    Start-Process icacls -ArgumentList “T:\Profile /grant Administrateurs:(OI)(CI)F”
    Start-Process icacls -ArgumentList “T:\Profile /inheritance:r”
    } 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

    Start-Process icacls -ArgumentList $cmd1
    start-process icacls -ArgumentList $cmd2
    start-process icacls “T:\Profile /setowner SYSTEM”

  8. Hi

    Please help me to fill this bit because my folder path do not have sub folders.

    My old UPD path: \\PNI-UPD-001\UPD
    New fslogix UPD path: \\UPD-2019-T01\Profiles

    So

    # Example from my UPM Path “\\path_to_your_share\username\2012R2\UPM_Profile” ???
    # fslogix Root profile path
    $newprofilepath = “\\UPD-2019-T01\Profiles”
    # UPM Root profile path
    $oldprofilepath = “\\PNI-UPD-001\UPD”
    # 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” ???

    Thank you.

    Dash

  9. Nice Blog man, Very nice!!

Leave a Reply to Franco Cancel reply

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

(required)

(required)

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