Doorgaan naar hoofdcontent

AD Provisioning: Aanmaken user accounts en managed service accounts

De vorige keer heb ik aan de hand van een provisioning PowerShell script organizational units en groups aangemaakt. Deze keer is het de beurt aan de user accounts en managed service accounts die ik nodig heb in mijn proeftuin. Aan de basis van mijn PowerShell script heeft het Microsoft Technet artikel 'Automating User Provisioning, Part 2' gelegen. Dit script ging uit van Exchange Server 2007 cmdlets en de Quest AD extensies.

Het PowerShell script begint met het goed zetten van de executie rechten voor PowerShell.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

De volgende stap is het registreren van de PowerShell module voor AD.

# Inlezen Windows PowerShell Module voor Active Directory. Deze module is 
# beschikbaar op Windows 2008 R2 (alleen op de Standard, Enterprise en
# DataCenter versies) en, middels 'Windows Server 2008 R2 Remote Server
# Administration Tools (RSAT)', op Windows 7.
Import-Module ActiveDirectory

Het provisioning proces bestaat uit verschillende stappen.

#
# .SYNOPSIS
# Provisioning acties voor (nieuwe) accounts.
#
# .DESCRIPTION
# Centrale provision functie die op basis van een hashtabel waarin de
# (nieuwe) gebruikersgegevens staan allerlei subfuncties aanroept waarmee
# alle feitelijke provisioning taken worden uitgevoerd.
#
function Provision
{
PROCESS {
Create-UserAccountInAD $_ # Aanmaken van nieuw account
Modify-ManagerInAD $_ # Bijwerken manager van het account
Modify-UserAccountInAD $_ # Bijwerken overige gegevens van het account
}
}

De input voor het proces wordt ingelezen middels een CSV bestand waarvan de gegevens in een hashtable worden opgeslagen.

