Hey, Scripting Guy! How Can I Add a User to Multiple Groups?

Hey, Scripting Guy! How Can I Add a User to Multiple Groups?

  • Comments 1
  • Likes

Hey, Scripting Guy! Question

Hey Scripting Guy! It seems that I can never find what I need anymore. I am looking for a Windows PowerShell script that will add a user to multiple groups. The user and the group are in the same organizational unit, and I do not want to have to run the same script multiple times to add a user to multiple groups. It should be easy to do, right?

-- WK

 

 

 

Hey, Scripting Guy! Answer

Hello WK,

I am sorry you are having trouble finding information. You did not mention if it is the Internet in general, or the Script Center Web site that is causing you trouble. If it is the Internet in general, I would suggest you give Bing a try—I have been using it since its inception and have been impressed with both its speed and the results it returns. In fact, I like it so much; I have it installed on my Windows Mobile Smart phone as well. Bing rocks and was a lifesaver when I was on vacation in New York City recently. If you are having problems navigating the Scripting Guys site, I would suggest you watch Script Center 101. We have recently added a really cool control to the main Script Center page that hosts this entertaining and informative video. After watching Script Center 101, you will know as much about the Script Center as I do.

In the meantime, I do not want you to miss out on finding a script, so I wrote the Add-UserToGroups.ps1 script for you. Check it out. it is cool. The complete script is seen here.

Add-UserToGroups.ps1

Param(
   [string[]]$group,
   [string]$user,
   [string]$ou,
   [string]$domain,
   [switch]$whatif,
   [switch]$help,
   [switch]$debug
) #end param

Function Get-ScriptHelp
{
 "Add-UserToGroups.ps1 adds a user to one or more groups. User and group must be in same OU"
 "Add-UserToGroups.ps1 -user cn=myuser -group cn=mygroup -ou ou=myou -domain 'dc=nwtraders,dc=com'"
  "Add-UserToGroups.ps1 -user cn=myuser -group cn=mygroup1,cn=mygroup2 -ou ou=myou -domain 'dc=nwtraders,dc=com'"
 "Add-UserToGroups.ps1 -user cn=myuser -group cn=mygroup -ou ou=myou -domain 'dc=nwtraders,dc=com' -whatif"
} # end function Get-ScriptHelp

Function Add-UserToGroups
{
 Param(
   [string[]]$group,
   [string]$user,
   [string]$ou,
   [string]$domain
 ) #end param
 $ads_Property_Append = 3
 ForEach($g in $group)
 {
   write-debug "Connecting to group: LDAP://$g,$ou,$domain"
   $de = [adsi]"LDAP://$g,$ou,$domain"
    write-debug "Putting user: $user,$ou,$domain"
   $de.putex($ads_Property_Append,"member", @("$user,$ou,$domain"))
   $de.SetInfo()
  } #end foreach
} # end function Add-UserToGroups

Function Get-Whatif
{
  Param(
   [string[]]$group,
   [string]$user,
   [string]$ou,
   [string]$domain
 ) #end param
 ForEach($g in $group)
  {
   "WHATIF: Add user $user,$ou,$domain to $g,$ou,$domain"
  } #end foreach
} #end function Get-Whatif

# *** Entry Point to script ***
if($debug) { $debugPreference = "continue" }
if(-not($user -and $group -and $ou -and $domain))
  { throw ("user group ou and domain required") }
if($whatif) { Get-Whatif -user $user -group $group -ou $ou -domain $domain ; exit }
if($help) { Get-Scripthelp ; exit }

 Write-Debug "Adding user to group ..."
 Write-Debug "Calling Add-UserToGroups function."
 Write-Debug "passing: user $user group $group ou $ou domain $domain"

Add-UserToGroups -user $user -group $group -ou $ou -domain $domain

The first thing the Add-UserToGroups.ps1 script does is create a series of command-line parameters. To create command-line parameters, use the Param statement and separate each parameter with a comma. The group parameter is a string that will accept an array. The square brackets are used to indicate an array of strings. This allows you to supply the name of more than one group from the command line. The group parameter is seen here:

[string[]]$group

The user, ou, and domain parameters are strings. When supplying the user name and the ou name from the command line, quotation marks are not required because the parameter expects a string to be supplied. The domain parameter value must be surrounded with single quotation marks. This is because the domain parts are separated by commas and would be interpreted as an array if they were not grouped by single quotation marks. The user, ou, and domain parameters are seen here:

[string]$user,
[string]$ou,
[string]$domain,

