How can I get a plaintext list/array of local users on my system in powershell? - powershell

I need to get a plaintext list or array of all the local users on my system so I can loop through them and preform certain actions. By "plaintext" I mean just the user's names. Nothing else. No fancy formatting, no titles, no groups, nothing but the user's names.
I've googled around and tried several solutions, (for e.g. this one powershell - list local users and their groups) but they all have extraneous data that makes looping through the users impossible.
Is there any way I can get just a plain list of users? I wouldn't mind a cmd solution if that's what you have. Note that I have already tried net users, but like I stated earlier, it has this extraneous data.

VBScript:
Dim ADsContainer, User
Set ADsContainer = GetObject("WinNT://.,Computer")
ADsContainer.Filter = Array("User")
For Each User In ADsContainer
WScript.Echo User.Name
Next
Paste the above lines into GetLocalUsers.vbs and run it like this:
cscript //nologo GetLocalUsers.vbs
If you want to use WMI directly in PowerShell, you can use this:
get-wmiobject Win32_UserAccount -filter 'LocalAccount=TRUE' |
select-object -expandproperty Name

You have to write it like this to get it formatted as you requested:
Get-WmiObject -Class Win32_UserAccount | Format-wide -property name -column 1
Prints:
Administrator
Guest
and so on..

After a bit more experimentation, reading, etc, I found a rather simple solution:
$accounts = Get-WmiObject -Class Win32_UserAccount | Select name
Returns:
name
----
Administrator
Guest
John Doe
Other User
Not quite what I want, but if I loop through it like this:
foreach ($i in $accounts) { Write-host $i.name }
It prints:
Administrator
Guest
John Doe
Other User
This is messy, so I shortened it down to one loop:
foreach ($i in Get-WmiObject -Class Win32_UserAccount | Select name) {
# refer to the looped user as $i.name now
}
and per Bill_Stewart's comment, it is a good idea to filter by local account:
foreach ($i in Get-WmiObject -Class Win32_UserAccount -filter 'LocalAccount=true' | Select name) {
# refer to the looped user as $i.name now
}
Still less than optimal, but for now it suits my needs.

Related

Modify local users property description in Powershell 4.0

I would like to modify the description property from local users.
I can retrieve all local users name and description in two ways.
One using WMI Win32_UserAccount class:
Get-CimInstance -ClassName Win32_UserAccount -Filter "LocalAccount='True'" | Select-Object -Property name, description | FL
And one using ADSI:
$Computername = $env:COMPUTERNAME
$adsi = [ADSI]"WinNT://$Computername"
$Users = $adsi.Children | Where-Object {$_.SchemaClassName -eq 'user'}
ForEach ($u in $Users) {
$u | Select-Object -Property Name, Description
}
However, I can't figure out how using commands similar to the ones above I can modify the local user property description. I did research and only found out how to do GETS and not SETS.
My final objective is to put this code in an Ansible playbook and run it in several remote servers. If you have an idea of how to solve this or how to help me I would be grateful.
Working with ADSI can be very tricky but, its super helpful since it usually doesnt rely on 3rd party modules.
Without going super in depth on ADSI, heres the easiest way you can change, or add a value to a property, the description property in this case:
$adsi = [ADSI]"WinNT://$env:Computername"
$User = $adsi.Children.Find('Abraham')
$User.Description = "Hi, this is a description"
$User.SetInfo()
Using $User.SetInfo method, we can write the changes to the database. It's not a method you would get either when piping to a Get-Member. Unfortunately, it's one that you would need to know already. Using Dot Notation we can reference the property you'd like to change, then assigning it a value just like we would when assigning a value to a variable: $var = value.

Group Membership of Servers