#
# .SYNOPSIS
# Ophalen van gebruikergegevens uit een CSV-bestand.
#
# .DESCRIPTION
# Ophalen van gebruikergegevens uit een CSV-bestand. De eerste regel van
# dit CSV-bestand dient de volgende kolomnamen te bevatten:
#
# Kolom Toelichting
# ------------- --------------------------------------------------
# Gebruikersnaam Mag niet langer zijn dan 20 tekens
# Wachtwoord Dient te voldoen aan de wachtwoord policy
# Omschrijving Doel van het account
# Voornaam Roepnaam
# Middelste_Naam Overige namen
# Achternaam
# Adres Straat + Huisnummer + Toevoeging
# Postcode 9999 ZZ
# Plaats
# Provincie
# Landcode 2 lettercode voor het land (NL = Nederland)
# Postbus "Postbus " + nummer
# Postcode_Postbus 9999 ZZ
# Plaats_Postbus
# Telefoon_Zakelijk (999 | 9999) (9)99 99 99
# Mobiel (06) 99 99 99 99
# Fax (999 | 9999) (9)99 99 99
# Telefoon_Prive (999 | 9999) (9)99 99 99
# Email POP3 / Exchange e-mail adres
# Homepage URL van SharePoint My Site van betreffende account
# Functie
# Kantoor
# Afdeling
# Divisie
# Organisatie
# Bedrijf
# Manager Gebruikersnaam van de manager
# PersoneelsID
# Personeelnummer
# Managed_Account TRUE | FALSE
# OU Het pad in AD waaronder de gebruiker aangemaakt
# dient te worden. Voorbeeld: OU=Users,DC=Contoso,DC=Com
#
# .PARAMETER BestandsNaam
# De naam van het CSV-bestand dat ingelezen dient te worden.
#
# .EXAMPLE
# PS C:\> ProvisionInputCSV -BestandsNaam 'c:\provision\gebruikers.csv'
# Dit voorbeeld toont hoe de ProvisionInputCSV functie aangeroepen dient
# te worden met named parameters.
#
# .EXAMPLE
# PS C:\> ProvisionInputCSV 'c:\provision\gebruikers.csv'
# Dit voorbeeld toont hoe de ProvisionInputCSV functie aangeroepen dient
# te worden met gepositioneerde parameters.
#
# .INPUTS
# System.String
#
# .OUTPUTS
# System.Collections.Hashtable
#
function ProvisionInputCSV
{
Param
(
[System.String] $BestandsNaam
)

# Importeren CSV-bestand
$Gebruikers = Import-Csv -Path $BestandsNaam -Delimiter ";";

# Transformeren van gegevens naar de benodigde AD naamgeving in de hash
# tabel
foreach ($Gebruiker in $Gebruikers)
{
$GebruikerHashTabel =
@{
# --- General ---
'Name' = Replace-EmptyString(($Gebruiker.Voornaam +
" " + $Gebruiker.Achternaam).Trim()); # SarahDavis
'GivenName' = Replace-EmptyString($Gebruiker.Voornaam); # Sanjay
'Initials' = Replace-EmptyString($Gebruiker.Initialen); # L
'OtherName' = Replace-EmptyString($Gebruiker.MiddelsteNaam); # Peter
'Surname' = Replace-EmptyString($Gebruiker.Achternaam); # Patel
'DisplayName' = Replace-EmptyString(($Gebruiker.Voornaam +
" " + $Gebruiker.Achternaam).Trim()); # Sarah Davis Laptop
'Description' = Replace-EmptyString($Gebruiker.Omschrijving); # Description of the object
'Office' = Replace-EmptyString($Gebruiker.Kantoor); # D1042
'OfficePhone' = Replace-EmptyString($Gebruiker.Telefoon_Zakelijk); # +1 (999) 555 1212
'EmailAddress' = Replace-EmptyString($Gebruiker.Email); # sarahdavis@contoso.com
'HomePage' = Replace-EmptyString($Gebruiker.Homepage); # http://employees.contoso.com/sdavis

# --- Address ---
'StreetAddress' = Replace-EmptyString($Gebruiker.Adres); # 1200 Main Street
'POBox' = Replace-EmptyString($Gebruiker.Postbus); # 25662
'City' = Replace-EmptyString($Gebruiker.Plaats); # Las Vegas
'State' = Replace-EmptyString($Gebruiker.Provincie); # Nevada
'PostalCode' = Replace-EmptyString($Gebruiker.Postcode); # 28712
'Country' = Replace-EmptyString($Gebruiker.Landcode); # IN

# --- Account ----
'SamAccountName' = Replace-EmptyString($Gebruiker.Gebruikersnaam); # saradavis
'AccountPassword' = Replace-EmptyString($Gebruiker.Wachtwoord); # <W8woord>

# --- Telephones ---
'HomePhone' = Replace-EmptyString($Gebruiker.Telefoon_Prive); # +1 (999) 555 1212
'MobilePhone' = Replace-EmptyString($Gebruiker.Mobiel); # +1 (999) 555 1212
'Fax' = Replace-EmptyString($Gebruiker.Fax); # +1 (999) 555 1212

# --- Organization ---
'Title' = Replace-EmptyString($Gebruiker.Functie); # Manager
'Department' = Replace-EmptyString($Gebruiker.Afdeling); # Development
'Division' = Replace-EmptyString($Gebruiker.Divisie); # Software
'Organization' = Replace-EmptyString($Gebruiker.Organisatie); # Accounting
'Company' = Replace-EmptyString($Gebruiker.Bedrijf); # Contoso
'Manager' = Replace-EmptyString($Gebruiker.Manager); # saradavis
'EmployeeID' = Replace-EmptyString($Gebruiker.PersoneelsID); # A123456
'EmployeeNumber' = Replace-EmptyString($Gebruiker.Personeelnummer); # 12345678

# --- Additional information ---
'Managed_Account' = [System.Convert]::ToBoolean($Gebruiker.Managed_Account); # true
'OU' = Replace-EmptyString($Gebruiker.OU); # OU=Users,DC=contoso,DC=com
}

# Verzend hash tabel naar het volgende commando in de pipeline
Write-Output $GebruikerHashTabel;
}
}

Het aanmaken van user accounts en managed service accounts is in een function ondergebracht. Er is voor gekozen deze functie alleen het account te laten aanmaken. Het zetten van managers en het vullen van de overige gegevens is belegt in aparte functies. Hiermee is het provisioning script ook in te zetten voor onderhoud op de accounts.

