- Add a domain user or group to local administrators with PowerShell - Wed, Mar 19 2014
- Create a list of local administrators with PowerShell - Wed, Mar 5 2014
- Remotely query user profile information with PowerShell - Tue, Nov 26 2013
I will show you how to query Windows user profile information for a remote computer using WMI and PowerShell. Since Windows Vista SP1, Microsoft has offered a WMI class named Win32_UserProfile to facilitate querying profile information for a remote computer. There are other ways to accomplish this task, such as listing the directories in the c:\users folder, but these methods are not efficient and might fail in cases where user profiles are stored in different drives or directories.
Querying using the Win32_UserProfile class will return a list of profile objects. These objects contain information such as the SID of the user to whom the profile belongs and the type of profile. Because the SID is not in a human-friendly format for identifying the user names, the script tries to convert the SID to a user name. This conversion will work for both domain and local user accounts when run locally on the computer. The SID-to-name conversion fails when you query profile information for local user accounts remotely. In such cases, you will see the SID number instead of a user name in the script output.
Another thing the script does is translate the profile type. The profile objects returned by the WMI query contain an attribute called Status. Per the Technet page, this attribute should contain values of 0, 1, 2, and 3. But what people have noticed is that the attribute stores values of 0, 1, 2, 4, and 8, where 1 = Temporary, 2 = Roaming, 4 = Mandatory, and 8 = Corrupted. The script output contains this profile type information as well.
Look at the PowerShell script below to understand how SID translation and profile type determination is done using PowerShell.
[cmdletbinding()] param ( [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [string[]]$ComputerName = $env:computername ) foreach ($Computer in $ComputerName) { $Profiles = Get-WmiObject -Class Win32_UserProfile -Computer $Computer -ea 0 foreach ($profile in $profiles) { try { $objSID = New-Object System.Security.Principal.SecurityIdentifier($profile.sid) $objuser = $objsid.Translate([System.Security.Principal.NTAccount]) $objusername = $objuser.value } catch { $objusername = $profile.sid } switch($profile.status){ 1 { $profileType="Temporary" } 2 { $profileType="Roaming" } 4 { $profileType="Mandatory" } 8 { $profileType="Corrupted" } default { $profileType = "LOCAL" } } $User = $objUser.Value $ProfileLastUseTime = ([WMI]"").Converttodatetime($profile.lastusetime) $OutputObj = New-Object -TypeName PSobject $OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.toUpper() $OutputObj | Add-Member -MemberType NoteProperty -Name ProfileName -Value $objusername $OutputObj | Add-Member -MemberType NoteProperty -Name ProfilePath -Value $profile.localpath $OutputObj | Add-Member -MemberType NoteProperty -Name ProfileType -Value $ProfileType $OutputObj | Add-Member -MemberType NoteProperty -Name IsinUse -Value $profile.loaded $OutputObj | Add-Member -MemberType NoteProperty -Name IsSystemAccount -Value $profile.special $OutputObj } }
The script also gives you information such as whether the profile is in use or not and if the profile belongs to a system account such as SYSTEM. In addition, the script indicates whether the profile is in use or not.
Sample usage and output:
Query profile information on a local computer:
.\Get-WindowsProfiles.ps1
Query profile information for a remote computer:
.\Get-WindowsProfiles.ps1 -ComputerName SRVTIB1
Query profile information for multiple remote computers:
.\Get-WindowsProfiles.ps1 -ComputerName (get-content c:\temp\servers.txt)
Get user profile information with PowerShell
Hi,
Found an error on line 17 in your code.
should be:
switch($profile.status)
Björn, thanks! The line is now correct.
It’s very nice script, thank you for this.
As I am not familiar to scripting in PowerShell I will appreciate, if anyone could modify script to add some more feature which is usable for audit purposes.
In my environment, we need to review accounts and also check if disabled or locked out.
Could you, please, add 2 more columns into script to verify if account is disabled or locked out – on DC as well as on local computer ?
Thanks for your effort. Appreciate it!
David
awesome script, can you add each users folder size?
AWESOME !!!! just what im looking for! thank you 1000x !!!
Hi,
Can u send a script to delete those user profiles which is not used from more than 30 days excluding service, admin and network profiles.
I’d also like to have sizes included in the results. Great job though. Very useful for the environment I just came into. Profile cleanups had never occurred before and this with the size should help me justify accomplishing it.
Hi there
Will it show temporary profiles by default if found?
Thank you
Paul
I am not able to run this file. I copied code in to notepad and saved as a Ps1 . but when i am trying to run it using powershell, i am getting multiple error where in it is working on powershell ISE. can you please help?
What error messages do you get?
I saved above script in notepad and given name as “WindowsProfiles.ps1”
If i try to type Get-WindowsProfiles.ps1 then it gives me below error
PS D:\> Get-WindowsProfiles.ps1
Get-WindowsProfiles.ps1 : The term ‘Get-WindowsProfiles.ps1’ is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path
correct and try again.
At line:1 char:1
+ Get-WindowsProfiles.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-WindowsProfiles.ps1:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
if i run script without “Get-” then it gives me result
but my main question is how i can run same script for multiple servers
I saved above script in notepad and given name as “WindowsProfiles.ps1”
If i try to type Get-WindowsProfiles.ps1 then it gives me below error
PS D:\> Get-WindowsProfiles.ps1
Get-WindowsProfiles.ps1 : The term ‘Get-WindowsProfiles.ps1’ is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path
correct and try again.
At line:1 char:1
+ Get-WindowsProfiles.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-WindowsProfiles.ps1:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
if i run script without “Get-” then it gives me result
but my main question is how i can run same script for multiple servers
Since you are saving the file as “WindowsProfiles.ps1” that will be what you need to call in the console. in the example above, the author saved the file as “Get-WindowsProfiles.ps1”. That is why you are getting the error you stated.
Thank you so much for guidance ….I thought he used get command
How do we add this line to get the remote computers? I’m a bit of a Powershell noob and could use some assistance. 🙂
\Get-WindowsProfiles.ps1 -ComputerName (get-content c:\temp\servers.txt)
I figured it out. I made a ps1 file for the program itself, a text servers list and then used the code for executing it and everything works perfect.
I have another question though. Is there a way to get all this information output in to an Excel spreadsheet or at least a notepad for easy searching and access?
Thank you very much! 🙂
Hi,
Apologies just a novice at this stage using powershell. Love your scrip exactly what I needed for my program I am working on.
With your script is there away to output the output to an array that I can add not a list box (Win Gui)
Thanks heaps
Aidan, there is no need to apologize for being a newbie. 🙂 The script’s output is not a GUI, the output is an object and you can use the object’s properties in your script. Objects are much easier to manage than arrays. If you want to work with PowerShell, I highly recommend to learn how to use classes and objects.
Script works great. I had one question though. Is there a way i can get the output of the command to go into a CSV with each output object is its own colum?
Thanks
Nevermind my question above, i figured it out.
I was able to export and have it format as i wanted by assigning the output a variable and then outputting the variable to csv:
$results = .\Get-WindowsProfiles.ps1 -ComputerName (get-content c:\temp\test.txt)
$results | export-csv -Path C:\temp\test.csv
its not working for 2003 servers. what need to modify ?
It won’t work with 2003. The WMI class didn’t exist in Win2k3. :-\
David F.
When I try to run the script for a remote computer by adding the ComputerName variable, nothing happens. It works fine on the local machine.
There’s no error, no output in powershell at all. I’m attempting to query other computers on our domain.
Maybe the Windows Firewall blocks the connection. Check if you can access the remote machine with the Computer Management tool.
Thank you. I tried using the Computer Management tool as you suggested and cannot connect that way either. I think you’re right in that it is being blocked by our company antivirus.
That solves the mystery, thanks again!
Great script!
when i run it against a list of computers, it does nothing. if i run against individual computers, it works.
Also, how can i exclude the system profiles.
thanx again.
This is a tangent question, but this script is the perfect source for it..
Given this section:
Would this perform better with hashtables?
David F.
Warren Klaus:
I can't help you with why you aren't getting remote results, I can help you with the Special Profiles..
Change this line:
to this:
David F.
Is it possible to list the date when each profile was created?
I need a script that will identify profiles that were created after a certain date so that I can then remove them.
(For OS rollback)
I’m fairly new with powershell. I’m an old Winbatch person with a lot of WiseScript usage. I came across this thread looking for something similar to all of you and like many of you, I find things on various sites and modify those items to fit my needs.
I could be wrong but it seems like an awful lot of code that I’ve found relies on the registry SID or some convoluted WMI stuff. So, I share with you something I created with the help of this site and various other sites.
I like simple… C:\users\
ForEach ($line in (get-content -Path "C:\temp\powershell\servers.txt")){
$Computername = get-childitem \\$Line\c$\users |SELECT Root, LastAccessTime, Name |Out-File C:\temp\powershell\output.txt -Append
}
I think if we simply find the last access dates of profiles, that will give us a fairly good indication of the last logon time. It’s probably not perfect but it’s good enough.
Instead of “SELECT Root, LastAccessTime, Name” you can use “SELECT *” and that will give you full list of items you can include. Maybe you want them all. My script includes only what I needed.
Im not sure when this will work well. I am just logged on my server via RDP, the server is up for few days, and query like yours shows this:
Last access time is 4 days ago.
I read your reply and went back to my script to take a look. I've only run it on Win10 VM machines.
One thing I changed but didn't seem to matter when comparing two different output files was
$Computername = get-childitem \\$Line\c$\users |SELECT Root, LastAccessTime, Name
$Computername = get-childitem \\$Line\c$\users |SELECT "\\$Line\c$\users", LastAccessTime, Name
This producted the same exact results except for the path. Kinda concerned me but I thought I was pulling the path from the wrong place but it wasn't.
Maybe change "LastAccessTime" to "LastWriteTime". On my systems, the times for both values match.
As a PS newbie, maybe I'm just not getting something but for me, it appears to be working. If anyone can comment on why what I'm doing isn't working and can supply something different, I'd love to try it out.
I dont think this is about Powershell, but rather how Windows works. In below example you can see that even that I am just now logged under Administrator user and I have access my Documents folder, the root folder access date shows old date:
What are you trying to achieve? It seems for me a little strange to pull information when someone was last time logged like this. Instead, I would user Active Directory user information. If you speak about W10 machines, those are usually used by single user.
The profile thing would make sense to me on a RDS server with hundreds of profiles that consumes disk space.
Just looking to all users who logged into these remote machines and at what dates.
Well in that case I guess you might use this approach. Just remember, if the user has active session (even in disconnected state) for several days, the date might be old as I showed.
Hello Sitaram,
When I created a windows batch to fetch the information from the SQL servers and then sending the mail to mail box using powershell, I am getting report as well as company related information in the mail body.
Could you please let me know how to suppress the unwanted messages apart from the report which is getting from windows batch files.