I want to get "WSUS" group membership of my ad computers (servers) in the entire domain.
The PowerShell Script is use:
$csvInfos=#()
$allservers=#(Get-ADComputer -SearchBase "OU=BRLN-Servers,OU=OU-BRLN,OU=DE,OU=Locations,DC=bla,DC=bla,DC=bla" -Filter * -Properties *)
foreach($server in $allservers){
$customobject = new-object -TypeName PSObject -Property #{
'Servername' = $server.Name
'WSUS Gruppen' = ($server | get-ADPrincipalGroupMembership |?{$_.Name -like '*wsus*'} | Select-Object Name )
'OS' = $server.OperatingSystem }
$csvinfos+= $customobject }
$csvinfos | export-csv c:\temp\wsus_server_groups.csv -Delimiter ";" -NoTypeInformation
The Script works ... kinda ok I think but I got some problems with the result.
The group names are displayed as #{Name=Groupname}, Is it possible that the group name will be displayed as "Groupname"?
If a server is in more than 1 "WSUS"-Group I get System.Object[]. How can I get all the groups the server is a member of as result?
I think my problems are not that difficult to fix, but I do not have that xp with PowerShell to do it on my own.
Best regards
Michael
EDIT: ORIGINAL QUESTION IS SOLVED ... BUT HERE IS A NEW PROBLEM!
The script is used on 3 different domains (US, EU, ASIA) The domain are built the same. Same OU structure, same settings, same everything.
Based on the updated script I am able to get the results I want for 2 of the 3 domains. On the third domain I get an error with the get-adprincipalgroupmembership command:
Get-ADPrincipalGroupmembership : The server was unable to process the request due to an internal error.
I googled very much about this error. Even here on stackoverflow is a topic with that error:
Get-ADPrincipalGroupMembership Fails when any user group name has "/"
but I don't think that is describes the same situation as mine. Or maybe I am blind....
so: Is there a way to fix that problem / error or do I have to use another command that does the same as Get-ADPrincipalGroupmembership?
Thank you, Michael
Use The -ExpandProperty parameter for the Select-Object property to get the property value without the column header.
See the Differnece:
Get-Process explorer | Select Name
Name
----
explorer
Get-Process explorer | Select -ExpandProperty Name
explorer
Join the Multiple results with comma , (in case there's only one element, no join occur)
To convert an array to string, you need to parse it in someway, for example join it with commas
Example:
1..3 # Array of 3 elements
1
2
3
(1..3).ToString() # Convert it to string will result:
System.Object[]
(1..3 -join ',').ToString() # using join will result:
1,2,3
# for one element, there's no effect:
(1 -join ',').ToString()
1
So, update this line to solve both problems:
'WSUS Gruppen' = ($server | get-ADPrincipalGroupMembership |?{$_.Name -like '*wsus*'} |
Select-Object -ExpandProperty Name ) -join ','

How to put computers on a network into a variable in PowerShell?

I've been using these lines of code:
$204computernames = Get-ADComputer -searchbase $sb -filter * | ?{$_.name -like "ptfg*-061*"} | select name
$onlineComputers = $204computernames |Where-Object { Test-Connection $_.name -Count 1 -Quiet }
to grab all of my computers on my network and put them into a variable so I can push all of my documents, updates, etc to them so that I dont have to go to each computer individually to get the files I want where I want. When I take the variable and put it into a line of code like this
Test-Connection $onlineComputers
I get errors like this:
Test-Connection : Testing connection to computer '#{name=PTFGW-0613618TN}' failed: A non-recoverable error occurred during a database lookup
At line:1 char:1
+ Test-Connection $onlineComputers
I'm assuming after extensive testing in different codes that there is a problem with the way my variable stores its values. Does anyone know how I can fix this issue?
As #boxdog already pointed out in the comments, with | select name you get objects with the single property Name. Therefore, you don't get a list of computer names, but a list of objects that have the computer name in the Name property. You can work with that and access each computer name like .Name.
But to solve your problem, you can replace | select name (which stands for | Select-Object -Property Name) by | Select-Object -ExpandProperty Name. That way, you filter out only the computer name and expand the result to just this property. After that, you really have just a list of computernames (an array of string objects).

Prepend AD User description with PS - Duplicate Update with ForEach

I've seen many code examples where Get-ADUser can be used to append a description with the following code:
get-aduser username -Properties Description | ForEach-Object { Set-ADUser $_ -Description "$($_.Description) Some more stuff" }
I had thought I could simply invert the order of the code in order to prepend, like so:
get-aduser username -properties Description | ForEach-Object { Set-ADUser $_ -Description "Stuff To Use - $($_.Description)"}
The output then becomes:
"Stuff To Use - Stuff To Use"
In essence, whatever is there to start with is wiped out completely and replaced with a doubled up result of the intended goal.
What am I missing here?
The code is good and it likely ran twice accidentally.
Reset the description, run the code, then refresh Active Directory Users and Computers and recheck.

How to use a user's input variable as a search query in Get-ADComputer

thank you for visiting my first question on this website.
The purpose of this PowerShell script is to query the user for a partial name of a pre-existing computer on the domain. After the query is complete it retrieves the full computer name from a specific OU in active directory, and copies this full computer's name it to the user's clipboard. This is to help save time to the people I work with at the help desk(including myself) who have to perform this action manually every day.
Note:I'm pretty sure the problem isn't with the two 'Get-ADComputer' lines because if I manually enter the full computer name in the script it works exactly as intended. The issue seems to be either with how I'm defining the user input, or how it's being passed along to the variable($PCName) inside of the 'Get-ADComputer' cmdlet.
Here is the script in its entirety, the only thing I omitted is the specific active directory OU - I know it's looking in the right OU, because the lines taken individually and with a manually PC Name entered work great.
$global:PCName=(Read-Host "Enter partial PC name")
write-host "You entered the partial PC Name: $PCName"
return $PCName
#PCName Information Table Display.
Get-ADComputer -SearchBase 'OU=(Disregard)' -Filter 'Name -like "*$PCName*"' -Properties IPv4Address | Format-Table Name,DNSHostName,IPv4Address -A
#Progress indicator advisory message.
Write-Output "Converting $PCname to full computer name and copying result to your clipboard."
#Clip Line - Retrieves full PC name and copies resolved PC name to clipboard.
Get-ADComputer -SearchBase 'OU=(Disregard)' -Filter 'Name -like "*$PCName*"' | Select Name -ExpandProperty Name | Clip
#End of script advisory message.
Write-Output "Full PC Name:$PCName - Resolved and copied to clipboard."
If there's any other fault to be pointed out, I would appreciate it. I have been using PowerShell for less than a week and am a new programmer overall. I've performed no less than 40 google queries and spent at least 3 hours trying to get this to work.
Thank you!
do {
$computerName = read-host "Enter partial computer name [blank=quit]"
if ( -not $computerName ) {
break
}
$sb = [ScriptBlock]::Create("name -like '*$computerName*'")
$computer = get-adcomputer -filter $sb
if ( $computer ) {
$computer
$computer | select-object -expandproperty Name | clip
"Copied name to clipboard"
}
else {
"Not found"
}
""
}
while ( $true )
In PowerShell, single and double quotes each have a different meaning and significance. Variables will only be expanded in double quotes.
Your query does not work because you use single quotes for the parameter:
-Filter 'Name -like "*$PCName*"'
In this string, $PCName will not be replaced by its value. The double quotes are not significant here, because inside a single quoted string, they are just characters.
You can build the parameter like this:
-Filter ('Name -like "*' + $PCName + '*"')
Additionally, you should remove the return statement and in your example there is no need to create a global variable $global:PCName, you can use $PCName instead
Your main issue is how you were quoting your -Filter. Variables do not expand inside single quotes. Your query was looking for a computer matching the string literal $pcname as supposed to the variable contents.
Also you make the same call twice which is inefficient. You should also know that it is possible to have more than one match with this so you need to be aware of/ account for that possibility.
$PCName=(Read-Host "Enter partial PC name")
write-host "You entered the partial PC Name: $PCName"
#PCName Information Table Display.
$results = Get-ADComputer -SearchBase 'OU=(Disregard)' -Filter "Name -like '*$pcname*'" -Properties IPv4Address
$results | Format-Table Name,DNSHostName,IPv4Address -A
#Progress indicator advisory message.
Write-host "Converting $PCname to full computer name and copying result to your clipboard."
#Clip Line - Retrieves full PC name and copies resolved PC name to clipboard.
$results| Select -ExpandProperty Name | Clip
#End of script advisory message.
Write-host "Full PC Name:$PCName - Resolved and copied to clipboard."
I don't see a need for a global variable here so I removed it. Changed all the Write-Output to Write-Host as that is how you were treating them. If nothing else you have them mixed together so picking one would be more my point.
I had a similar issue with filter (building into an ASP application) and solved it by using curly brackets.
$searchterm = "*$($PCName)*"
-Filter {Name -like $searchterm}
The extra $() is most likely unnecessary in this particular instance as we aren't doing anything with the variable, but it's a habit of mine now.