The last three parameters are switched parameters. This means they only work if they are present on the command line. Switched parameters provide an easy way to incorporate additional functionality into the scripts design. Here three switched parameters are defined: whatif, help, and debug. These three parameters correspond to the common parameters that are supported by most cmdlets. In this manner, the Add-UserToGroups.ps1 script will behave in a similar fashion as Windows PowerShell cmdlets and will therefore be easy to use. The switched parameters are shown here:

   [switch]$whatif,
   [switch]$help,
   [switch]$debug

The complete Param section of the script is seen here:

Param(
   [string[]]$group,
   [string]$user,
   [string]$ou,
   [string]$domain,
   [switch]$whatif,
   [switch]$help,
   [switch]$debug
) #end param

When a script accepts command-line parameters, it is a best practice to provide help for the script. In Windows PowerShell 1.0, you can do this by creating a function that displays information about the parameters and acceptable syntax. In Windows PowerShell 2.0, there are tags that allow you to integrate the information with the Get-Help cmdlet. In the Add-UserToGroups.ps1 script, a function named Get-ScriptHelp is created to display the purpose of the script and several examples of allowable syntax. This ensures the script will run on both Windows PowerShell 2.0 and Windows PowerShell 1.0. The Get-ScriptHelp function is called when the script is called with the help switch. The entire Get-ScriptHelp function is seen here:

Function Get-ScriptHelp
{
 "Add-UserToGroups.ps1 adds a user to one or more groups. User and group must be in same OU"
 "Add-UserToGroups.ps1 -user cn=myuser -group cn=mygroup -ou ou=myou
-domain 'dc=nwtraders,dc=com'"
 "Add-UserToGroups.ps1 -user cn=myuser -group cn=mygroup1,cn=mygroup2 -ou ou=myou
-domain 'dc=nwtraders,dc=com'"
 "Add-UserToGroups.ps1 -user cn=myuser -group cn=mygroup -ou ou=myou
-domain 'dc=nwtraders,dc=com' -whatif"
} # end function Get-ScriptHelp

The main portion of the script is the Add-UserToGroups function. This function begins by creating a series of parameters for the function. These parameters correspond to the parameters created by the script itself. The difference is there are no switched parameters for the function. The group parameter is created as an array of strings just like it was at the beginning of the script. Similarly, the user, ou, and domain parameters are defined as strings. This is seen here:

Function Add-UserToGroups
{
 Param(
   [string[]]$group,
   [string]$user,
   [string]$ou,
   [string]$domain
 ) #end param

To update a property in Active Directory, you can use the putex method. This method needs a value from the ADS_PROPERTY_OPERATION_ENUM. The ADS_PROPERTY_APPEND constant is equal to the value 3. When this is set to 3, it instructs the directory service to append the property values to the object.

The ADS_PROPERTY_OPERATION_ENUM values seen in Table 1 are used in the first position of the putex method call.

Table 1

Enumeration name

Enumeration value

  ADS_PROPERTY_CLEAR   

 1

  ADS_PROPERTY_UPDATE  

 2

 

Rather than create an actual constant, you can create a variable and assign the value to it. As long as you do not modify the value of the variable, it will be constant. If you feel the need to protect the value, you could make it a read-only variable. To do this, you would use the following syntax:

New-Variable -Name ads_Property_Append -Value 3 -Option readonly

The advantage of a read-only variable is you can delete it or change the value if you specify the force switched parameter. You therefore obtain protection from inadvertent changes to the variable with the flexibility of making changes if you must do so.

In the Add-UserToGroups function there was no need to protect the variable, and a simple value assignment is used to create and to set the value for the variable. This is seen here:

 $ads_Property_Append = 3

Because there may be more than one group that you wish to assign the user to, the ForEach statement is used to iterate through the $group variable. The variable $g is used to keep track of the position inside the collection. In Windows PowerShell this works if there is a single value in the $group variable or if there are many values. In VBScript, an error is generated when you try to walk through a collection by using For…Each…Next and there is a single value in the variable. This line of code is seen here:

 ForEach($g in $group)
 {

You can use the Write-Debug cmdlet to display debugging information when the script is run with the debug switch. If the script is not run with the debug switch, nothing is displayed on the command line. This is seen here:

Image of nothing displayed on the command line when script is run without debug switch


A well-designed series of Write-Debug statements displays progress information on the Windows PowerShell console. The code that writes to the console is seen here:

   write-debug "Connecting to group: LDAP://$g,$ou,$domain"

Next the [adsi] type accelerator is used to connect to the group. The LDAP protocol is used to make the connection to the group in Active Directory. The returned DirectoryEntry object is stored in the variable $de as seen here:

   $de = [adsi]"LDAP://$g,$ou,$domain"

Now it is time to produce another Write-Debug statement. This is seen here:

    write-debug "Putting user: $user,$ou,$domain"

When the DirectoryEntry object has been created and stored in the $de variable, you can call the putex method to append the user to the member property of the group object. This is seen here:

   $de.putex($ads_Property_Append,"member", @("$user,$ou,$domain"))

Next you will need to commit your changes to Active Directory. To do this, you call the setinfo method from the DirectoryEntry object. This is seen here:

   $de.SetInfo()
  } #end foreach
} # end function Add-UserToGroups

