Hey, Scripting Guy! How Can I Use Windows PowerShell to Add a Domain User to a Local Group?

Hey, Scripting Guy! How Can I Use Windows PowerShell to Add a Domain User to a Local Group?

  • Comments 9
  • Likes
Hey, Scripting Guy! Question

Hey, Scripting Guy! I recently came across your article where you showed people how to use VBScript to add a domain user to a local group. How can I do that same task using Windows PowerShell?

-- KE

SpacerHey, Scripting Guy! AnswerScript Center

Hey, KE. Before we begin we thought we should mention that the Scripting Guy who writes this column has a new favorite TV commercial. He’s not even sure what the commercial is advertising (other than some car maker) but it shows two identical cars (with identical drivers and passengers) driving parallel roads. When the two roads merge together, the cars magically merge together as well, and the two cars seamlessly become one car.

Admittedly, that’s not that big of a deal. Instead, what’s really cool about the commercial isn’t the commercial itself, but the disclaimer that accompanies it:

Professional driver on closed course. Do not attempt.

To be honest, that’s extremely good advice. For example, suppose you’ve had yourself cloned, and both you and your clone drive identical cars. Should you drive down parallel roads and then smash the cars into one another, assuming that the two cars will seamlessly merge into one? No, you should not.

Well, not unless both you and your clone happen to be professional drivers on a closed course. Then it’s OK.

Or at least that’s what they tell you on TV. To tell you the truth, though, it doesn’t look all that hard to us. Why don’t you give it a try and let us know how it goes?

Note. At the risk of giving the poor old Scripting Editor a heart attack, we take that back: don’t give this a try, even if you are a professional driver on a closed course. And no, not even if your clone is also a professional driver.

Oh, and a word of advice: to the best of our knowledge, no court in the world will accept “The Scripting Guys told me to do it” as a legitimate excuse for doing something stupid.

Nor should they.

But don’t worry; this doesn’t mean that only professional drivers on closed courses get to have any fun. Granted, you can’t smash two cars together to see if you can somehow get them to merge into one car. (Although, then again … no, never mind. Don’t even think about it. Or, at the least, don’t tell anyone that the Scripting Guys told you to think about it.) But who cares? Believe it or not, you can still have fun without smashing two cars together. For example, you don’t need to be a professional driver on a closed course in order to write a Windows PowerShell script that adds a domain user to a local group. Instead, all you have to do is put together something similar to this:

$objUser = [ADSI]("WinNT://fabrikam/kenmyer")
$objGroup = [ADSI]("WinNT://atl-fs-001/Administrators")

$objGroup.PSBase.Invoke("Add",$objUser.PSBase.Path)

So what’s going on here? Good question. In the first line, we’re using the [ADSI] type adapter to create an object reference to an Active Directory user account; more specifically, we’re creating an object reference to the fabrikam\kenmyer user account. So what is the [ADSI] type adapter? That’s also a good question. In order to make certain operations a little easier for, and a little more relevant to, system administrators, PowerShell includes several “type adapters” such as [ADSI]; in this case, the type adapter makes it easier to connect to ADSI, regardless of whether you’re using ADSI to manage Active Directory or to manage local accounts. If it wasn’t for the type adapter, you’d need to go through the .NET Framework and conjure up an instance of the System.DirectoryServices.DirectoryEntry class in order to work with ADSI. The type adapter simply creates that instance for you.

Hmmm, that’s another good question: if this is Active Directory why did we use the WinNT provider; aren’t you supposed to use the LDAP provider when working with Active Directory?

Yes, you are, provided that you are working exclusively with Active Directory. In this case, however, we aren’t working exclusively with Active Directory; instead we’re working with local accounts as well. Local accounts require the use of the WinNT provider, and the WinNT provider doesn’t know how to work with OUs and other Active Directory components. Because of that, we have to use the old-fashioned domain/username syntax.

After we create an object reference to the user account we repeat the process to create a second object reference, this one to our local group. For our sample script, that’s the Administrators group on the computer atl-fs-001:

$objGroup = [ADSI]("WinNT://atl-fs-001/Administrators")

Once we’ve done that we can add the domain user Ken Myer to our local Administrators group by using the following line of code:

$objGroup.PSBase.Invoke("Add",$objUser.PSBase.Path)

Yet another good question: what the heck is that PSBase stuff? Well, when you use Windows PowerShell to connect to an object, PowerShell will often decide, in advance, which methods and properties will be exposed to you. That’s usually fine, except that sometimes PowerShell guesses wrong; sometimes it fails to show the property or method you really need. That’s the case here; if you bind to a local group account (like the Administrator account) PowerShell exposes only a handful of methods and properties:

Name                        MemberType
----                        ----------
ConvertDNWithBinaryToString CodeMethod
ConvertLargeIntegerToInt64  CodeMethod
Description                 Property
groupType                   Property
Name                        Property
objectSid                   Property

That’s where the PSBase object comes in. PSBase lets you get at the “raw” object behind the object PowerShell exposes by default; in other words, PSBase lets you get at all the properties and methods of the object:

