Repairing Invalid Win32_UserProfile WMI Class on Windows 7 to 10 In-Place Upgraded Devices

I recently needed to query the Win32_UserProfile class in WMI for some reporting I was working on. This class is a default Hardware Inventory class in ConfigMgr. I noticed that we had a large number of devices were reporting NULL values for several properties in this class when I queried them in SQL so I decided to investigate. From the ConfigMgr console, I used CMPivot (only one of the best tools ever!!) to query the class (Listed as USMUserProfile in CMPivot). As CMPivot returned results, I noticed that about half of my devices were returning with a failure message and as I dug into the errors, I made a few discoveries and may have found a bug with the In-Place upgrade process for Windows 7 to Windows 10.

Win32_UserProfile Class in ConfigMgr Client Hardware Inventory
Win32_UserProfile Class in ConfigMgr Client Hardware Inventory

CMPivot Results

If you’ve ever worked with SQL or WMI/WQL queries, you’ve likely heard the advice that you shouldn’t use SELECT * FROM table but should specifically list the columns that you want to query like SELECT ColA, ColB, ColC FROM table to have better query performance and only return the data needed for your specific query. Without going into too much detail on how CMPivot works, the bit that’s relevant to this post is that whenever you query a class in CMPivot, it explicitly lists out the columns in the query that it sends down to the client. In this case, I selected the USMUserProfile entity from CMPivot and clicked Run Query.

A Square Dozen Image

The WMI query that CMPivot attempts to run on the client is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
SELECT 
  HealthStatus,
  LastAttemptedProfileDownloadTime,
  LastAttemptedProfileUploadTime,
  LastBackgroundRegistryUploadTime,
  LastDownloadTime,
  LastUploadTime,
  LastUseTime,
  Loaded,
  LocalPath,
  RefCount,
  RoamingConfigured,
  RoamingPath,
  RoamingPreference,
  SID,
  Special,
  Status 
FROM 
	Win32_UserProfile

In CMPivot, click on Query Summary to view Success, Failed and Offline totals and click through to see details for each category.

Summary of CMPivot Query Results
Summary of CMPivot Query Results

A Square Dozen Image
Failed Device details in CMPivot

As you can see, my Failed Devices details show ‘Invalid query…’.

Manually Validating the Query

I exported the list of failures from CMPivot and was able to get the full query posted above. I connected to a failed machine directly and ran the query in PowerShell:

1
Get-CIMInstance -Namespace "root\cimv2" -Query "SELECT HealthStatus,LastAttemptedProfileDownloadTime,LastAttemptedProfileUploadTime,LastBackgroundRegistryUploadTime,LastDownloadTime,LastUploadTime,LastUseTime,Loaded,LocalPath,RefCount,RoamingConfigured,RoamingPath,RoamingPreference,SID,Special,Status FROM Win32_UserProfile

And got these results:

1
2
3
4
5
6
PS C:\WINDOWS\system32> Get-CIMInstance -Namespace "root\cimv2" -Query "SELECT HealthStatus,LastAttemptedProfileDownloadTime,LastAttemptedProfileUploadTime,LastBackgroundRegistryUploadTime,LastDownloadTime,LastUploadTime,LastUseTime,Loaded,LocalPath,RefCount,RoamingConfigured,RoamingPath,RoamingPreference,SID,Special,Status FROM Win32_UserProfile"           Get-CIMInstance : Invalid query
At line:1 char:1
+ Get-CIMInstance -Namespace "root\cimv2" -Query "SELECT HealthStatus,L ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-CimInstance], CimException
    + FullyQualifiedErrorId : HRESULT 0x80041017,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand

Then I ran tried with SELECT *:

1
Get-CIMInstance -Namespace "root\cimv2" -Query "SELECT * FROM Win32_UserProfile

And got results!!:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
PS C:\WINDOWS\system32> Get-CIMInstance -Namespace "root\cimv2" -Query "SELECT * FROM Win32_UserProfile"                

