Automating Active Directory account creation with Powershell
Earlier this year I set about simplifying the user account creation process for the company I work for. Previously when someone joined the company the user account creation was a manual process. Some of the tasks we manually undertook were:
- Create the account and Exchange mailbox;
- Set relevant attributes (Job Title, Office Address etc);
- Enable the user for office communicator;
- Set the calendar permissions so that everyone can view the persons calendar;
I chose Powershell as my tool of choice, it’s extremely flexible for stuff like this and most of the management functionality comes out the box with Exchange 2007 and later. I initially used Glen Scales’ EWS module for setting permissions and other bits but as we moved to Exchange 2010 the need for EWS disappeared (Thanks to functionality like Set-MailboxFolderPermissions).
The only third-party software I now use is Quest’s ActiveRoles Management Shell for Active Directory as there doesn’t seem to be a decent way to set custom attributes on a user account. Short of writing my own managed code to do it, or calling another application to make the change Quest’s tool seems to be the best choice.
I eventually came up with the following quick and dirty script to create users, based on the contents of a CSV file it will:
- Create the mailbox (uses New-Mailbox);
- Set attributes on the AD account such as the job title, office address etc;
- Set the default calendar permissions to ‘Reviewer’
- Set attributes on the account, enabling it to use Office Communications Server
- Generate a welcome letter to the user, including the OWA address and other bits of information
The format of the CSV file is as follows:
GivenName,Surname,Password,PhisicalDeliveryLocation,JobTitle John,Doe,MyFirstPassword123!,London,Test Account
And finally, the PowerShell script itself:
# # Create user accounts in AD, Exchange and OCS. # This script will read a CSV file and create user accounts based on that information. # # Requirements: # [+] http://www.quest.com/powershell/activeroles-server.aspx (For setting # attributes on an AD DS account) # [+] Exchange Management Console installed (for Powershell stuff, new-mailbox, # Get-MailboxDatabase etc). # #import-module activedirectory; Add-PSSnapin Quest.ActiveRoles.ADManagement $cfgTab = [char]9 $cfgCompany = "NW Traders"; $cfgOCSHomeServer = "CN=LC Services,CN=Microsoft,CN=OCSSRV01,CN=Pools,CN=RTC Service,CN=Services,CN=Configuration,DC=nwtraders,DC=msft"; # OCS Server $cfgMailDomain = "@nwtraders.msft"; #E-Mail Domain #============================================================================= # A series of hash tables for office information. #============================================================================= $cfgLondon = @{ "Address" = "10 Downing Street, London, SW1A 2AA"; "Telephone" = "+44 2079 250 918"; "OU" = "OU=London,OU=Europe,OU=Users,DC=NWTRADERS,DC=MSFT"; "DC" = "LONDON" }; $cfgWashington = @{ "Address" = "The White House, 1600 Pennsylvania Avenue NW, Washington, DC 20500"; "Telephone" = "+1 202 456 1414"; "OU" = "OU=Washington,OU=US,OU=Users,DC=NWTRADERS,DC=MSFT"; "DC" = "WASHINGTON" }; #============================================================================= # Creates an array of the above hash tables. #============================================================================= $cfgOffices = @{ "London" = $cfgLondon; "Washington" = $cfgWashington; }; #============================================================================= # Displays a select file dialog box, returning the path to a CSV file. #============================================================================= function chooseCSVfile { param([string]$Title,[string]$Directory,[string]$Filter="CSV Files (*.csv)|*.csv") [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog $openFileDialog.InitialDirectory = $Directory $openFileDialog.Filter = $Filter $openFileDialog.Title = $Title $openFileDialog.ShowHelp = $true $Show = $openFileDialog.ShowDialog() If ($Show -eq "OK") { Return $openFileDialog.FileName } Else { Exit } } #============================================================================= # Generate welcome e-mail. #============================================================================= Function generateIntroLetter { param( [string]$GivenName, [string]$samAccountName, [string]$Password, [string]$DisplayName, [string]$DomainController ) $tmpServer = get-mailbox $DisplayName -DomainController $DomainController | select servername $tmpOWA = get-OutlookAnywhere -Server $tmpServer.ServerName -DomainController $DomainController -ADPropertiesOnly | select ExternalHostname $tmpOWA = "https://" + $tmpOWA.ExternalHostname + "/owa/" $rtfBuilder = new-object system.text.stringbuilder # Append RTF header $null = $rtfBuilder.Append("{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fswiss\fprq2\fcharset0 Calibri;}{\f1\fnil\fcharset0 Calibri;}}") $null = $rtfBuilder.Append("`r`n") # Append RTF color table which will contain all Powershell console colors. #$null = $rtfBuilder.Append('{\colortbl ;\red0\green0\blue255;}') #$null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("{\*\generator Msftedit 5.41.21.2509;}\viewkind4\uc1\pard\sa200\sl276\slmult1\f0\fs22 Dear $GivenName,\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("Please find the below access credentials for the NW Traders network. These are the only credentials you should need at NW Traders and will log you into your computer, e-mail account and other systems. As such, they should be kept confidential.\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("\tab Username\tab\tab $samAccountName\line\tab Password\tab\tab $PlainPassword\line\tab Domain\tab\tab\tab NWTRADERS\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("It is highly recommended that you change your password the first time you login. You should be able to use Outlook both in the office and at home, if for some reason that is not available you can access webmail using the following address:\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("\pard\tab{\field{\*\fldinst{HYPERLINK `$tmpOWA`}}{\fldrslt{\ul\cf1 h$tmpOWA}}}\f0\fs22\pard\par") $null = $rtfBuilder.Append("\pard\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("If you require support please contact the IT Support team via e-mail, {\field{\*\fldinst{HYPERLINK `mailto:it@nwtraders.msft` }}{\fldrslt{\cf1\ul it@nwtraders.msft}}}\cf0\ulnone\f0\fs22 . Alternatively an increasing number of self-service resources are available on our intranet:\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("\pard\fi720\par") $null = $rtfBuilder.Append("\pard\fi720{\field{\*\fldinst{HYPERLINK `http://intranet/`}}{\fldrslt{\ul\cf1 http://intranet/}}}\f0\fs22\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("\pard\sa200\sl276\slmult1\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("Kind Regards,\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("IT Support.\lang9\f1\par") $null = $rtfBuilder.Append("`r`n") $null = $rtfBuilder.Append("}") # Save as RTF File. echo $rtfBuilder.ToString() | out-file -Encoding Ascii "$samAccountName.rtf" } #============================================================================= # Displays a list of mailbox databases, which the user needs to choose from. #============================================================================= Function chooseMailboxDatabase() { $MbDbase = Get-MailboxDatabase $NumOfDB = $MbDbase.Count $Number = 0 $Choice = 0 If ($NumOfDB -eq $Null) { Write-Host $MbDbase.Identity return $MbDbase.Identity } else { foreach ($mbxDB in $MbDbase) { Write-Host "$Number . " $MbxDB.Identity $Number ++ } Write-Host "" $Choice = Read-Host "Mailbox Database" return $MbDbase[$Choice].Identity } } #============================================================================= # Opening user detail list" #============================================================================= $FileName = chooseCSVfile -Title "Import an CSV file" -Directory "c:\" $UserInformation = Import-Csv $FileName #============================================================================= # Do some logic about our environment. #============================================================================= Foreach ($User in $UserInformation) { $SurName = $User.Surname $GivenName = $User.givenName $samAccountName = $GivenName + " " + $SurName $DisplayName = $SurName + ", " + $GivenName $PlainPassword = $User.Password $userPrincipalName = $samAccountName + $cfgMailDomain #Exchange Specific $strMailAddress = $samAccountName -replace " ", "."; $strMailAddress += $cfgMailDomain; $strMailAlias = $samAccountName -replace " ", "."; # Attributes. $strOffice = $User.PhisicalDeliveryLocation; $strTitle = $user.JobTitle; $strOU = $cfgOffices.Get_Item( $strOffice ).Get_Item("OU") $strOAddress = $cfgOffices.Get_Item( $strOffice ).Get_Item("Address"); $strOTel = $cfgOffices.Get_Item( $strOffice ).Get_Item("Telephone"); Write-Host -Foreground Gray "---------------------------------------------------------------" Write-Host -Foreground Red " "$DisplayName Write-Host -Foreground Gray "---------------------------------------------------------------" Write-Host " Username:"$cfgTab$samAccountName; Write-Host " Password:"$cfgTab$PlainPassword; Write-Host " Job Title:"$cfgTab$strTitle; Write-Host " OU:"$cfgTab$cfgTab$strOU; Write-Host " E-Mail:"$cfgTab$strMailAddress Write-Host -Foreground Gray "---------------------------------------------------------------" Write-Host "" # Choose a mailbox database for this account. $mbDatabase = chooseMailboxDatabase Write-Host "" Write-Host -Foreground Gray "---------------------------------------------------------------" # Lets actually create the account now. $Password = ConvertTo-SecureString $PlainPassword -AsPlainText -Force # Create Exchange mailbox. New-Mailbox -Name $DisplayName -Alias $strMailAlias -OrganizationalUnit $strOU -UserPrincipalName $userPrincipalName -SamAccountName $samAccountName -FirstName $GivenName -Initials '' -LastName $SurName -Password $Password -ResetPasswordOnNextLogon $false -Database $mbDatabase -DomainController $cfgOffices.Get_Item( $strOffice ).Get_Item("DC") | out-null # Set Quest Active Directory stuff to use a DC in the local site (mostly). # Otherwise trying to make exchange changes in a remote site using a local # DC is going to fail, since the account doesn't exist yet. Connect-QADService -service $cfgOffices.Get_Item( $strOffice ).Get_Item("DC") | out-null # Set attributes on AD DS account. Get-QADUser $DisplayName | set-qaduser -oa @{'Office'=$strOffice; 'StreetAddress'=$strOAddress; 'OfficePhone'=$strOTel; 'Company'=$cfgCompany; 'Title'=$strTitle } | out-null # Set calendar permissions. Set-MailboxFolderPermission -Identity $strMailAddress`:\Calendar -User Default -AccessRights Reviewer -DomainController $cfgOffices.Get_Item( $strOffice ).Get_Item("DC") | out-null # Create the OCS Account. Get-QADUser $DisplayName | set-qaduser -oa @{'msRTCSIP-ArchivingEnabled'=0; 'msRTCSIP-FederationEnabled'=$true; 'msRTCSIP-InternetAccessEnabled'=$true; 'msRTCSIP-OptionFlags'=257; 'msRTCSIP-UserEnabled'=$true; 'msRTCSIP-PrimaryHomeServer'=$cfgOCSHomeServer; 'msRTCSIP-PrimaryUserAddress'=("sip:" + $strMailAddress ).ToString() } | out-null # Disconnect QADService. disconnect-qadservice # Generate Welcome e-mail. generateIntroLetter -GivenName $GivenName -samAccountName $samAccountName -Password $PlainPassword -DisplayName $DisplayName -DomainController $cfgOffices.Get_Item( $strOffice ).Get_Item("DC") }
You can expect outlook similar to the below:
---------------------------------------------------------------
Doe, John
---------------------------------------------------------------
Username: John Doe
Password: MyFirstPassword123!
Company: NW Traders
Job Title: Test Account
OU: OU=London,OU=Europe,OU=Users,DC=NWTRADERS,DC=MSFT
E-Mail: John.Doe@nwtraders.msft
---------------------------------------------------------------
0 . LONDON
1 . WASHINGTON
Mailbox Database: 0
---------------------------------------------------------------
You can then send the resulting RTF document to the persons line manager, or whoever should have it for when the employee starts on their first day.
I should note, Andy Grogan (Exchange MVP) has a very similar tool which you might like to take a look at. I gleaned the Open-CSV idea and plagiarised the choose mailbox database code from him.
Hi Dave – I read your post and wanted to know if you would be willing to beta test a new simplified provisioning product that we have developed using a web-based interface and a Powershell back-end. I hope you dont take this as a ‘sales’ inquiry as we are really wanting some real world feedback as to our design and implementation. No obligation and no sales calls, I can promise you that.
Let me know and I will have one of our engineers contact you.
Cheers!
Steve Denney
Dave,
Is it possible to prompt for input? I want to use a similar script for our Service Desk team to create AD, OCS and Echange accounts.
Thanks.
Jose,
Yep. Get rid of the Import-Csv bit and the for loop. Then for the $GivenName etc change then to be read-host “Given Name: ”
And powerhsell will prompt for input.
Hi Guys
I am really new to powershell and am having a tough time understand or locating any scripots that will simply add users from a excel or csv file. can anyone place a asimply script or how to alter the script already listed just to create ad users.
Thanks in advance for your help
Confused
Muito bem explicado, estarei seguindo for the reason that aulas! Muito obrigado pela ajuda! ^^
[…] Automating Active Directory account creation with Powershell – Hier wird die Nutzung von PowerShell zur Automatisierung von AD-Accounts und Exchange-Email-Postfächern demonstriert. […]
Dave,
I have been workinmg in IT for a while but mostly tier2 and some tier 3- I have basic working knowledge of ADUC and EMT. I will be tasked with creating user accounts as well as some PCI stuff. I dig your post man and am keeping an eye out for other posts that you may have.
Thomas
Yep. Get rid of the Import-Csv bit and the for loop. Then for the $GivenName etc change then to be read-host “Given Name: ”
And powerhsell will prompt for input.
Can u please let me know how to edit the script to prompt for input.