It is time to create the Get-Whatif function. The Get-Whatif function is called when the script is run with the whatif switched parameter. The first thing that must be done is to create the same parameters that are used by the Add-UserToGroups function. This is because the Get-Whatif will accept the command-line parameters that would be used to add a user to one or more groups. This is seen here:

Function Get-Whatif
{
  Param(
   [string[]]$group,
   [string]$user,
   [string]$ou,
   [string]$domain
 ) #end param

Because there could be more than one group that is supplied from the command line, you will need to use the ForEach statement to walk through the group names. Inside the ForEach statement you display the WhatIf information. This is seen here:

 ForEach($g in $group)
  {
   "WHATIF: Add user $user,$ou,$domain to $g,$ou,$domain"
  } #end foreach
} #end function Get-Whatif

After completing all the functions, it is time to design the entry point to the script. The first thing to do is to see if the script was run with the debug switch; if it was, the value of the $debugPreference automatic variable is set to continue. This setting will cause all of the Write-Debug cmdlets to display the debug information. The line of code that causes this to happen is seen here:

if($debug) { $debugPreference = "continue" }

To assign a user to a group, you need to know the name of the user, the group, the ou, and the domain the objects reside in. To check for all of this, use the if statement. Inside the if statement, the –not operator is used to check for missing items. The –and operator is used to ensure that all the parameters are present. If one of the parameters is missing, the throw statement is used to raise an error and halt execution of the script. This is seen here:

if(-not($user -and $group -and $ou -and $domain))
  { throw ("user group ou and domain required") }

If the script is run with the whatif parameter, you do not want to actually execute the script. Instead, you want to see what the parameters would do. To do this, the Get-Whatif function is called. This is seen here:

if($whatif) { Get-Whatif -user $user -group $group -ou $ou -domain $domain ; exit }

To display help information, the script is called with the help parameter. When the script is called with the help switched parameter, it will create a variable $help. If that variable exists, the Get-ScriptHelp function is called, and the script exits. This is seen here:

if($help) { Get-Scripthelp ; exit }

The next-to-the-last thing that is done is a series of Write-Debug statements are used to display detailed tracking information about the progress of the script. These are seen here:

 Write-Debug "Adding user to group ..."
 Write-Debug "Calling Add-UserToGroups function."
 Write-Debug "passing: user $user group $group ou $ou domain $domain"

The last thing to be done is to call the Add-UserToGroups function and pass the command-line parameters. This is seen here:

Add-UserToGroups -user $user -group $group -ou $ou -domain $domain

When the Add-UserToGroups function is called, it adds the specified user to the specified groups. This is seen here:

Image of the specified user added to the specified groups

 

WK, we hope you have enjoyed this discussion on adding users to multiple groups. We encourage you to follow us on Twitter, join our group on Facebook, and hang out in the The Official Scripting Guys Forum. Until tomorrow, peace!

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • <p>Hi! Thx for great script! But i have some errors(( And dont know what they means.</p> <p>...</p> <p>DEBUG: Putting user: cn=user,ou=groups ou=marketing ou=company ou=enterprise -domain,dc=test,dc=net</p> <p>The following exception occurred while retrieving member &quot;putex&quot;: &quot;Unknown error (0x80005000)&quot;</p> <p>At C:\Users\administrator\Desktop\My_Scripts\addusertogroups.ps1:33 char:13</p> <p>+ &nbsp; &nbsp;$de.putex &lt;&lt;&lt;&lt; ($ads_Property_Append,&quot;member&quot;, @(&quot;$user,$ou,$domain&quot;))</p> <p> &nbsp; &nbsp;+ CategoryInfo &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: NotSpecified: (:) [], ExtendedTypeSystemException</p> <p> &nbsp; &nbsp;+ FullyQualifiedErrorId : CatchFromBaseGetMember</p> <p>The following exception occurred while retrieving member &quot;SetInfo&quot;: &quot;Unknown error (0x80005000)&quot;</p> <p>At C:\Users\administrator\Desktop\My_Scripts\addusertogroups.ps1:34 char:15</p> <p>+ &nbsp; &nbsp;$de.SetInfo &lt;&lt;&lt;&lt; ()</p> <p> &nbsp; &nbsp;+ CategoryInfo &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: NotSpecified: (:) [], ExtendedTypeSystemException</p> <p> &nbsp; &nbsp;+ FullyQualifiedErrorId : CatchFromBaseGetMember</p>