Collecting USMT Estimates using ConfigMgr

Collecting USMT Estimates using ConfigMgr

A common ask is how much space is needed to store user state data captured by USMT. This is an important question to answer so that you know how space you may potentially need when capturing user data to the network in traditional Replace scenario task sequences. It’s not an easy question to necessarily answer because of a lot of variables. Gathering the data from all of your systems could also prove tricky. Fortunately, there is a fairly straight-forward way to get this done using USMT’s built-in space estimate ability and by extending ConfigMgr’s Hardware Inventory. Of course, I did this all for the customer as detailed below.

Script Update - January 9, 2019

Based on some feedback (and gentle nudging by Gilbert T.), I’ve updated the script to account for spaces in path names which was causing file not found issues when folks were manually running the script or included the files within another sub-folder containing spaces in the name.

The Steps

Step 1: Use USMT to estimate the space needed

USMT’s scanstate has a /p switch that will generate an XML file with estimated space required to capture the user data (much emphasis on estimated).

Step 2: Store USMT’s space estimate in WMI

Consume the XML file grabbing the space estimate and store it in a custom WMI namespace and class.

Step 3: Configure hardware inventory to gather the data

Very easy to do via the GUI in ConfigMgr 2012. Not too difficult to do in 2007 either but you must edit the sms_def.mof file. Note that for data already in WMI, there is no need to touch configuration.mof.

Step 4: Report on the data

Use your favorite mechanism report on the data including (WQL) queries, SQL queries, or reports.

The Script

Steps 1 and 2 above are in a fairly straight-forward script called USMT-Estimate.vbs. This script runs scanstate.exe with the /p (space estimate) option using the default MigApp.xml and MigDocs.xml configuration files. By default, the script also uses the scanstate uel option and sets it to 90 days – this option causes scanstate to only consider user profiles for users that have logged in within the last number of specified days (90 in this case by default).

scanstate outputs an XML file with estimates in it to the %temp% directory called scanstate.xml. The script grabs the results from this file, creates a new namespace in WMI (if it doesn’t already exist) called ITLocal under root, creates a new class called USMT-Estimate in this namespace (if it doesn’t already exist), and then creates an instance/object of this class with the space estimate (in MB) and a date/time stamp.

USMT Estimate script: Get it on GitHub

Script Use

To use the script, place it in the root of your USMT 4 package (at the same level as the x86 and amd64 folders) and update your DP(s). Create a program that runs with admin privileges that runs the following command line:

cscript.exe USMT-Estimate.vbs

Deploy. That’s it really.


scanstate will produce a log file in %temp% called scanstate.log so you can check it if you suspect something wonky has happened.

There are a lot of ways to check if the data is being populated into WMI, but my favorite is PowerShell (and it should be yours also). On a system where the script has run, this is easily done using two simply PowerShell commands:

$usmt_estimate = gwmi -namespace rootITLocal -class USMT_Estimate

Get-WMIObject has a –computer parameter to connect to remote systems also and of course you can use all of the power of PowerShell. Other possible ways to review the data in WMI include WBemTest, CIMStudio, and wmic, to name a few.

Script Customization

If you have custom configuration files, you can run those instead (or in addition to the default ones) by using the /xml option making sure to also specify any default configuration files that you would like to use also (comma separated):

cscript USMT-Estimate.vbs /xml:MigApps.xml,MigDocs.xml,MyCustom.xml

The script looks for all scanstate XML configuration files in either the x86 or amd64 subfolder of the USMT package source files folder so place any custom configuration files you have into one or both of these directories based on your expected usage.

To change or remove this or add other options, update the ScanStateOptions variable on line 9 of the script. The complete set of options is listed at

Data Gathering

This is step 3 from above and is the easy part in ConfigMgr 2012. First, run the script (either manually or through a deployment) on at least one system first though so that ConfigMgr can find information about the new class.

Navigate to Overview –> Site Configuration –> Client Settings in the Administration workspace. Create a new set of client settings or edit an existing set (just like with Group Policies, it is highly recommended that you don’t edit the Default Client Settings and instead create and deploy your own as needed).

In the Hardware Inventory section, click on the Set Classes … button.

Hardware Inventory Set Classes

Hardware Inventory Set Classes

In the resulting Hardware Inventory Classes dialog, click Add…

In the Add Hardware Inventory Class dialog, click Connect…

In the Connect to Windows Management Instrumentation (WMI) dialog, enter the Computer name for the system where you’ve already successfully run the script and rootITlocal for the WMI namespace. Supply alternate credentials if necessary to connect to the system specified and click Connect.

This will (eventually) return showing the one and only class in this namespace: USMT_Estimate. Check the checkbox next to this class and then click Edit… at the bottom.

Hardware Inventory Edit Class

Hardware Inventory Edit Class

In the Class qualifiers dialog, Change the Display name to USMT Estimate (without the underscore). Leave all of the Units as None and click OK four times.

That’s it. The next time the clients update their machine policy, they will be informed of this change and the next hardware inventory cycle after this they will collect the data from this class (if it’s been populated by the script). You can check on this by looking in InventoryAgent.log on the client:



If you’re stuck on ConfigMgr 2007, you should be able to just add this snippet to your sms_def.mof file:

