PowerShell is Logical… Usually

Alternative title: questions I’d ask Jeffrey Snover in an AMA.

I use PowerShell at work on a daily basis. It’s not usually anything complicated, but I couldn’t do my job effectively without it. Office 365 is great, but the GUI is slow, and PowerShell is much faster. Managing Active Directory is easy, but managing objects at any scale is always quicker once scripted, especially when you want to repeat tasks.

Today, I needed to deploy a change to local user accounts on our clients. We have a standard local user account for use at events, so non-staff can temporarily use a laptop without accessing company data.

Our domain policies dictate all accounts must have passwords, and password complexity requirements are applied, even to local accounts. To satisfy this, there’s a standard, unprivileged account, set up on each device that requires it, with a uniform password.

Last year, I rolled out a deployment server, because why deploy hardware manually when you don’t have to? Unfortunately, the new deployment system and the old method of deploying a local account don’t work well together. The password used for the local account conflicts with the configuration settings applied by the deployment server.

This is easy to fix. It requires a change to the password. You can do this individually on computers, but that takes a lot of time and disturbs staff. Therefore, PowerShell is the answer.

There are four PowerShell cmdlets for managing local users:

  • New-LocalUser
  • Get-LocalUser
  • Set-LocalUser
  • Remove-LocalUser

I needed to:

  • Check for the existence of the local user account
  • Create the account if it doesn’t exist
  • Update the account if it does exist

So, I wrote a script that could do this, which I could then distribute. I found it didn’t work consistently, and I had to do a bit of digging into Microsoft’s PowerShell documentation to find the cause. It was simple, but it’s a little illogical.

PowerShell has different types of parameters. Sometimes it’s looking for an integer (a number), sometimes a string (free text, essentially), sometimes a boolean (something that’s true, or something that’s false), sometimes a switch parameter (requires no further input).

There are two differences between the Set-LocalUser cmdlet and the New-LocalUser cmdlet.

First, the New-LocalUser cmdlet has the following parameter:

-UserMayNotChangePassword

Whereas the Set-LocalUser cmdlet has the following parameter:

-UserMayChangePassword

Essentially, these switches do the same thing, but in reverse, and it’s difficult to remember which way round it is. Why can’t they both just use the same syntax?

However, there’s a second issue, affecting both these cmdlets, and another one:

-PasswordNeverExpires

In the New-LocalUser cmdlet, these parameters are switch parameters. You include them and there is no further input.

In the Set-LocalUser cmdlet, these parameters are boolean – you have to set them to $True or $false.

It’s easy enough to fix, but it’s odd logic, eh?