New-BulkUsers.ps1
Niveau : Avancรฉ
Crรฉation et gestion en masse des utilisateurs depuis un fichier CSV.
Description
Ce script automatise la gestion des utilisateurs en masse : - Crรฉation d'utilisateurs AD depuis CSV - Crรฉation d'utilisateurs locaux Windows - Gรฉnรฉration de mots de passe sรฉcurisรฉs - Attribution aux groupes - Mode simulation (WhatIf) - Export des credentials crรฉรฉs - Validation des donnรฉes avant import
Prรฉrequis
- Systรจme : Windows Server 2016+ ou Windows 10/11
- PowerShell : Version 5.1 minimum
- Permissions : Droits administrateur (Domain Admins pour AD, Administrateur local pour utilisateurs locaux)
- Modules :
ActiveDirectory(pour mode AD uniquement, installรฉ par dรฉfaut sur DC)
Cas d'Usage
- Onboarding massif : Crรฉer des dizaines d'utilisateurs lors de l'arrivรฉe d'une nouvelle รฉquipe
- Migration Active Directory : Recrรฉer des comptes depuis un export CSV
- Environnement de test : Gรฉnรฉrer rapidement des utilisateurs pour tests et formation
- Automatisation RH : Intรฉgrer avec un systรจme RH pour provisioning automatique
Script
<#
.SYNOPSIS
Bulk user creation and management from CSV file.
.DESCRIPTION
Creates users in Active Directory or locally from a CSV file.
Supports password generation, group membership, and credential export.
.PARAMETER CsvPath
Path to the CSV file containing user data.
.PARAMETER Mode
Target: AD (Active Directory) or Local (local Windows users).
.PARAMETER DefaultPassword
Default password for all users (if not specified in CSV).
.PARAMETER GeneratePasswords
Generate unique random passwords for each user.
.PARAMETER PasswordLength
Length of generated passwords (default: 16).
.PARAMETER ExportCredentials
Export created credentials to a secure file.
.PARAMETER WhatIf
Simulation mode - show what would be created without making changes.
.EXAMPLE
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode AD -GeneratePasswords
.EXAMPLE
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode Local -DefaultPassword "TempPass123!"
.NOTES
Author: ShellBook
Version: 1.0
Requires: ActiveDirectory module (for AD mode)
#>
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory = $true)]
[ValidateScript({ Test-Path $_ -PathType Leaf })]
[string]$CsvPath,
[Parameter(Mandatory = $true)]
[ValidateSet("AD", "Local")]
[string]$Mode,
[Parameter()]
[string]$DefaultPassword,
[Parameter()]
[switch]$GeneratePasswords,
[Parameter()]
[int]$PasswordLength = 16,
[Parameter()]
[string]$ExportCredentials,
[Parameter()]
[string]$DefaultOU,
[Parameter()]
[string[]]$DefaultGroups,
[Parameter()]
[switch]$Force
)
#region Functions
function Write-Log {
param(
[string]$Message,
[ValidateSet("INFO", "WARN", "ERROR", "SUCCESS")]
[string]$Level = "INFO"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$color = switch ($Level) {
"INFO" { "Cyan" }
"WARN" { "Yellow" }
"ERROR" { "Red" }
"SUCCESS" { "Green" }
}
Write-Host "[$timestamp] [$Level] $Message" -ForegroundColor $color
}
function New-SecurePassword {
param([int]$Length = 16)
$chars = @()
$chars += [char[]](65..90) # A-Z
$chars += [char[]](97..122) # a-z
$chars += [char[]](48..57) # 0-9
$chars += [char[]]"!@#$%^&*()_+-=[]{}|;:,.<>?"
# Ensure at least one of each type
$password = @()
$password += [char](Get-Random -InputObject ([char[]](65..90))) # Uppercase
$password += [char](Get-Random -InputObject ([char[]](97..122))) # Lowercase
$password += [char](Get-Random -InputObject ([char[]](48..57))) # Number
$password += [char](Get-Random -InputObject ([char[]]"!@#$%^&*")) # Special
# Fill remaining length
for ($i = $password.Count; $i -lt $Length; $i++) {
$password += [char](Get-Random -InputObject $chars)
}
# Shuffle
$password = $password | Sort-Object { Get-Random }
return -join $password
}
function Test-ADModule {
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
Write-Log "ActiveDirectory module not found. Install RSAT or run on a DC." -Level ERROR
return $false
}
Import-Module ActiveDirectory -ErrorAction SilentlyContinue
return $true
}
function Test-UserExists {
param(
[string]$Username,
[string]$Mode
)
if ($Mode -eq "AD") {
try {
$null = Get-ADUser -Identity $Username -ErrorAction Stop
return $true
}
catch {
return $false
}
}
else {
try {
$null = Get-LocalUser -Name $Username -ErrorAction Stop
return $true
}
catch {
return $false
}
}
}
function New-ADUserFromCsv {
param(
[PSCustomObject]$UserData,
[string]$Password,
[string]$OU,
[string[]]$Groups
)
$samAccountName = $UserData.Username
$displayName = "$($UserData.FirstName) $($UserData.LastName)"
$userPrincipalName = "$samAccountName@$((Get-ADDomain).DNSRoot)"
# Build parameters
$adParams = @{
SamAccountName = $samAccountName
UserPrincipalName = $userPrincipalName
Name = $displayName
DisplayName = $displayName
GivenName = $UserData.FirstName
Surname = $UserData.LastName
AccountPassword = (ConvertTo-SecureString $Password -AsPlainText -Force)
Enabled = $true
ChangePasswordAtLogon = $true
}
# Optional fields
if ($UserData.Email) { $adParams.EmailAddress = $UserData.Email }
if ($UserData.Department) { $adParams.Department = $UserData.Department }
if ($UserData.Title) { $adParams.Title = $UserData.Title }
if ($UserData.Office) { $adParams.Office = $UserData.Office }
if ($UserData.Phone) { $adParams.OfficePhone = $UserData.Phone }
if ($UserData.Description) { $adParams.Description = $UserData.Description }
# OU
$targetOU = if ($UserData.OU) { $UserData.OU } else { $OU }
if ($targetOU) { $adParams.Path = $targetOU }
# Create user
New-ADUser @adParams
# Add to groups
$userGroups = @()
if ($UserData.Groups) { $userGroups += $UserData.Groups -split ";" }
if ($Groups) { $userGroups += $Groups }
foreach ($group in ($userGroups | Where-Object { $_ })) {
try {
Add-ADGroupMember -Identity $group.Trim() -Members $samAccountName
Write-Log " Added to group: $group" -Level INFO
}
catch {
Write-Log " Failed to add to group '$group': $_" -Level WARN
}
}
return $true
}
function New-LocalUserFromCsv {
param(
[PSCustomObject]$UserData,
[string]$Password,
[string[]]$Groups
)
$username = $UserData.Username
$fullName = "$($UserData.FirstName) $($UserData.LastName)"
# Build parameters
$localParams = @{
Name = $username
FullName = $fullName
Password = (ConvertTo-SecureString $Password -AsPlainText -Force)
PasswordNeverExpires = $false
AccountNeverExpires = $true
}
if ($UserData.Description) { $localParams.Description = $UserData.Description }
# Create user
New-LocalUser @localParams
# Add to groups
$userGroups = @()
if ($UserData.Groups) { $userGroups += $UserData.Groups -split ";" }
if ($Groups) { $userGroups += $Groups }
foreach ($group in ($userGroups | Where-Object { $_ })) {
try {
Add-LocalGroupMember -Group $group.Trim() -Member $username
Write-Log " Added to local group: $group" -Level INFO
}
catch {
Write-Log " Failed to add to local group '$group': $_" -Level WARN
}
}
return $true
}
function Export-Credentials {
param(
[array]$Credentials,
[string]$OutputPath
)
$exportData = $Credentials | Select-Object Username, Password, Email, CreatedAt
# Export to CSV (encrypted password column)
$exportData | Export-Csv -Path $OutputPath -NoTypeInformation
# Also create a secure version
$securePath = $OutputPath -replace '\.csv$', '_secure.xml'
$Credentials | Export-Clixml -Path $securePath
Write-Log "Credentials exported to: $OutputPath" -Level SUCCESS
Write-Log "Secure export: $securePath" -Level INFO
}
#endregion
#region Main
# Banner
Write-Host ""
Write-Host "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ" -ForegroundColor Cyan
Write-Host " BULK USER MANAGER" -ForegroundColor Green
Write-Host " Mode: $Mode" -ForegroundColor Yellow
if ($WhatIfPreference) {
Write-Host " [SIMULATION MODE]" -ForegroundColor Magenta
}
Write-Host "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ" -ForegroundColor Cyan
Write-Host ""
# Check requirements
if ($Mode -eq "AD") {
if (-not (Test-ADModule)) {
exit 1
}
Write-Log "ActiveDirectory module loaded" -Level SUCCESS
}
# Validate password options
if (-not $GeneratePasswords -and -not $DefaultPassword) {
Write-Log "Specify -GeneratePasswords or -DefaultPassword" -Level ERROR
exit 1
}
# Import CSV
Write-Log "Loading CSV: $CsvPath" -Level INFO
try {
$users = Import-Csv -Path $CsvPath
}
catch {
Write-Log "Failed to import CSV: $_" -Level ERROR
exit 1
}
Write-Log "Found $($users.Count) users to process" -Level INFO
# Validate required columns
$requiredColumns = @("Username", "FirstName", "LastName")
$csvColumns = $users[0].PSObject.Properties.Name
foreach ($col in $requiredColumns) {
if ($col -notin $csvColumns) {
Write-Log "Missing required column: $col" -Level ERROR
Write-Log "Required columns: $($requiredColumns -join ', ')" -Level INFO
exit 1
}
}
# Process users
$results = @{
Created = 0
Skipped = 0
Failed = 0
}
$createdCredentials = @()
foreach ($user in $users) {
$username = $user.Username
Write-Host ""
Write-Log "Processing: $username ($($user.FirstName) $($user.LastName))" -Level INFO
# Check if exists
if (Test-UserExists -Username $username -Mode $Mode) {
if (-not $Force) {
Write-Log " User already exists, skipping" -Level WARN
$results.Skipped++
continue
}
Write-Log " User exists but -Force specified, will update" -Level WARN
}
# Generate or use password
$password = if ($GeneratePasswords) {
New-SecurePassword -Length $PasswordLength
}
elseif ($user.Password) {
$user.Password
}
else {
$DefaultPassword
}
# WhatIf check
if ($PSCmdlet.ShouldProcess($username, "Create user")) {
try {
if ($Mode -eq "AD") {
$created = New-ADUserFromCsv -UserData $user -Password $password `
-OU $DefaultOU -Groups $DefaultGroups
}
else {
$created = New-LocalUserFromCsv -UserData $user -Password $password `
-Groups $DefaultGroups
}
if ($created) {
Write-Log " User created successfully" -Level SUCCESS
$results.Created++
# Store credentials for export
$createdCredentials += [PSCustomObject]@{
Username = $username
Password = $password
Email = $user.Email
FullName = "$($user.FirstName) $($user.LastName)"
CreatedAt = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
}
}
}
catch {
Write-Log " Failed to create user: $_" -Level ERROR
$results.Failed++
}
}
else {
Write-Log " [WhatIf] Would create user with password: $($password.Substring(0,4))****" -Level INFO
$results.Created++
}
}
# Export credentials if requested
if ($ExportCredentials -and $createdCredentials.Count -gt 0) {
Export-Credentials -Credentials $createdCredentials -OutputPath $ExportCredentials
}
# Summary
Write-Host ""
Write-Host "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ" -ForegroundColor Cyan
Write-Host " SUMMARY" -ForegroundColor Green
Write-Host "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ" -ForegroundColor Cyan
Write-Host ""
Write-Host " Total Processed: $($users.Count)" -ForegroundColor White
Write-Host " Created: $($results.Created)" -ForegroundColor Green
Write-Host " Skipped: $($results.Skipped)" -ForegroundColor Yellow
Write-Host " Failed: $($results.Failed)" -ForegroundColor Red
Write-Host ""
if ($results.Failed -gt 0) {
exit 1
}
#endregion
Format CSV
Colonnes Requises
Colonnes Optionnelles
Username,FirstName,LastName,Email,Department,Title,Office,Phone,Groups,OU,Password,Description
jdoe,John,Doe,john.doe@company.com,IT,Developer,Paris,+33123456789,Developers;IT-Users,OU=Users,OU=IT,DC=company,DC=com,,New developer
asmith,Alice,Smith,alice.smith@company.com,HR,Manager,Lyon,+33987654321,HR-Team;Managers,OU=Users,OU=HR,DC=company,DC=com,,HR Manager
bwilson,Bob,Wilson,bob.wilson@company.com,Finance,Analyst,Paris,,Finance-Users,,,Contractor
Exemple Complet
Fichier new_users.csv:
Username,FirstName,LastName,Email,Department,Title,Groups
jdupont,Jean,Dupont,jean.dupont@company.com,IT,Administrateur Systรจme,IT-Admins;VPN-Users
mmartin,Marie,Martin,marie.martin@company.com,RH,Responsable RH,HR-Team;Managers
pdurand,Pierre,Durand,pierre.durand@company.com,Dev,Dรฉveloppeur Senior,Developers;Git-Users
sleblanc,Sophie,Leblanc,sophie.leblanc@company.com,Finance,Comptable,Finance-Users
Utilisation
Active Directory
# Crรฉer des utilisateurs AD avec mots de passe gรฉnรฉrรฉs
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode AD -GeneratePasswords
# Avec export des credentials
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode AD -GeneratePasswords `
-ExportCredentials "C:\Admin\new_users_credentials.csv"
# Avec OU et groupes par dรฉfaut
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode AD -GeneratePasswords `
-DefaultOU "OU=NewUsers,OU=Company,DC=domain,DC=com" `
-DefaultGroups @("Domain Users", "VPN-Access")
# Mode simulation
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode AD -GeneratePasswords -WhatIf
# Avec mot de passe par dรฉfaut
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode AD -DefaultPassword "Welcome2024!"
Utilisateurs Locaux
# Crรฉer des utilisateurs locaux
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode Local -GeneratePasswords
# Avec groupe local par dรฉfaut
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode Local -GeneratePasswords `
-DefaultGroups @("Remote Desktop Users")
# Simulation
.\New-BulkUsers.ps1 -CsvPath users.csv -Mode Local -DefaultPassword "TempPass!" -WhatIf
Sortie Exemple
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
BULK USER MANAGER
Mode: AD
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
[2024-01-15 14:30:22] [SUCCESS] ActiveDirectory module loaded
[2024-01-15 14:30:22] [INFO] Loading CSV: C:\Admin\users.csv
[2024-01-15 14:30:22] [INFO] Found 4 users to process
[2024-01-15 14:30:22] [INFO] Processing: jdupont (Jean Dupont)
[2024-01-15 14:30:23] [INFO] Added to group: IT-Admins
[2024-01-15 14:30:23] [INFO] Added to group: VPN-Users
[2024-01-15 14:30:23] [SUCCESS] User created successfully
[2024-01-15 14:30:23] [INFO] Processing: mmartin (Marie Martin)
[2024-01-15 14:30:24] [INFO] Added to group: HR-Team
[2024-01-15 14:30:24] [INFO] Added to group: Managers
[2024-01-15 14:30:24] [SUCCESS] User created successfully
[2024-01-15 14:30:24] [INFO] Processing: pdurand (Pierre Durand)
[2024-01-15 14:30:24] [WARN] User already exists, skipping
[2024-01-15 14:30:24] [INFO] Processing: sleblanc (Sophie Leblanc)
[2024-01-15 14:30:25] [INFO] Added to group: Finance-Users
[2024-01-15 14:30:25] [SUCCESS] User created successfully
[2024-01-15 14:30:25] [SUCCESS] Credentials exported to: C:\Admin\credentials.csv
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
SUMMARY
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Total Processed: 4
Created: 3
Skipped: 1
Failed: 0
Fichier Credentials Exportรฉ
Username,Password,Email,CreatedAt
jdupont,X7#kL9@mN2$pQ4,jean.dupont@company.com,2024-01-15 14:30:23
mmartin,R5$tY8&uI1@oP3,marie.martin@company.com,2024-01-15 14:30:24
sleblanc,W2#eR6$tY9@uI4,sophie.leblanc@company.com,2024-01-15 14:30:25
Bonnes Pratiques
- Toujours tester en mode WhatIf avant exรฉcution rรฉelle
- Sรฉcuriser le fichier credentials exportรฉ (supprimer aprรจs distribution)
- Forcer le changement de mot de passe ร la premiรจre connexion
- Valider le CSV avant import (caractรจres spรฉciaux, doublons)
- Logger les opรฉrations pour audit