Q: Some of the things we do in our logon scripts require the user to be a local administrator. How can the script tell if the user is a local administrator or not, using PowerShell 7.
A: Easy using PowerShell 7 and the LocalAccounts module
Local Users and Groups
The simple answer is of course, easily. And since you ask, with PowerShell 7! But let’s begin lets begin by reviewing local users and groups in Windows.
Every Windows system, except for Domain Controllers, maintains a set of local accounts – local users and local groups. Domain controllers use the AD and do not really have local accounts as such. You use these local accounts in addition to domain users and domain groups on domain-joined hosts when setting permissions. You can log on to a given server using a local account or a domain account. On Domain Controllers you can only log in using a domain account.
As with AD groups, local groups and local users each have a unique Security ID (SID). When you give a local user or group access to a file or folder, Windows adds that SID to the object’s Access Control List. This is the same way Windows enables you to give permissions to a local file or folder to any Active Directory user or group.
Additionally, Windows and some Windows features create “well known” local groups. The intention is that you add users to these groups to enable those users to perform specific administrative functions on just those servers.
Traditionally, you might have used the Wscript.Network
COM object, in conjunction with ADSI. You can, of course, use the older approach in side PowerShell 7, but why bother? The good news with PowerShell 7, you can use the Microsoft.PowerShell.LocalAccounts
module to manage local accounts. At the time of writing, this is a Windows-only module.
The Microsoft.PowerShell.LocalAccounts module
In PowerShell 7 for Windows, you can use the Microsoft.PowerShell.LocalAccounts
module to manage local users and group. This module is a Windows PowerShell module which PowerShell 7 loads from C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.LocalAccounts
.
This module contains 15 cmdlets, which you can view like this:
PS> Get-Command -Module Microsoft.PowerShell.LocalAccounts
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Add-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Disable-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Enable-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet New-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet New-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Rename-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Rename-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Set-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Set-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
As you can tell, these cmdlets allow you to add, remove, change, enable and disable a local user or local group And they allow you to add, remove and get the local group’s members. These cmdlets are broadly similar to the ActiveDirectory cmdlets, but work on local users. And as noted above, you can use domain users/groups as a member of a local group should you wish or need to.
You use the Get-LocalGroupMember
command to view the members of a local group, like this:
PS> Get-LocalGroupMember -Group 'Administrators'
ObjectClass Name PrincipalSource
----------- ---- ---------------
Group COOKHAMDomain Admins ActiveDirectory
User COOKHAM24Administrator Local
User COOKHAMJerryG ActiveDirectory
User COOKHAM24Dave Local
As you can see in this output, the local Administrators group on this host contains domain users and groups as well as local users
Is the User an Administrator?
It’s easy to get membership of any local group, as you saw above. But what if you want to find out if a given user is a member of some local administrative group? That too is pretty easy and take a couple of steps. One way you can get the name of the current user is by using whoami.exe
. Then you can get the members of the local administrator’s group. Finally, you check to see if the currently logged on user is a member of the group. All of which looks like this:
PS> # Get who I am
PS> $Me = whoami.exe
PS> $Me
Cookham\JerryG
PS> # Get members of administrators group
PS> $Admins = Get-LocalGroupMember -Name Administrators |
Select-Object -ExpandProperty name
PS> # Check to see if this user is an administrator and act accordingly
PS> if ($Admins -Contains $Me) {
"$Me is a local administrator"}
else {
"$Me is NOT a local administrator"}
Cookham\JerryG is a local administrator
If the administrative group contains a user running the script, then $Me
is a user in that local admin group.
In this snippet, we just echo the fact that the user is, ir is not, a member of the local administrators group. You can adapt it to ensure a user is a member of the appropriate group before attempting to run certain commands. And you can also adapt it to check for membership in other local groups such as Backup Operators or Hyper-V Users which may be relevant.
In your logon script, once you know that the user is a member of a local administrative group, you can carry out any tasks that requires that membership. And if the user is not a member of the group, you could echo that fact, and avoid using the relevant cmdlets.
Summary
Using the Local Accounts module in PowerShell 7, it’s easy to manage local groups! You can, of course, manage the groups the same way in Windows PowerShell.
Tip of the Hat
This article was originally a VBS based solution as described in an earlier blog post. I am not sure who the author of the original post was – but thanks.
That's not entirely in PowerShell. It cheats and uses WhoAmI.exe. Here is what I use:
<code>
My approach returns "false" if the current user is an admin but the current process is not elevated. Once can still use $MyID.Name instead of WhoAmI.exe though, like this:
<code>
I like this way of doing it rather going into local groups.
The script on top misses UAC, which might not have the user with admin privileges the moment he starts the job.
Yours does it in my eyes the right way.
Thanks Fleet Command. You show another way to do it.
I like using Whoami and am old school in that regard. Another way to create $Me would be:
<code>
Interestingly, using .NET in this way to create $Me is significantly faster then using Whowmi.exe:
<code>
So there are (*at least) two ways to calculate $ME - both work and one is a lot slower.
With respect, why do you even create the $WindowsPrincipal object when you have no intentions of calling IsInRole()? $MyID.Name is the same as $WindowsPrincipal.Identities.Name. You're just imposing a few milliseconds of performance penalty. This scripts demonstrates that:
<code>
Here is the output:
Method 1: 14.7724 milliseconds
DOMINION\SarahKerrigan
Method 2: 19.956 milliseconds
DOMINION\SarahKerrigan
I love WordPress (at times). Fleet Command - I did not use $WindowsPrincipal in the original post. You may have been referring to comment vs the op. When I create code samples, I tend to use variables to hold output as they may come in useful later - and in a part of a script not shown here. But you ake a blood point that
Looking at your function - I note that in the second...
Q: Some of the things we do in our logon scripts require the user to be a local administrator. How can the script tell if the user is a local administrator or not, using PowerShell 7.
A: Easy using PowerShell 7 and the LocalAccounts module.
But... but... but... this has nothing to do with PowerShell 7. Though that was the question.
This has been doable for well before PowerShell ever existed (including using legacy tools other than whoami.exe;...
Thanks for your comment, Daniel.
The local accounts module is found in the WIn32 folder - so is a Windows PowerShell module rather than a PowerShell module. And, some of us with long memories of the development of PowerShell 7.x may remember that what you say was not always the case. I closely monitored the development of PowerShell 7, and recall this GitHub issue https://github.com/PowerShell/PowerShell/issues/4305 (and its resolution). With the benefit of hindsight, I could...