LastDownloadTime  :
LastUploadTime    :
LastUseTime       : 1/19/2020 1:44:54 PM
Loaded            : True
LocalPath         : C:\Users\Gross
RefCount          :
RoamingConfigured : False
RoamingPath       :
RoamingPreference :
SID               : S-1-5-21-3437610054-3136568823-3853729785-1003
Special           : False
Status            : 0
PSComputerName    :

By looking at the results, I could see that a lot of the properties listed in the CMPivot query aren’t listed. Then I checked a device that successfully reported results in CMPivot and the results were much better.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
PS C:\Windows\system32> Get-CIMInstance -Namespace "root\cimv2" -Query "SELECT HealthStatus,LastAttemptedProfileDownloadTime,LastAttemptedProfileUploadTime,LastBackgroundRegistryUploadTime,LastDownloadTime,LastUploadTime,LastUseTime,Loaded,LocalPath,RefCount,RoamingConfigured,RoamingPath,RoamingPreference,SID,Special,Status FROM Win32_UserProfile"


AppDataRoaming                   :
Contacts                         :
Desktop                          :
Documents                        :
Downloads                        :
Favorites                        :
HealthStatus                     : 3
LastAttemptedProfileDownloadTime :
LastAttemptedProfileUploadTime   :
LastBackgroundRegistryUploadTime :
LastDownloadTime                 :
LastUploadTime                   :
LastUseTime                      : 1/19/2020 1:49:06 PM
Links                            :
Loaded                           : True
LocalPath                        : C:\Users\Adam
Music                            :
Pictures                         :
RefCount                         :
RoamingConfigured                : False
RoamingPath                      :
RoamingPreference                :
SavedGames                       :
Searches                         :
SID                              : S-1-5-21-86492988-3276933293-758329271-1001
Special                          : False
StartMenu                        :
Status                           : 0
Videos                           :
PSComputerName                   :

As you can see, there are a lot more properties listed.

Further Investigation

One thing that I knew about our environment was that we had In-Place Upgraded about 50% of our devices from Windows 7 to Windows 10. The number of failure was close to 50%, so on a hunch I began comparing results from known upgraded devices to new builds and discovered that ALL of my upgraded devices had Win32_UserProfile classes with missing properties when compared to Windows 10 new builds!

I reached out to some folks over on the WinAdmins Discord to help get some validation of what I was seeing (thanks guys!) and they were able to duplicate the results. I also spun up some Hyper-V VMs to test and proved that a clean (build from MSDN ISO media) Windows 7 SP1 device, upgraded to Windows 10 (1809/1903/1909 were tested) all ended up with missing properties for Win32_UserProfile.

Steps to reproduce

  1. In Hyper-V, create a new VM with the Windows 7 SP 1 ISO.
  2. Log into Windows 7
  3. In PowerShell run Get-WMIObject Win32_UserProfile and save the results.
  4. Mount a Windows 10 ISO (I’ve tested with 1809/1903/1909) and upgrade or push a feature update from WU/WSUS/ConfigMgr.
  5. Log into Windows 10.
  6. In PowerShell run Get-WMIObject Win32_UserProfile and save the results.
  7. Compare the results from step 3 and 6. They should be the same.
  8. In Hyper-V, create a new VM with Windows 10 ISO media.
  9. Log in to Windows 10.
  10. In PowerShell run Get-WMIObject Win32_UserProfile and save the results.
  11. Compare results from steps 3, 6 and 10. Step 10 will have many more properties.

This got me wondering if there were more classes in WMI that were incomplete so I wrote a quick PowerShell script (sorry, I don’t have the code - not sure what I did with it) to query the classes and property names from WMI then I just dropped the results into VSCode and did a comparison between the results. The Win32_UserProfile class was the only one that had extra properties between a 7-10 upgrade vs a new build.