#
# .SYNOPSIS
# Aanmaken van een gebruikersaccount in AD.
#
# .DESCRIPTION
# Aanmaken van een gebruikersaccount in AD op basis van de gegevens uit de
# doorgegeven hash tabel. Het account dat aangemaakt wordt bestaat alleen
# uit een gebruikersnaam en een wachtwoord. Het account is reeds actief
# en bij de eerste keer inloggen hoeft het wachtwoord niet gewijzigd te
# worden.
#
# .PARAMETER Gebruiker
# De hash tabel met gebruikergegevens.
#
# .EXAMPLE
# PS C:\> Create-UserAccountInAD $Gebruiker
# Dit voorbeeld toont hoe de Create-UserAccountInAD functie aangeroepen
# dient te worden met een hash tabel vol gebruikergegevens.
#
# .INPUTS
# System.Collections.Hashtable
#
# .OUTPUTS
# Null
#
function Create-UserAccountInAD
{
param
(
[System.Collections.Hashtable] $Gebruiker
)

# Lokale variabelen
[Microsoft.ActiveDirectory.Management.ADUser] $adUser;

# Controle of het account reeds bestaat in het AD
if ($Gebruiker.Managed_Account -eq $false)
{
$adUser = Get-ADUser -Filter ("SamAccountName -eq '" +
$Gebruiker.SamAccountName + "'");
}
else
{
$adUser = Get-ADServiceAccount -Filter ("SamAccountName -eq '" +
$Gebruiker.SamAccountName + "$'");
}

# Indien het account niet is gevonden dan maken we het aan
if ($adUser -eq $null)
{
Write-Verbose ("Aanmaken AD account voor '" + $Gebruiker.Name + " (" +
$Gebruiker.SamAccountName + ")'.");

# Managed Service account aanmaken?
if ($Gebruiker.Managed_Account -eq $false)
{
# Samenstellen van UserPrincipal object
[System.String] $adUserPrincipal = $Gebruiker.SamAccountName + "@" +
(Get-ADForest -Current LocalComputer).RootDomain;

# Actief gebruikers account met geen verplichte wachtwoord wijziging
if ($Gebruiker.SamAccountName.Length -cle 20)
{
if ($Gebruiker.Name -ne $null)
{
# Gewone accounts zijn niet trusted for delegation
New-ADUser -Name $Gebruiker.Name -Path $Gebruiker.OU -UserPrincipalName $adUserPrincipal -SamAccountName $Gebruiker.SamAccountName -AccountPassword (ConvertTo-SecureString $Gebruiker.AccountPassword -AsPlainText -Force) –ChangePasswordAtLogon $false -Enabled $true -TrustedForDelegation $false;

Write-Debug ("Aangemaakt als: Standaard user account");

trap [Microsoft.ActiveDirectory.Management.ADException]
{
# Fout is niet blokkerend
Write-Warning ("Bij het aanmaken van AD user '" +
$Gebruiker.Name + " (" + $Gebruiker.OU + ")" +
"' is er een fout opgetreden. De opgetreden fout is: '" +
$_.Exception.Message + " (" +
$_.Exception.GetType() + ")'. ");
Continue;
}
}
else
{
# Service accounts zijn trusted for delegation
New-ADUser -Name $Gebruiker.SamAccountName -Path $Gebruiker.OU -UserPrincipalName $adUserPrincipal -SamAccountName $Gebruiker.SamAccountName -AccountPassword (ConvertTo-SecureString $Gebruiker.AccountPassword -AsPlainText -Force) –ChangePasswordAtLogon $false -Enabled $true -TrustedForDelegation $true;

Write-Debug ("Aangemaakt als: Standaard user account");

trap [Microsoft.ActiveDirectory.Management.ADException]
{
# Fout is niet blokkerend
Write-Warning ("Bij het aanmaken van AD user '" +
$Gebruiker.SamAccountName + " (" + $Gebruiker.OU + ")" +
"' is er een fout opgetreden. De opgetreden fout is: '" +
$_.Exception.Message + " (" +
$_.Exception.GetType() + ")'. ");
Continue;
}
}
}
else
{
Write-Warning ("AD user account voor '" + $Gebruiker.Name + " (" +
$Gebruiker.SamAccountName + ")' is niet aangemaakt omdat " +
"opgegeven SamAccountName langer is dan 20 tekens.");
}
}
else
{
# Actief managed service account en trusted for delegation
if ($Gebruiker.SamAccountName.Length -cle 20)
{
New-ADServiceAccount -Name $Gebruiker.SamAccountName -Path $Gebruiker.OU -SamAccountName $Gebruiker.SamAccountName -TrustedForDelegation $true -Enabled $true;

Write-Debug ("Aangemaakt als: Managed Service account");

trap [Microsoft.ActiveDirectory.Management.ADException]
{
# Fout is niet blokkerend
Write-Warning ("Bij het aanmaken van AD Service account '" +
$Gebruiker.SamAccountName + " (" + $Gebruiker.OU + ")" +
"' is er een fout opgetreden. De opgetreden fout is: '" +
$_.Exception.Message + " (" +
$_.Exception.GetType() + ")'. ");
Continue;
}
}
else
{
Write-Warning ("AD Managed Service account voor '" +
$Gebruiker.Name + " (" + $Gebruiker.SamAccountName +
")' is niet aangemaakt omdat opgegeven SamAccountName " +
"langer is dan 20 tekens.");
}
}
}
else
{
Write-Warning ("Aanmaken AD account voor '" + $Gebruiker.Name +
" (" + $Gebruiker.SamAccountName +
")' overgeslagen. Het opgegeven account bestaat reeds.");
}
}

