Hey, Scripting Guy! How Can I List All User Profiles on a Remote Computer?

Bookmark and Share


Hey, Scripting Guy! Question

Hey, Scripting Guy! I am trying to administer a remote computer using Windows PowerShell 2.0, and I need to find out what profiles are stored on that computer. I found an old VBScript that reads the registry, but it looks like it will be a lot of work to adapt it and to make it work.

-- JB

Hey, Scripting Guy! AnswerHello JB,

Microsoft Scripting Guy Ed Wilson here. It is a nice sunny day here in Charlotte, North Carolina, in the United States. It is cold but nice. Some of my friends are out wearing their winter coats because the temperature is 57 degrees Fahrenheit (13 degrees Celsius). The smell of mothballs fills the halls of the Microsoft office here in Charlotte. I usually work from home, but I needed to return some books to the Microsoft Library and converse with a few of my colleagues. Besides, we have a Starbucks in the office as well as an award-winning cafeteria, a pool table, jukebox, Xbox 360 (with all the latest Xbox games), free soft drinks, a nice selection of hot tea, and basketball hoops. Therefore I feel compelled to go into the office to work at least every couple of months, just to hang out with my friends if for no other reason.

I am not sure which “old registry” script you found on the Internet, but there is a Hey, Scripting Guy! post from a few years ago named How Can I List All the User Profiles on a Computer that contains a script that reads the registry to retrieve profiles. The ReadRegistryGetProfiles.vbs script, copied from that article, is shown here.


On Error Resume Next

Const HKEY_LOCAL_MACHINE = &H80000002

strComputer = "."
Set objRegistry=GetObject("winmgmts:\" & _
    strComputer & "rootdefault:StdRegProv")
strKeyPath = "SOFTWAREMicrosoftWindows NTCurrentVersionProfileList"
objRegistry.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubkeys
For Each objSubkey In arrSubkeys
    strValueName = "ProfileImagePath"
    strSubPath = strKeyPath & "" & objSubkey
    objRegistry.GetExpandedStringValue HKEY_LOCAL_MACHINE,strSubPath,strValueName,strValue
    Wscript.Echo strValue

To read from the registry using Windows PowerShell, you can use the registry provider, which will work on Windows PowerShell 2.0 or Windows PowerShell 1.0. The registry provider makes working with the registry as easy as working with FileSystem. In fact, you use the same kinds of commands and in the same kinds of ways. In the GetProfilesFromRegistry.ps1 script, the path to the ProfileList registry key is specified in the $regPath variable. This is seen here:

$regPath = 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionProfileList'

The Get-ChildItem cmdlet is used to obtain a list of all the registry keys under the ProfileList location. Using the Get-ChildItem cmdlet, you specify the path in the same way you would the path to a folder. The only difference is that you are using the HKLM drive instead of a C: or D: drive. This command is shown here, along with the output:

PS C:> Get-ChildItem -Path 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionProfileList'

    Hive: HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionProfileList

SKC  VC Name                           Property
---  -- ----                           --------
  0   5 S-1-5-18                       {Flags, State, RefCount, Sid...}
  0   3 S-1-5-19                       {ProfileImagePath, Flags, State}
  0   3 S-1-5-20                       {ProfileImagePath, Flags, State}
  0  10 S-1-5-21-3746122405-8348924... {ProfileImagePath, Flags, State, Sid...}

PS C:>

The results of the Get-ChildItem cmdlet are piped to the ForEach-Object cmdlet for additional processing. This is shown here:

Get-ChildItem  -path $regPath|
ForEach-Object {

The additional processing is because of the way registry values are exposed. To retrieve the value of the ProfileImagePath key, it is necessary to use the Get-ItemProperty cmdlet. An example of using the Get-ItemProperty cmdlet is seen in this image:

Image of using Get-ItemProperty cmdlet

As you can see from the preceding image, multiple properties are returned by the Get-ItemProperty cmdlet. Because of this, it is necessary to repeat the registry key name twice: once in the –name parameter and once to select the property value itself.

Each of the profile paths is seen under the ProfileList registry key. This is seen in this image:

Image of profile paths under ProfileList registry key

Because there are multiple profiles stored in the registry, you need to use a looping type of construction to walk through the collection of registry keys. When you are using piping, you will need to use the ForEach-Object cmdlet. This section of the script is shown here:

ForEach-Object {
 (Get-ItemProperty -path (join-path -path $regPath -child $_.pschildName) `
  -Name profileImagePath).profileImagePath

The complete GetProfilesFromRegistry.ps1 script is shown here.


$regPath = 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionProfileList'
Get-ChildItem  -path $regPath|
ForEach-Object {
 (Get-ItemProperty -path (join-path -path $regPath -child $_.pschildName) `
  -Name profileImagePath).profileImagePath

However, if you are only interested in finding out about the profiles that are stored on a remote computer, Windows Vista introduced the Win32_UserProfile WMI class. This class has the ChangeOwner method, and it supports an instance delete. The RoamingPreference property is also read/write. In short, the Win32_UserProfile WMI class is cool. There is only one problem; it too is undocumented. The only official reference I can find is to Knowledge Base article 930955 from 2007 that discusses the fact that moveuser.exe does not work on Windows Vista. I can confirm that the WMI class Win32_UserProfile does not exist on Windows XP.

To use the Win32_UserProfile WMI class to list the profiles on a remote computer, use the Get-WmiObject WMI cmdlet. The command to list remote profiles and display the results in a table follows is shown here:

Get-WmiObject -Class win32_userprofile -ComputerName win7-pc |
Format-Table –property sid, localpath –AutoSize

You can shorten that command by using aliases, positional arguments, and partial parameter completion. This is shown here:

PS C:> gwmi win32_userprofile -co win7-pc | ft sid, localpath -a

sid                                           localpath
---                                           ---------
S-1-5-21-3875537581-88027767-1834046371-500   C:UsersAdministrator
S-1-5-21-3875537581-88027767-1834046371-1001  C:Userswin7
S-1-5-21-3746122405-834892460-3960030898-500  C:Usersadministrator.NWTRADERS
S-1-5-21-3746122405-834892460-3960030898-1115 C:Usersed
S-1-5-20                                      C:WindowsServiceProfilesNetworkService
S-1-5-19                                      C:WindowsServiceProfilesLocalService
S-1-5-18                                      C:Windowssystem32configsystemprofile

PS C:>


JB, that is all there is to using Windows PowerShell to work with the registry. Registry Week will continue tomorrow when we will talk about…wait a minute.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson and Craig Liebendorfer, Scripting Guys


Comments (2)

  1. Anonymous says:

    I tried this but got this error

    Get-WmiObject : Invalid class

    At line:1 char:14

    + Get-WmiObject <<<<  -Class win32_userprofile -ComputerName citrix3a | ft sid, localpath -a

       + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], ManagementException

       + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

  2. Christian says:

    Unfortunately, the PowerShell script is missing one important part of the question: "…on a remote computer"

    Maybe you want to add that…

Skip to main content