I also copied the c:\Windows\System32\wbem folders from the 3 machine states Win7, Win10-post upgrade and Win10 new build and compared them in VSCode and determined that the MOF files for the Upgraded machine matched the New build. This appears to indicate that there may be a process that performs a MOFCOMP on the files post-upgrade that is failing to process this particular class. These are the files that I looked at:

1
2
3
4
 "C:\Windows\System32\wbem\UserProfileWmiProvider.mof",
 "C:\Windows\System32\wbem\UserProfileConfigurationWmiProvider.mof"
 "C:\Windows\System32\wbem\en-us\UserProfileWmiProvider.mfl",
 "C:\Windows\System32\wbem\en-us\UserProfileConfigurationWmiProvider.mfl

Repairing WMI

After determining that there wasn’t a larger issue at play here, I decided that I just needed to repair the WMI class. If you’ve been working with Windows for any length of time, you’ve likely run across scripts to repair WMI. Unfortunately, they are often brute force and possibly cause more damage than they fix. Given the fact that I don’t even know the impact of this class being incomplete, I just wanted to fix it, but not break more things. This will impact about 3000 production devices and I don’ think that running WINMGMT /ResetRepository would be the best route. After digging and testing, I finally settled on a script that appears to do the trick. I’ve written it so that it can be re-used to repair other WMI classes and can be pushed as a Configuration Baseline in ConfigMgr. It simply checks to see if the class is missing the HealthStatus property and if so, uses MOFCOMP to recompile the MOFs for the class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#In a ConfigMgr CI, Use $Remediate = $False for the detection script and $Remediate = $True for the remediation script. This keeps you from needing to maintain 2 scripts.

param(
    [Parameter()]
    [string]
    $InputParam,

    [Parameter()]
    [switch]
    $Remediate = $False,

    [Parameter()]
    [string]
    $NameSpace = "root\cimv2",

    [Parameter()]
    [string]
    $ClassName = "Win32_UserProfile",

    [Parameter()]
    [string]
    $ValidProperty = "HealthStatus",

    [Parameter()]
    [string[]] 
    $FileList = @(
        "C:\Windows\System32\wbem\UserProfileWmiProvider.mof",
        "C:\Windows\System32\wbem\UserProfileConfigurationWmiProvider.mof"
        "C:\Windows\System32\wbem\en-us\UserProfileWmiProvider.mfl",
        "C:\Windows\System32\wbem\en-us\UserProfileConfigurationWmiProvider.mfl"
    )
)

Try {
    $Class = Get-CimInstance -Namespace $NameSpace -ClassName $ClassName
    If(!($Class[0].PSObject.Properties.Name -contains $ValidProperty)) {
        If($Remediate.IsPresent) {
            ForEach($File in $FileList) {
                If(Get-Item -Path $File -ErrorAction Stop) {
                    mofcomp.exe $File
                }
                Else {
                    Write-Host "File $($File) not found."
                }
            }
        }
        Return 1
    }
    Else {
        Return 0
    }
}
Catch {
    Return 0
}

Simply add this to a Configuration Item and deploy in a Configuration Baseline in ConfigMgr and you should be able to repair any broken Win32_UserProfile classes. Obviously, test first. I’d start with the CMPivot steps listed above to help identify broken devices.


Note: I also verified that performing a Feature Update from 1809 to 1903/1909 doesn’t fix the class. Also, creating a new user profile doesn’t seem to help either.


Summary

As you can see, this simple query turned into quite the rabbit hole. I don’t know if this is an actual bug or even anything to worry about at this stage, I just know that it seems abnormal. I’ve forward this information to the Windows Setup team and have asked them to investigate whether this is a bug or by design. As of this post, they have responded indicating they will work to repro and provide feedback once they know more.

Ultimately, the fact that the MOF shows the correct properties for the class and repairing WMI fixes it, sure seems like there’s a bug.