Het bijwerken van niet sleutel gegevens is belegt in een modificatie functie. Het zetten van de manager is apart gehouden. Dit is onder andere gedaan omdat de managed service acounts geen manager veld kennen.

#
# .SYNOPSIS
# Wijzigingen gegevens van een bestaand gebruikersaccount in AD.
#
# .DESCRIPTION
# Wijzigingen van gegevens van een bestaand gebruikersaccount in AD op
# basis van de gegevens uit de doorgegeven hash tabel.
#
# .PARAMETER Gebruiker
# De hash tabel met gebruikergegevens.
#
# .EXAMPLE
# PS C:\> Modify-UserAccountInAD $Gebruiker
# Dit voorbeeld toont hoe de Modify-UserAccountInAD functie aangeroepen
# dient te worden met een hash tabel vol gebruikergegevens.
#
# .INPUTS
# System.Collections.Hashtable
#
# .OUTPUTS
# Null
#
function Modify-UserAccountInAD
{
param
(
[System.Collections.Hashtable] $Gebruiker
)

# Lokale variabelen
[Microsoft.ActiveDirectory.Management.ADUser] $adUser;

# Gegevens account ophalen uit het AD
if ($Gebruiker.Managed_Account -eq $false)
{
$adUser = Get-ADUser -Filter ("SamAccountName -eq '" +
$Gebruiker.SamAccountName + "'");
}
else
{
$adUser = Get-ADServiceAccount -Filter ("SamAccountName -eq '" +
$Gebruiker.SamAccountName + "$'");
}

# We kunnen het account alleen wijzigen als het bestaat
if ($adUser -eq $null)
{
Write-Warning ("Wijzigen gegevens van AD account voor '" +
$Gebruiker.Name + " (" + $Gebruiker.SamAccountName +
")' is mislukt. Het opgegeven account bestaat niet.");
}
else
{
Write-Verbose ("Bijwerken gegevens van AD account van '" +
$Gebruiker.Name + " (" + $Gebruiker.SamAccountName + ")'.");

# Betreft het een Managed Service account?
if ($Gebruiker.Managed_Account -eq $false)
{
# --- General ---
Set-ADUser $adUser -GivenName $Gebruiker.GivenName;
Set-ADUser $adUser -Initials $Gebruiker.Initials;
Set-ADUser $adUser -OtherName $Gebruiker.OtherName;
Set-ADUser $adUser -Surname $Gebruiker.Surname;
Set-ADUser $adUser -DisplayName $Gebruiker.DisplayName;
Set-ADUser $adUser -Description $Gebruiker.Description;
Set-ADUser $adUser -Office $Gebruiker.Office;
Set-ADUser $adUser -OfficePhone $Gebruiker.OfficePhone;
Set-ADUser $adUser -EmailAddress $Gebruiker.EmailAddress;
Set-ADUser $adUser -HomePage $Gebruiker.HomePage;

# --- Address ---
Set-ADUser $adUser -StreetAddress $Gebruiker.StreetAddress;
Set-ADUser $adUser -POBox $Gebruiker.POBox;
Set-ADUser $adUser -City $Gebruiker.City;
Set-ADUser $adUser -State $Gebruiker.State;
Set-ADUser $adUser -PostalCode $Gebruiker.PostalCode;
Set-ADUser $adUser -Country $Gebruiker.Country;

# --- Telephones ---
Set-ADUser $adUser -HomePhone $Gebruiker.HomePhone;
Set-ADUser $adUser -MobilePhone $Gebruiker.MobilePhone;
Set-ADUser $adUser -Fax $Gebruiker.Fax;

# --- Organization ---
Set-ADUser $adUser -Title $Gebruiker.Title;
Set-ADUser $adUser -Department $Gebruiker.Department;
Set-ADUser $adUser -Division $Gebruiker.Division;
Set-ADUser $adUser -Organization $Gebruiker.Organization;
Set-ADUser $adUser -Company $Gebruiker.Company;
Set-ADUser $adUser -EmployeeID $Gebruiker.EmployeeID;
Set-ADUser $adUser -EmployeeNumber $Gebruiker.EmployeeNumber;
}
else
{
# --- General ---
Set-ADServiceAccount $adUser -Description $Gebruiker.Description;
Set-ADServiceAccount $adUser -DisplayName $Gebruiker.DisplayName;
Set-ADServiceAccount $adUser -HomePage $Gebruiker.HomePage;
}
}
}

