Dhiwakar Ravikumar
Dhiwakar Ravikumar

Reputation: 2207

Checking if a local user account/ group exists or not with Powershell

There are two parts to this question.

  1. I want to check if a local user exists or not before I go ahead and create it. So far I've come up with a simple script to check if a local user exists or not. Here's the script to check if a user exists before I go ahead and create it.
$password = ConvertTo-SecureString -String "password" -AsPlainText -Force
$op = Get-LocalUser | Where-Object {$_.Name -eq "testuser1"}
if ( -not $op)
 {
  New-LocalUser testuser1 -Password $password | Out-Null
 }

I tested this one out on my setup and it works fine for the most part without throwing any exception. Is there a better, quicker way to check if a user exists ? Also, is the script I'm using foolproof i.e. would it be better to handle it using ErrorAction or using try....catch ?

I'll be using this script for checking more than a couple of user accounts before I go ahead and create them.

  1. Why is $op different in the following cases ?

CASE 1

enter image description here

CASE 2

enter image description here

I understand that Out-String is the reason behind this difference in output but I would've expected the output to have been more than just testuser1 in CASE 1.

I'm new to Powershell so can someone please help me understand why there's a difference in output ?

Upvotes: 6

Views: 53223

Answers (5)

Dennis
Dennis

Reputation: 1784

The old style usage of [ADSI] and WinNT: is also a valid option even with PowerShell 7.
And it works equally well with local as well as with domain accounts.

But it's quite legacy.

$UserName = './TestUser'
$WinNtUser = [ADSI]"WinNT://$UserName,user"

if (! $WinNtUser.Name) {
  throw "User $UserName was not found"
}

Upvotes: 0

Jonathan176
Jonathan176

Reputation: 115

The first line calls the Get-LocalUser commandlet and uses the Name parameter to Specify the user be searched for. If that user is found the assignment of the variable $UserID will happen. If Get-LocalUser cannot find the user then it errors out and no assignment happens. Specifying the ErrorAction "SilentlyContinue" will tell PowerShell not to stop or alert that there if there was an error making the assignment.

The If($UserID) test will return True if the assignment of the Variable happened successfully and False if did not.

$UserID = Get-LocalUser -Name 'UserName' -ErrorAction SilentlyContinue
if($UserID){
   Write-Host 'User Found'
}else{
    Write-Host 'User Not Found'
} #end if user exists

Upvotes: 4

SteloNLD
SteloNLD

Reputation: 601

Use Try/Catch, most of the time it's faster to just ask and let Powershell handle the searching ;)

Especially with Long User lists, retrieving all the users and then iterating trough all of them will slow things down, just asking for a specific user is much faster but you need to handle the error if the user does not exist.

See example below:

Clear-Host
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'

#User to search for
$USERNAME = "TestUser"

#Declare LocalUser Object
$ObjLocalUser = $null

try {
    Write-Verbose "Searching for $($USERNAME) in LocalUser DataBase"
    $ObjLocalUser = Get-LocalUser $USERNAME
    Write-Verbose "User $($USERNAME) was found"
}
catch [Microsoft.PowerShell.Commands.UserNotFoundException] {
    "User $($USERNAME) was not found" | Write-Warning
}
catch {
    "An unspecifed error occured" | Write-Error
    Exit # Stop Powershell! 
}

#Create the user if it was not found (Example)
if (!$ObjLocalUser) {
    Write-Verbose "Creating User $($USERNAME)" #(Example)
    # ..... (Your Code Here)
}

About outputting certain data, I recommend that you explicitly define what you want to output, this way their will be no surprises and it makes thing clearer in your code.

See the example below, I explicitly defined the 3 properties I wanted and then forced it into a Table-View, to finish I converted it to a string, so no surprises for me any more ;)

Get-LocalUser | Select Name, Enabled, PasswordLastSet | Format-Table | Out-String

Example output

Name               Enabled PasswordLastSet    
----               ------- ---------------    
Administrator        False                    
DefaultAccount       False                    
Gast                 False                    
Test-Gebruiker        True 24-12-2017 01:58:12

Upvotes: 9

Roger
Roger

Reputation: 101

You can use measure to check if user exist

$op = Get-LocalUser | where-Object Name -eq "yourusername" | Measure
if ($op.Count -eq 0) {
     # DO SOMETHING
} else {
     # REPORT SOMETHING
}

Upvotes: 5

Mustafa Zengin
Mustafa Zengin

Reputation: 3023

Write-Host calls ToString() method implementation of an object behind the scenes.

Write-Host $op is equivalent to

Write-Host $op.ToString()

Get-LocalUser | Where-Object {$_.Name -eq "testuser1"} returns a LocalUser object. LocalUser.ToString() implementation returns Name property, that's why you see testuser1 as output.

Out-String on the other hand, converts the whole output of the command, which is a table representation of LocalUser object with 3 properties.

In Case 2, you can only use that output as a String object, whereas in Case 1, $op is a LocalUser object that you can manipulate or access properties. For example, you can print more properties:

Write-Host $op.Name, $op.Enabled, $op.Description

In order to see all the properties/methods available on an object, run Get-Member cmdlet:

$op | Get-Member

Upvotes: 1

Related Questions