Adding users in Powershell

I recently ran into an issue where large numbers of client UPNs were not being copied properly by the client, and would need to be corrected manually so as to make sure all users were being added successfully.

Instead of burning out my wrists, I thought that it would be a good idea to automate the process in Powershell.

My first attempt looked something like this:

<# PowerShell script to populate the Group $mygroup 
with each UPN listed on the given text file $csv
c:\adduserstogroup\Adduserstogroup.ps1 #>

Function Write-Log {
	Param ([string]$string)
	(  $string) | Out-File -FilePath $LogFileName -Append
}
   
<# Load the AD Routine #>
import-module activedirectory
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -scope currentuser
 
<# Load Variables #>
Write-host "This script will populate specified by the Group variable $mygroup"

$mygroup = "000-Test"
$mydir = "G:\Scripts\new\"
$csvlocation  = $mydir + "elect.csv"
$csv = Get-Content $csvlocation | ConvertFrom-Csv
$LogFileName = $MyDir + "adduserstogroupoutput.CSV" 
New-Item $LogFileName -ItemType file -Force 
 
write-host "Adding Group Members to $mygroup"
Write-Log ("Adding Group Members to " + $mygroup)    
<# Iterate through the CSV #>
$csv | foreach-object {
    $user = Get-ADUser -Filter "UserPrincipalName -eq '$($_.username)'"
    if ($user){
        Add-ADGroupMember -Identity $mygroup -Members $user
        write-host "Added User " $user.UserPrincipalName
        Write-Log ($user.UserPrincipalName + " added")  		
    }
    else{
        Write-host "Unable to add user " $user.UserPrincipalName
        Write-Log ($_.username + " failed")  	
    }
}

This worked OK at adding users to the GPO quickly, but left a lot of room for errors in several places:

  1. The name of the file is hard-coded, so unless you copy and paste new data into the original CSV each time, you may copy the wrong people.
  2. The GPO is also hard-coded, so you if you forget to modify the script, you may copy the right people to the wrong place.
  3. If the user address given by the client is not actually the UPN, but rather an alias, you will only see that it failed.

Therefore, I made several modifications.

<# PowerShell script to populate the AD Group $ElectionGroup  with everyone from text file $csv
R:\new\AddUsersToGroup-pm.ps1 #>
   
<# .SYNOPSIS #>
Param([Parameter(Mandatory=$True,HelpMessage="Enter the name of the election AD Group")][String]$ElectionGroup)

<#Uncomment this if you want a more verbose prompt
Param([Parameter(HelpMessage="Enter the name of the election AD Group")][String]
$ElectionGroup=$(Read-Host -prompt "Enter the name of the election AD Group"))#>

Function Write-Log {
	Param ([string]$string)
	(  $string) | Out-File -FilePath $LogFileName -Append
}
   
<# Load the AD Routine #>
import-module activedirectory
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -scope currentuser

<# hard coded directory strings
these could be parameterized as well #>
$mydir = "R:\new\"

<# you may wish to change this to 'users.csv' #>
$csvlocation  = $mydir + "elect.csv"
$csv = Get-Content $csvlocation | ConvertFrom-Csv
$LogFileName = $MyDir + "adduserstogroupoutput.CSV" 

<# prime log messages to CSV #>
New-Item $LogFileName -ItemType file -Force

<# store user UPNs here #>

$successes = @()
$aliases = @()
$failures = @()
  
<# Iterate through each UPN listed in the CSV 
note that the column in the source CSV \
must be titled 'username' #>
$csv | foreach-object {

    $user = Get-ADUser -Filter "UserPrincipalName -eq '$($_.username)'"
    $alias = Get-ADUser -Filter "EmailAddress -like '$($_.username)'"

    if ($user){

        if ($ElectionGroup -contains $user) {

            $successes += $_.username
            Write-Log ($_.username + "is already a member of this election group.")
            Write-Host ($_.username + "is already a member of this election group.")

        } else {

            Add-ADGroupMember -Identity $ElectionGroup -Members $user
            $successes += $_.username
            Write-Log ($user.UserPrincipalName + " added")  
            Write-Host ($user.UserPrincipalName + " added")
        }	
            
    } elseif ($alias){

        if ($ElectionGroup -contains $alias) {
            
            Write-Log ($_.username + "is already a member of this election group.")
            Write-Host ($_.username + "is already a member of this election group.")


        } else {
            
            # Comment this out if you would like to confirm the suggestions before adding
            Add-ADGroupMember -Identity $ElectionGroup -Members $alias
            Write-Log ("Alias " + $alias.UserPrincipalName + " added")
            Write-Host ("Alias " + $alias.UserPrincipalName + " added")
            $aliases += $alias

        }
        

    } else {

        Write-Log ($_.username+ " failed to be added")
        Write-Host ($_.username+ " failed to be added")
        $failures += $_.username
    
    }

}

<# get a timestamp value and prime file to be exported #>
$timestamp = Get-Date -format yyyyMMdd
$OutputFile = "$timestamp-electionotput.txt"
$OutputPath = Join-Path -Path $mydir -ChildPath $OutputFile

<# define a hashtable of parameters for Out-File. #>
$outParams = @{

    FilePath = $OutputPath
    Encoding = "ASCII"
    Append = $True
    Width = 120

}

<# save the results to a .txt file report #>
$header = @"
Election Group User Report $((Get-Date).ToShortDateString())

*******************
Data Source = $csvlocation

*******************
Successfully Added
*******************

"@

$header | Out-File @outParams
$successes | Format-Table -AutoSize | Out-file @outParams

$header = @"


*******************
Aliases
*******************

"@

$header | Out-File @outParams
$aliases | Format-Table -AutoSize | Out-file @outParams

$header = @"


*******************
Failures
*******************

"@

$header | Out-File @outParams
$failures  | Format-Table -AutoSize | Out-file @outParams

<# write report file to the pipeline #>
Get-Item -Path $OutputPath

The addition of a formatted .txt report, as well as parameterizing the $ElectionGroup and $CSV variables, made things significantly easier. Additionally, the following block made it a 2-step process to determine which addresses where malformed, given incorrectly, or matched a user alias in on-prem Active Directory:

<# store user UPNs here #>

$successes = @()
$aliases = @()
$failures = @()
  
<# ... #>
$csv | foreach-object {

    $user = Get-ADUser -Filter "UserPrincipalName -eq '$($_.username)'"
    $alias = Get-ADUser -Filter "EmailAddress -like '$($_.username)'"

    if ($user){

        if ($ElectionGroup -contains $user) {

            $successes += $_.username
            Write-Log ($_.username + "is already a member of this election group.")
            Write-Host ($_.username + "is already a member of this election group.")

        } else {

            Add-ADGroupMember -Identity $ElectionGroup -Members $user
            $successes += $_.username
            Write-Log ($user.UserPrincipalName + " added")  
            Write-Host ($user.UserPrincipalName + " added")
        }	
            
    } elseif ($alias){

        if ($ElectionGroup -contains $alias) {
            
            Write-Log ($_.username + "is already a member of this election group.")
            Write-Host ($_.username + "is already a member of this election group.")


        } else {
            
            # Comment this out if you would like to confirm the suggestions before adding
            Add-ADGroupMember -Identity $ElectionGroup -Members $alias
            Write-Log ("Alias " + $alias.UserPrincipalName + " added")
            Write-Host ("Alias " + $alias.UserPrincipalName + " added")
            $aliases += $alias

        }
        

    } else {

        Write-Log ($_.username+ " failed to be added")
        Write-Host ($_.username+ " failed to be added")
        $failures += $_.username
    
    }

}