De functie voor het bijwerken van manager gegevens.

#
# .SYNOPSIS
# Wijzigingen manager gegevens van een bestaand gebruikersaccount in AD.
#
# .DESCRIPTION
# Wijzigingen van manager gegevens van een bestaand gebruikersaccount in
# AD op basis van de gegevens uit de doorgegeven hash tabel.
#
# .PARAMETER Gebruiker
# De hash tabel met gebruikergegevens.
#
# .EXAMPLE
# PS C:\> Modify-ManagerInAD $Gebruiker
# Dit voorbeeld toont hoe de Modify-ManagerInAD functie aangeroepen
# dient te worden met een hash tabel vol gebruikergegevens.
#
# .INPUTS
# System.Collections.Hashtable
#
# .OUTPUTS
# Null
#
function Modify-ManagerInAD
{
param
(
[System.Collections.Hashtable] $Gebruiker
)

# Bijwerken van de manager kan niet op Managed Service accounts.
if ($Gebruiker.Managed_Account -eq $true)
{
return;
}

# Controleer of het AD account bestaat
$adUser = Get-ADUser -Filter ("SamAccountName -eq '" +
$Gebruiker.SamAccountName + "'");

if ($adUser -eq $null)
{
Write-Warning ("Wijzigen manager gegevens van AD account voor '" +
$Gebruiker.Name + " (" + $Gebruiker.SamAccountName +
")' is mislukt. Het opgegeven account bestaat niet.");
}
else
{
Write-Verbose ("Bijwerken manager gegevens van AD account van '" +
$Gebruiker.Name + " (" + $Gebruiker.SamAccountName + ")'.");

# Controleer of het AD account van de manager bestaat
if ($Gebruiker.Manager -ne $null)
{
$adManager = Get-ADUser -Filter ("SamAccountName -eq '" +
$Gebruiker.Manager + "'");

if ($adManager -eq $null)
{
# Overschrijf de bestaande manager
Set-ADUser $adUser -Manager $null;
}
else
{
# Voeg de actuele manager toe
Set-ADUser $adUser -Manager $adManager;
}
}
else
{
Set-ADUser $adUser -Manager $null;
}
}
}

Onderstaande functie zorgt ervoor dat null values uit de CSV goed worden gezet. Doen we dit niet dan treden er fouten op bij het zetten van bepaalde AD velden.

