Incans
Incans

Reputation: 182

Correct way to access the USERPROFILE dir of a specific user in a script?

I'm writing a script to perform some file operations in the USERPROFILE folder of each (local) user on a Windows machine.

I have found various examples that use $env:USERPROFILE to identify the profile directory of the current logged-in user. I have also seen examples that assume all user profiles are saved in C:\Users\ and iterate/filter over that folder.

However, profile folders can be moved on Windows. My aim is to find (robustly) the profile directory of a specific user, given either that user's username (string) or a LocalUser object.

I can get an array of User objects based on active accounts with-

$users = Get-LocalUser | Where-Object Enabled -eq true

But the properties of those LocalUser objects are limited, and the UserProfile path is not among them. I believe this information is stored in the registry. I've through the PowerShell docs multiple times, but I haven't yet found the correct incantation that will give me the path of a user profile for a given user, which I can use in a loop to iterate across all users and their profile folders.

Upvotes: 2

Views: 5625

Answers (3)

js2010
js2010

Reputation: 27433

You can use the wmi class win32_userprofile, but it only has sid, not username:

get-wmiobject win32_userprofile | select sid,localpath

sid                                              localpath
---                                              ---------
S-1-5-21-3961843708-1234567890-2901110831-1002   C:\Users\user

Upvotes: 0

mklement0
mklement0

Reputation: 437833

You can retrieve the root (parent) directory of all user profile directories from the registry as follows:

$profilesRootDir = 
  Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' ProfilesDirectory

To get a specific user's profile directory, say jdoe, you can then use:

# See more robust alternative below.
Join-Path $profilesRootDir jdoe

However, the ultimate source of truth is the ProfileImagePath value in the subkeys of the above registry key path, named for each user's SID (security identifier), which Get-LocalUser does provide (the output objects have a .SID property).

Thus, it is better to use:

Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$((Get-LocalUser jdoe).SID)" ProfileImagePath

To reliably get the profile directories of all enabled local users, use the following:

Get-LocalUser | 
  Where-Object Enabled |
  ForEach-Object {
    # Note the use of ...\ProfileList\$($_.SID) and value name ProfileImagePath
    Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$($_.SID)" ProfileImagePath
  }

Upvotes: 2

RetiredGeek
RetiredGeek

Reputation: 3158

Perhaps something along this line:

$users = Get-LocalUser | Where-Object Enabled -eq true

$profilesRootDir = @(
 Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' ProfilesDirectory)

ForEach ($User in $Users) {

  $UserPath = Join-Path -Path "$profilesRootDir" -ChildPath "$User"

  "User     : $User`n" +
  "User-Path: $UserPath" 
}

Output:

User     : Bruce
User-Path: C:\Users\Bruce

Upvotes: 1

Related Questions