[ SMS_Report (TRUE),
SMS_Group_Name ("USMT_Estimate"),
Namespace ("root\ITLocal") ]
class USMT_Estimate : SMS_Class_Template
[ SMS_Report (TRUE), key ]
String     GUID;
[ SMS_Report (TRUE) ]
DateTime     DateTime;
[ SMS_Report (TRUE) ]
UInt32     SizeEstimate;

I have not explicitly tested this on 2007 but there’s no reason this shouldn’t work.

Once ConfigMgr has gathered the data, you’ll be able to see it in a variety of places:

Resource Explorer

Resource Explorer

Resource Explorer

Query Wizard

Query Wizard

Query Wizard

SQL Server

SQL Server Views

SQL Server Views


I didn’t explicitly create any reports so I’ll leave that as an exercise for you and your gangnam style reporting skillz.

KB2522623 and Offline Servicing

Next Article

KB2522623 and Offline Servicing



  1. There is an bug in the VBScript (line 32). I had to edit it because it was not correctly identifying the bit version. If the environment variable does not exist, then ExpandEnvironmentStrings() returns the string you sent it.

    ‘ Per MSDN
    If g_WshShell.ExpandEnvironmentStrings(“%ProgramFiles(x86)%”) = “%ProgramFiles(x86)%” Then
    architecture = “x86”
    architecture = “amd64”
    End If

    • Hi Phil,

      Thanks! I knew about the bug, but neglected fixing it 🙁

      Thanks to your small change though, the show can go on — I’ve updated the download with your small change 🙂 Thanks again.

  2. Hi, I don’t have SCCM here. Therefore how can I use this script without SCCM ?.
    We are just going to use MDT 2012 in our deployment solution.

    Any help is much appreciated.

    • I really have no idea. The whole point is capturing and reporting on this info before the migration. If you don’t have ConfigMgr in place, how do you expect to gather the info?

  3. Thank you for this.

    I noticed the WMI entries do not over write themselves. Is this by design and if so, is there a simple way to modify it so it overwrite the old data?

    Thanks again

    • My main thinking was that this could be run multiple times on a system over time and the results compared. Yes, that could have still been done using the history view, but I like having all of the data in a single view. Yes it can be modified fairly quickly if you are familiar with WMI and VBScript. What’s the reason for wanting this though?

  4. Hi Jason,

    Great post. Got here through your other post on gathering inventory on SQL instances.

    One thing I want to comment on. Not sure if this is changed behaviour – I’m running SCCM 2012 R2 SP1 CU1 – but I could only add the WMI class in the hardware inventory classes for the Default Client Settings. All of my custom client settings have the Add… button greyed out.

    It wasn’t a problem to add the class though. I’ll go through my actions step by step for others to follow.

    In Default Client Settings, I went to Hardware Inventory, Set Classes…, Add…, Connect…, which is where I entered the name of my test machine and the custom WMI namespace created through your script. The SQLInstance class now showed up at the top of the list. I clicked Cancel, not OK, and confirmed that I did not want to save changes.

    Going back to my custom client settings, I was now able to find and select the SQLInstance class in the list, even though I canceled out of the dialog earlier. This has prevented me making any changes to the Default Client Settings.

    That’s it. Thanks again for sharing your script and methods. It’s helped me along nicely!


    • You must add all hardware inventory class changes to the default settings first — you don’t have to check/select it there, just add it there. After adding it there you’ll be able to select it in any of your custom client settings packages.

  5. Easy example for those of you who want to remove the past history from wmi. Add the sub to the end of the script and call it from the main.

    Sub ClearWMIClass()
    Dim objWMI
    On Error Resume Next
    Set objWMI = GetObject(“winmgmts:\\.\Root\” & CUSTOM_NAMESPACE)
    objWMI.Delete DATA_CLASS
    End Sub

  6. Hello,

    The script returns this results, any idea why? when I run the command on its own i get diffrent result.




  7. Hi Jason, I tried your script, but getting error,
    PS E:\User State Migration Tool\x86> cscript.exe USMT-Estimate.vbs
    Microsoft (R) Windows Script Host Version 5.812
    Copyright (C) Microsoft Corporation. All rights reserved.

    E:\User State Migration Tool\x86\USMT-Estimate.vbs(68, 2) (null): The system cannot find the file specified.
    and the 68,2 is g_WshShell.Run commandLine, 0, True
    Can you give more details if you have time?
    Thanks in advance.

    • You’ve placed the script in the wrong folder. As noted, it needs to be at the same level as the x86 and amd64 folders and not within one of them.

      • Having the same issue and validated that it is in the correct directory. Any ideas on how to get around this?

        • Hi Luke,

          What folder exactly did you place the script in? It needs to be in the same folder as the x86 and amd64 folders and not within one of them.

          • After some additional review, it looks like the script did not account for spaces in folder/path names. This generally shouldn’t be an issue when run from a ConfigMgr package set to download and execute as none of the sub-folders in the USMT folder have spaces in them; however, if run manually or another level of folders is introduced in the path containing spaces in their names, a file not found error will be thrown. I’ve updated the script to account for this. Please re-download and try again.