#
# .SYNOPSIS
# Vervang een lege System.String door een Null.
#
# .DESCRIPTION
# Vervang een lege System.String door een Null.
#
# .PARAMETER Str
# De te controleren System.String.
#
# .EXAMPLE
# PS C:\> Replace-EmptyString ''
#
# .INPUTS
# System.String
#
# .OUTPUTS
# Null of System.String
#
function Replace-EmptyString
{
param
(
[System.String] $str
)

# Vervang een empty string door een NULL waarde
if ($str -eq '')
{
Write-Output $null;
}
else
{
Write-Output $str.Trim();
}
}

Het uitvoeren van de provisioning taken dient initieel twee keer te gebeuren. De reden is dat anders de manager velden van de accounts niet overal goed worden gezet.

# Provisioning 2x uitvoeren omdat de eerste ronde de managers niet altijd goed gezet worden
ProvisionInputCSV -BestandsNaam "D:\Projects\PowerShell\Gebruikers\accounts.csv" | Provision
ProvisionInputCSV -BestandsNaam "D:\Projects\PowerShell\Gebruikers\accounts.csv" | Provision

Reacties

Populaire posts van deze blog

Active Directory limieten

Zoals ieder systeem heeft Active Directory ook zijn limieten. Tijdens wat Active Directory research kwam ik het volgende Technet artikel tegen waarin deze worden benoemd: Active Directory Maximum Limits . Kort samengevat zijn de limieten: Maximum aantal objecten per domain controller in een forest : ongeveer 2,5 biljoen (gedurende de volledige levensduur). Maximum aantal security identifiers (SID's) per domein : ongeveer 1 biljoen (gedurende de volledige levensduur). Aantal groepen waarvan een security indentifier (persoon, groep, computer account) lid kan zijn : ongeveer 1.015 groepen. FQDN lengte limiet : maximum lengte is 64 tekens (dit is inclusief punten en mintekens) voor de fully qualified domain name (FQDN). Bestandsnaam limiet : Windows kent een pad lengte limiet van 260 tekens. Deze is ook van toepassing op de fysieke bestanden van AD zoals SYSVOL. Organisational unit limiet : maximum lengte is 64 tekens. Heeft te maken met de Windows limiet van 260 tekens die in de gaten

Winsxs folder neemt veel ruimte in

In Windows Millenium is de Winsxs folder geintroduceerd. Deze folder bevat meerdere versies van in gebruik zijnde DLL bestanden. Het doel hiervan is dat iedere programma de juiste versie van de benodigde DLL kan gebruiken. Dit principe staat ook wel bekend als "Windows Side by Side". De folder die hiervoor gebruikt wordt is dus "C:\Windows\winsxs" en deze folder vormt dus de native assembly cache. In een tijd dat het vrij normaal is dat een computer is voorzien van een 500 GB harde schijf is de overhead van meerdere versies van een bestand opslaan niet echt een probleem. Echter in mijn geval wel. Op een van mijn multi boot computers heb ik een Vista Ultimate (met daarop Vista, MS Office en enkele andere programa's) van 32 GB. Mijn (persoonlijke) data staat op een aparte partitie. Door de installatie van de vele Windows updates is de vrije ruimte op deze partitie gezakt tot 2,85 GB (en dus in de rode waarschuwingszone terecht gekomen). Van de 32 GB is meer dan

Bevindingen over de E-tech ADWG02 tot nu toe

Ik heb de E-tech ADWG02 nu bijna een week in gebruik. Dit is de vervangende modem voor de buggy Linksys WAG54G die ik eerder gekocht had. Mijn bevindingen over de E-tech tot nu toe: Geen crashes tot nu toe. De firmware lijkt op dat punt stabiel. Het apparaat is niet door middel van een knop aan of uit te zetten. Erg vervelend omdat ik het apparaat alleen uit kan zetten door de stekker uit het stopcontact te halen. De reden dat ik hem graag uit wil kunnen zetten is dat het apparaat in de woonkamer staat (in het zicht) en de lampjes nogal fel schijnen. Dat vind ik niet erg prettig. Daarnaast wil ik niet dat de verbinding de gehele dag open staat uit beveiligingsoverwegingen en vanwege het stroomverbruik. WIFI is middels een setting uit te zetten. Als je de setting uitvinkt en bevestigd door middel van een 'apply' zie je het lampje uitgaan op de ADSL modem. Er is op dat moment ook geen WIFI verbinding actief. Sla je de setting definitief op dan reboot de modem automat