USMT
ConfigMgr 2012 R2 PowerShell to Install SMP Role
In a recent customer engagement, we needed to mass deploy the State Migration Point (SMP) role to nearly 70 servers. After completing about a dozen of these one by one, I thought PowerShell would be a much faster way to accomplish the end goal. The below script can be used as an example for finding existing site systems that do not have the SMP role installed, while allowing it to skip servers with certain names (in this example, it skips servers that begin with TEST in the name).
import-module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1') # Site Code + : $SiteCode = "GAL:" Set-Location $SiteCode #Properties for Setting the SMP Role $UsmtDrivePath = "F:\USMT" $MaxNumClients = 100 $MinFreeSpace = 3 $TimeDeleteAfterDays = 5 $SiteSystemServers = Get-CMSiteSystemServer write-host $SiteSystemServers.Count ForEach ($Server in $SiteSystemServers) { $ServerName = $Server.NetworkOSPath.Replace("\\", " ") $CheckSMP = Get-CMSiteRole -RoleName "SMS State Migration Point" -SiteSystemServerName $ServerName #write-host $CheckSMP.Count # If SMP Count is zero, SMP not installed If ($CheckSMP.Count -eq 0) { If ($ServerName.ToUpper().StartsWith("TEST")) { # Do Nothing, skip this type of server } Else { Write-host "No SMP Role, installing on" $ServerName $Folder = New-CMStorageFolder -StorageFolderName $UsmtDrivePath -MaximumClientNumber _ $MaxNumClients -MinimumFreeSpace $MinFreeSpace -SpaceUnit Gigabyte Add-CMStateMigrationPoint -SiteSystemServerName $ServerName -StorageFolder $Folder _ -AllowFallbackSourceLocationForContent $False -EnableRestoreOnlyMode $False -SiteCode $SiteCode _ -TimeDeleteAfter $TimeDeleteAfterDays -TimeUnit Days } } Else { Write-host "SMP Role installed, skipping server" $ServerName } }
Migrating .pst Files with USMT custom MigUser
A recent challenge I had with a USMT migration was to ensure that all .pst files could be migrated (or any file type for that matter). You may be asking how that is “challenging”. Well, a common best practice is to exclude unnecessary directory locations (such as C:\Drivers or C:\Temp), so what happens if the .pst file lives in that folder? Furthermore, if USMT using MigApp + MigUser, then program/system directories are excluded (such as user’s temp folders or C:\Windows), so what happens if the .pst file lives in that folder?
In either situation, if the .pst is actively connected to a user’s Outlook profile being migrated, then the .pst will also migrate. However, if the .pst is disconnected and lives in an excluded location, then it will not migrate. So this brings the challenge of how to migrate .pst files. The solution is to use a customized migration XML file, which in this example I am calling MigUserCustom.
MigUserCustom Code Snippet
<!-- This component migrates .PSTs except for ones on the network--> <component type="Documents" context="UserAndSystem"> <displayName>All PST files migrated from all fixed, no PST’s migrated from network, regardless of context or outlook registry catalog settings</displayName> <role role="Data"> <rules> <unconditionalExclude> <objectSet> <script>MigXmlHelper.GenerateDrivePatterns ("* [*.pst]", "Remote")</script> </objectSet> </unconditionalExclude> <unconditionalExclude> <objectSet> <pattern type="File">\\* [*.pst]</pattern> </objectSet> </unconditionalExclude> <include> <objectSet> <script>MigXmlHelper.GenerateDrivePatterns ("* [*.pst]", "Fixed")</script> </objectSet> </include> </rules> </role> </component>
If you would like to have a copy of the full MigUserCustom.xml to use an example, you can get it from my SkyDrive at http://sdrv.ms/Nf2X6a. An example USMT command line to use MigUserCustom may look like:
ScanState.exe /o "%CAPTURE_STORE_PATH%" /vsc /i:MigApp.xml /i:MigUser.xml /i:MigUserCustom.xml /config:Confiig.xml /localonly /l:"%CAPTURE_STORE_PATH%\scanstate.log" /listfiles:"%CAPTURE_STORE_PATH%\scanstatefiles.log" /v:13 /uel:90
Or if you have defined in an SCCM task sequence, be sure to add it as one of Configuration Files.
USMT workaround for BGInfo desktop wallpaper
If you use BGInfo on your computers and migrate a user’s profile to a new computer, you’ll soon discover that the BGInfo of the new computer is overlaying BGInfo from the old computer, creating a very ugly desktop wallpaper. The reason for this is that once BGInfo executes, it generates a new image from what the user had previously set for themselves. Fortunately, the original image file’s location is stored in the registry as well. The below script that I created is designed to run prior to USMT (while no user’s are logged into Windows). It essentially mounts each user’s registry hive, grabs the original file from the registry and then resets the Wallpaper value for that user.
There is one caveat to this process however. If within USMT you’ve set /uel:X to excludes user profiles older than X number of days, using this script will cause those profiles to now be recently logged into. So before using this script, be sure to cleanup any old user profiles that you do not want migrated.
'========================================================================== ' AUTHOR : Nick Moseley, https://t3chn1ck.wordpress.com ' COMMENT : This corrects a problem with migrating the BGInfo wallpaper vs. ' the user's actual wallpaperfile. This script will parse all User profiles ' on the computer, load their HKCU hive, then set the appropriate registry ' keys to reset a user's background image. ' HISTORY : ' 1.0 (06/23/2011) - Initial script ' 1.1 (02/20/2013) - Added Const LogFile to quickly define location '========================================================================== Option Explicit Const LogFile = "C:\Windows\Temp\ResetBGInfo.log" Const ForAppending = 8 Const HKLM = &H80000002 Const sReadUserKey = "Software\Winternals\BGInfo" Const sSetUserKey = "Control Panel\Desktop" Const sStringValueName = "Wallpaper" Dim oReg, oFSO, oFile, oUserSubkey, aUserProfiles, oShell Dim sProfileLCase, sRegExe, sRegLoad, sRegUnload, sHiveName, sSubPath, sProfile, sValueName, sKeyPathUserProfiles, sValue, ReturnVal Set oReg = GetObject("winmgmts:\\.\root\default:StdRegProv") Set oShell = CreateObject("WScript.Shell") Set oFSO = CreateObject ("Scripting.FileSystemObject") '========================================================================== ' Begin log file etnries '========================================================================== If Not oFSO.FileExists(LogFile) Then oFSO.CreateTextFile LogFile End If Set oFile = oFSO.OpenTextFile (LogFile, ForAppending, True) oFile.WriteLine "Reset BGInfo values for all users for USMT" oFile.WriteLine " => Began at " & Date & " " & Time oFile.WriteLine " => For each user profile, set " & sStringValueName & " (string) to the user's Wallpaper settings in HKCU\" & sSetUserKey '========================================================================== ' Begin configuration of existing user profiles sValueName = "ProfileImagePath" sKeyPathUserProfiles = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" sRegExe = "C:\Windows\system32\reg.exe" oReg.EnumKey HKLM, sKeyPathUserProfiles, aUserProfiles ' Existing User Profiles For Each oUserSubkey In aUserProfiles sSubPath = sKeyPathUserProfiles & "\" & oUserSubkey oReg.GetExpandedStringValue HKLM,sSubPath,sValueName,sValue sProfile = Split(sValue, "\") sProfileLCase = LCase(sProfile(2)) If sProfileLCase = "system32" Then 'oFile.WriteLine " => Skipped user profile: system32" ElseIf sProfileLCase = "localservice" Then 'oFile.WriteLine " => Skipped user profile: localservice" ElseIf sProfileLCase = "networkservice" Then 'oFile.WriteLine " => Skipped user profile: networkservice" ElseIf sProfileLCase = "serviceprofiles" Then 'oFile.WriteLine " => Skipped user profile: serviceprofiles" ElseIf sProfileLCase = "administrator" Then 'oFile.WriteLine " => Skipped user profile: administrator" Else sHiveName = "TempHive_" & sProfileLCase ' Load user's profile hive into a temp location sRegLoad = " LOAD HKLM\" & sHiveName & " """ & sValue & "\ntuser.dat""" oShell.Run sRegExe & sRegLoad, 0, True ' Call subroutine to change registry key SetConfigUserHive (sHiveName) ' Unload user's profile hive sRegUnload = " UNLOAD HKLM\" & sHiveName oShell.Run sRegExe & sRegUnload, 0, True End If Next ' End logging oFile.WriteLine " => Completed at " & Date & " " & Time WScript.Quit (oFile.Close) Sub SetConfigUserHive (sTempHive) Dim sTempHiveKeyPath, sTempHiveWallpaperKeyPath, sWallpaperFile ' Path of registry keys sTempHiveKeyPath = sTempHive & "\" & sReadUserKey sTempHiveWallpaperKeyPath = sTempHive & "\" & sSetUserKey ' Get BGInfo value oReg.GetStringValue HKLM, sTempHiveKeyPath, "Wallpaper", sWallpaperFile If sWallpaperFile="(None)" Or sWallpaperFile="" Then oReg.SetStringValue HKLM, sTempHiveWallpaperKeyPath, "Wallpaper", "" Else oReg.SetStringValue HKLM, sTempHiveWallpaperKeyPath, "Wallpaper", sWallpaperFile End If oFile.WriteLine " => Set user profile: " & sProfileLCase oFile.WriteLine " Note: Wallpaper value = " & sWallpaperFile End Sub
Workaround for KB2444193 with USMT 4
There is a known issue when migrating to Windows 7 with USMT. If a computer is deployed using an AutoUnattend.xml, then after migrating a user to the new computer, when the user launches IE they receive the message “A program on your computer has corrupted your default search provider…“. One workaround is to have a script correct the SearchScope GUIDs for each user profile. The script that I have written (below) simply mounts each user profile hive, then deletes the registry tree for the SearchScopes. The effect is that when the user first launches IE 8, then it will pull the default Search Provider from HKLM defined in the deployed computer via AutoUnattend.
'========================================================================== ' NAME: DeleteUserIESearchProviders ' AUTHOR: Nick Moseley, https://t3chn1ck.wordpress.com ' COMMENT: Mounts user registry hives and deletes the IE Search Provider ' registry values. This is to fix the issue caused by KB2444193 ' HISTORY: ' 1.0 (06/23/2011) - Initial Script '========================================================================== Option Explicit Const ForAppending = 8 Const HKLM = &H80000002 Const sUserKey = "Software\Microsoft\Internet Explorer\SearchScopes" Dim oReg, oFSO, oFile, oUserSubkey, aUserProfiles, oShell Dim sProfileLCase, sRegExe, sRegLoad, sRegUnload, sHiveName, sSubPath, sProfile, sValueName, sKeyPathUserProfiles, sValue, ReturnVal Set oReg = GetObject("winmgmts:\\.\root\default:StdRegProv") Set oShell = CreateObject("WScript.Shell") Set oFSO = CreateObject ("Scripting.FileSystemObject") ' Prompt if OK to continue Dim x x = msgbox ("Click OK to delete the IE Search Provider for all user profiles", vbOKCancel, "Fix IE Search Provider") If x<>1 Then WScript.Echo "Script Terminated" WScript.Quit End If '========================================================================== ' Begin log file etnries '========================================================================== If Not oFSO.FileExists("C:\DeleteSearchProvider.log") Then oFSO.CreateTextFile "C:\DeleteSearchProvider.log" End If Set oFile = oFSO.OpenTextFile ("DeleteSearchProvider.log", ForAppending, True) oFile.WriteLine "Delete IE Search Provider" oFile.WriteLine " => Began at " & Date & " " & Time oFile.WriteLine " => For each user profile, deleted HKCU\" & sUserKey '========================================================================== ' Begin configuration of existing user profiles sValueName = "ProfileImagePath" sKeyPathUserProfiles = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" sRegExe = "C:\Windows\system32\reg.exe" oReg.EnumKey HKLM, sKeyPathUserProfiles, aUserProfiles ' Existing User Profiles Dim sHiveKeyPath For Each oUserSubkey In aUserProfiles sSubPath = sKeyPathUserProfiles & "\" & oUserSubkey oReg.GetExpandedStringValue HKLM,sSubPath,sValueName,sValue sProfile = Split(sValue, "\") sProfileLCase = LCase(sProfile(2)) If sProfileLCase = "system32" Then 'oFile.WriteLine " => Skipped user profile: system32" ElseIf sProfileLCase = "localservice" Then 'oFile.WriteLine " => Skipped user profile: localservice" ElseIf sProfileLCase = "networkservice" Then 'oFile.WriteLine " => Skipped user profile: networkservice" ElseIf sProfileLCase = "serviceprofiles" Then 'oFile.WriteLine " => Skipped user profile: serviceprofiles" ElseIf sProfileLCase = "administrator" Then 'oFile.WriteLine " => Skipped user profile: administrator" ElseIf sProfileLCase = "default" Then 'oFile.WriteLine " => Skipped user profile: default user" Else sHiveName = "TempHive_" & sProfileLCase ' Load user's profile hive into a temp location sRegLoad = " LOAD HKLM\" & sHiveName & " """ & sValue & "\ntuser.dat""" oShell.Run sRegExe & sRegLoad, 0, True ' Call subroutine to change registry key sHiveKeyPath = sHiveName & "\" & sUserKey DeleteSubkeys (sHiveKeyPath) oFile.WriteLine " => Set user profile: " & sProfileLCase ' Unload user's profile hive sRegUnload = " UNLOAD HKLM\" & sHiveName oShell.Run sRegExe & sRegUnload, 0, True End If Next ' End logging oFile.WriteLine " => Completed at " & Date & " " & Time WScript.Echo "Script Completed" WScript.Quit (oFile.Close) Sub DeleteSubkeys(sTempHiveKeyPath) Dim aSubKeys, oSubKey oReg.EnumKey HKLM, sTempHiveKeyPath, aSubKeys If IsArray(aSubKeys) Then For Each oSubKey In aSubKeys DeleteSubkeys sTempHiveKeyPath & "\" & oSubKey Next End If oReg.DeleteKey HKLM, sTempHiveKeyPath End Sub
Excluding file types within MigUser.XML
For an upcoming upgrade of our computers, I had a request that during the user migration that only desktop shortcuts (.lnk) files be backed up and migrated and no other files. It took several failed attempts to get working correctly, but the process I finally found that works was to do the following:
- Edit MigUser.xml
- Find section with comment “This component migrates Desktop files”
- Within the objectSet of “<include filter=’MigXmlHelper.IgnoreIrrelevantLinks()’>”, change the pattern type line to the below:
<pattern type=”File”>%CSIDL_DESKTOP%\* [*.lnk]</pattern>
- Save the MigUser.xml (of course!)
Excluding Users using USMT 4.0 in SCCM 2007 SP2
When it comes to backing up user data with USMT 4.0 [hardlinking] in SCCM, there are a few things that most people will want to do. Such as excluding local computer accounts and excluding domain user profiles older than XX days. It took a couple of days to get this figured out since there was no one blog post or forum topic which seemingly discussed both of these options.
First things first, read this excellent blog post on How to use USMT 4 hardlinking in a Configuration Manager 2007 Task Sequence
Now, USMT uses Scanstate.exe and Loadstate.exe to backup and restore users [respectively]. Local users can be excluded using switch /ue and old domain user profiles can be excluded using switch /uel. However, both of these switches cannot be used at the same time because of a precedence order. For more information, read Understanding USMT 4.0 Behavior with UEL and UE. So, to exclude local users and old domain users, set task sequence variables
- OSDMigrateAdditionalCaptureOptions = /nocompress /hardlink /uel:30 (or however many days you want it to be)
- OSDMigrateAdditionalRestoreOptions = /nocompress /hardlink /ue:%computername%\*
But there is also an undocumented problem. SCCM adds to the Scanstate/Loadstate parameters, specifically adding the /all switch which says to backup/restore ALL USERS. This completely goes against being able to use the /ue and/or the /uel switches and will cause scanstate/loadstate to fail!! So what must be done to fix the problem is to
- Select the step to Capture User Files and Settings
- Select option “Customize how user profiles are captured”
- Click the Files… button
- Add files MigUser.xml, MigApp.xml
- Repeat the above steps for Restore User Files and Settings
Updated 8/16 – USMT Best Practices states to not use MigUser.xml and MigDocs.xml together, so I’ve removed MigDocs from step 4.