Name                      MemberType
----                      ----------
Close                     Method
CommitChanges             Method
CopyTo                    Method
CreateObjRef              Method
DeleteTree                Method
Dispose                   Method
Equals                    Method
GetHashCode               Method
GetLifetimeService        Method
GetType                   Method
InitializeLifetimeService Method
Invoke                    Method
InvokeGet                 Method
InvokeSet                 Method
MoveTo                    Method
RefreshCache              Method
Rename                    Method
ToString                  Method
AuthenticationType        Property
Children                  Property
Container                 Property
Guid                      Property
Name                      Property
NativeGuid                Property
NativeObject              Property
ObjectSecurity            Property
Options                   Property
Parent                    Property
Password                  Property
Path                      Property
Properties                Property
SchemaClassName           Property
SchemaEntry               Property
Site                      Property
UsePropertyCache          Property
Username                  Property

In this case, PSBase exposes the Invoke method. In turn, we can then call Invoke, passing it the Add parameter and the Path property containing the user account in Active Directory. What will that do for us? You got it: it will add the user in question (fabrikam\kenmyer) to the local Administrators group on atl-fs-001.

Note. By the way, you might notice that, when calling the Invoke method, we had to use the PSBase object of our user account: $objUser.PSBase.Path. That’s because, by default, we don’t have access to the object Path. The only way to get to that is to use PSBase.

Believe it or not, KE, that’s all you have to do. Run this script, and Ken Myer’s Active Directory account will be added to the local Admins account. Give it a try and see for yourself.

Remember, though, don’t try smashing two cars together for yourself. For that matter, don’t try smashing two anythings together. Several years ago, the Scripting Guys tried an experiment in which we had Peter Costantini and Dean Tsaltas run as fast as they can and then smash together. The hope was that, by combining the two, we would produce some sort of Super Scripting Guy. So what did we end up with instead? Peter and Dean, exactly as they are today.

Let that be a warning to you all.

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Dear Dr. Scripting Guy -

    How would you expand this script to perform this action on multiple remote PC's at the same time?  Like having it read the PC names from text file or something.  (We don't use true AD, that's why this Powershell script is handy, otherwise we would have a GPO implemented for it).  Thanks much!

  • # Add, Remove or List users in a server's local group.  User is assumed to be a domain user.

    # Ex: .\manageLocalGroup.ps1 -group Administrators -user user_id -server server_name

    param($server, $group, $user, $action)

    if (! $server) {

    $server = read-host "Enter server: "

    }

    if (! $group) {

    $group = read-host "Enter group: "

    }

    if (! $action) {

    $action = read-host "Add, Remove or List: "

    }

    $objGroup = [ADSI]("WinNT://$server/$group")

    if ($action.ToLower() -eq "list") {

    $members = @($objGroup.psbase.Invoke("Members"))

    $members | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}

    }

    else {

    if (! $user) {

    $user = read-host "Enter domain user id: "

    }

    $objADUser = [ADSI]("WinNT://domain/$user")

    $objGroup.PSBase.Invoke($action,$objADUser.PSBase.Path)

    }

  • I want to be able to add a user to a server's administrators group from my workstation but I need to do it not as the myself (the account I'm logged into my workstation as) but as my admistrator account (an account I'm not allowed to login as).  Is this possible?  Can I run the "$objGroup.PSBase.Invoke("Add",$objUser.PSBase.Path)" command and pass it different credentials?

  • Dear Dr. Scripting Guy -

    How can I add "NT Authority\Authenticated Users (S-1-5-11)" or "\Everyone" to the local system group using powershell?

    Anoop

  • I have Windows 2008 R2 Server

    I have a Local admin right on a server that joined a domin, I can't use the code above to add domain accounts for the reason that a domain credential is requierd, I have alreay a domain user account the can be used for that purpose.

    The question is: How do I refrence the domain user account Credential or incorporate it inotio the code?

    Best Regards,

    Sam

  • Thank you for the post, very enlightening.

    I have been able to write a script to change a local accounts password using ADSI.

    Question: How could I change a local account on a different domain?

    Current code:

    $account = [ADSI]("WinNT://$Computer/$userToChange,user")

    $account.pbase.invoke("setpassword",$password")

    What I want to do:

    #connect to the computer using a different account other than the one I'm logged into (type username + password)

    #same thing as above

  • $objGroup.PSBase.Invoke("Remove",$objUser.PSBase.Path)

  • I'm trying to run this simple script as part of my task sequence in SCCM.  When it runs, it fails with the following.  I've been racking my brain for 2 weeks.  The task is running with Domain Admin credentials, and UAC is disabled but it still fails.

    Exception calling "Invoke" with "2" argument(s): "Unknown error (0x80005000)"

    At C:\_SMSTaskSequence\WDPackage\Scripts\AddISTech.ps1:11 char:24

    + $objGroup.PSBase.Invoke <<<< ("Add",$objUser.PSBase.Path)

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    Any ideas?