Backup Structuur
Per user:
C:\AD_Backup\20250101_143052\
βββ john.doe.json
βββ jane.smith.json
βββ peter.jones.json
βββ ...
βββ _index.json
User JSON format:
{
"SamAccountName": "john.doe",
"DistinguishedName": "CN=John Doe,OU=Employees,DC=company,DC=nl",
"UserPrincipalName": "john.doe@company.nl",
"ObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"BackupDate": "2025-01-01 14:30:52",
"BackupServer": "DC01",
"Properties": {
"DisplayName": "John Doe",
"GivenName": "John",
"Surname": "Doe",
"Title": "Senior Developer",
"Department": "Engineering",
"Manager": "CN=Jane Smith,OU=Managers,DC=company,DC=nl",
"EmailAddress": "john.doe@company.nl",
"OfficePhone": "+31 20 1234567",
"MobilePhone": "+31 6 12345678",
"StreetAddress": "Main Street 123",
"City": "Amsterdam",
"PostalCode": "1012 AB",
"Country": "NL",
...
}
}
Index file (_index.json):
{
"BackupDate": "2025-01-01 14:30:52",
"Server": "DC01",
"SearchBase": "OU=Employees,DC=company,DC=nl",
"TotalUsers": 1245,
"AveragePropertiesPerUser": 40.87,
"ExcludedProperties": [
"BadLogonCount",
"ObjectGUID",
"ObjectSID",
...
],
"Users": [
{
"SamAccountName": "john.doe",
"UserPrincipalName": "john.doe@company.nl",
"DisplayName": "John Doe",
"DistinguishedName": "CN=John Doe,OU=Employees,DC=company,DC=nl",
"Enabled": true,
"ObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
...
]
}
Script Code
param(
[Parameter(Mandatory=$false)]
[string]$BackupPath = "C:\AD_Backup\$(Get-Date -Format 'yyyyMMdd_HHmmss')",
[Parameter(Mandatory=$false)]
[string]$SearchBase = "",
[Parameter(Mandatory=$false)]
[string]$Server = $env:LOGONSERVER.Replace("\\", "")
)
if (!(Get-Module -ListAvailable -Name ActiveDirectory)) {
Write-Host "Error: ActiveDirectory module not found" -ForegroundColor Red
Write-Host "Install with: Install-WindowsFeature RSAT-AD-PowerShell" -ForegroundColor Yellow
return
}
Import-Module ActiveDirectory
New-Item -ItemType Directory -Path $BackupPath -Force | Out-Null
Write-Host "`nStarting AD user backup" -ForegroundColor Green
Write-Host "Server: $Server" -ForegroundColor Cyan
Write-Host "Path: $BackupPath" -ForegroundColor Cyan
$excludedProperties = @(
'ObjectGUID', 'ObjectSID', 'SID', 'DistinguishedName', 'CN', 'Name', 'SamAccountName',
'WhenCreated', 'WhenChanged', 'Created', 'Modified', 'createTimeStamp', 'modifyTimeStamp',
'LastLogonDate', 'LastBadPasswordAttempt', 'accountExpires', 'lastLogoff',
'ObjectClass', 'ObjectCategory', 'DSCorePropagationData', 'InstanceType',
'uSNCreated', 'uSNChanged', 'nTSecurityDescriptor',
'lastLogon', 'lastLogonTimestamp', 'logonCount', 'LastLogon',
'badPwdCount', 'badPasswordTime', 'pwdLastSet', 'BadLogonCount',
'PropertyNames', 'PropertyCount', 'AddedProperties',
'ModifiedProperties', 'RemovedProperties', 'ProtectedFromAccidentalDeletion',
'AccountNotDelegated', 'AllowReversiblePasswordEncryption', 'CannotChangePassword',
'DoesNotRequirePreAuth', 'Enabled', 'HomedirRequired', 'LockedOut',
'MNSLogonAccount', 'PasswordExpired', 'PasswordNeverExpires', 'PasswordNotRequired',
'SmartcardLogonRequired', 'TrustedForDelegation', 'TrustedToAuthForDelegation',
'UseDESKeyOnly', 'userAccountControl',
'PrimaryGroup', 'primaryGroupID', 'adminCount',
'sAMAccountType', 'showInAdvancedViewOnly', 'codePage', 'countryCode',
'msDS-SupportedEncryptionTypes',
'msDS-ReplAttributeMetaData', 'msDS-ReplValueMetaData',
'replPropertyMetaData', 'replUpToDateVector',
'TokenGroups', 'TokenGroupsGlobalAndUniversal', 'TokenGroupsNoGCAcceptable',
'CanonicalName', 'Deleted', 'isDeleted', 'sDRightsEffective',
'msDS-User-Account-Control-Computed', 'IsCriticalSystemObject'
)
$params = @{
Filter = '*'
Properties = '*'
Server = $Server
}
if ($SearchBase) {
$params.SearchBase = $SearchBase
Write-Host "SearchBase: $SearchBase" -ForegroundColor Cyan
}
$users = Get-ADUser @params
$totalUsers = $users.Count
$counter = 0
$totalPropertiesBackedUp = 0
Write-Host "Found $totalUsers users`n" -ForegroundColor Yellow
foreach ($user in $users) {
$counter++
$percentComplete = [math]::Round(($counter / $totalUsers) * 100, 2)
Write-Progress -Activity "Backing up users" -Status "$($user.SamAccountName)" -PercentComplete $percentComplete
$userBackup = @{
SamAccountName = $user.SamAccountName
DistinguishedName = $user.DistinguishedName
UserPrincipalName = $user.UserPrincipalName
ObjectGUID = $user.ObjectGUID.ToString()
BackupDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
BackupServer = $Server
Properties = @{}
}
$propertiesBackedUp = 0
$user.PSObject.Properties | ForEach-Object {
$propName = $_.Name
$propValue = $_.Value
if ($excludedProperties -notcontains $propName -and
$propName -notmatch '^Property' -and
$propValue -ne $null) {
try {
$valueToStore = $null
if ($propValue -is [DateTime]) {
$valueToStore = $propValue.ToString("yyyy-MM-dd HH:mm:ss")
}
elseif ($propValue -is [Microsoft.ActiveDirectory.Management.ADPropertyValueCollection]) {
$valueToStore = @($propValue)
}
elseif ($propValue -is [System.Security.Principal.SecurityIdentifier]) {
$valueToStore = $propValue.Value
}
elseif ($propValue -is [byte[]]) {
$valueToStore = [Convert]::ToBase64String($propValue)
}
elseif ($propValue.GetType().Name -eq 'ActiveDirectorySecurity') {
$valueToStore = $null
}
else {
$valueToStore = $propValue
}
if ($null -ne $valueToStore) {
$userBackup.Properties[$propName] = $valueToStore
$propertiesBackedUp++
}
}
catch {
Write-Host "Warning: Failed to backup property '$propName' for $($user.SamAccountName): $($_.Exception.Message)" -ForegroundColor DarkYellow
}
}
}
$totalPropertiesBackedUp += $propertiesBackedUp
$safeFileName = $user.SamAccountName -replace '[\\/:*?"<>|]', '_'
$filePath = Join-Path $BackupPath "$safeFileName.json"
$userBackup | ConvertTo-Json -Depth 10 | Out-File -FilePath $filePath -Encoding UTF8
Write-Host "[$counter/$totalUsers] $($user.SamAccountName) - $propertiesBackedUp properties" -ForegroundColor Cyan
}
$indexFile = @{
BackupDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Server = $Server
SearchBase = $SearchBase
TotalUsers = $totalUsers
AveragePropertiesPerUser = [math]::Round($totalPropertiesBackedUp / $totalUsers, 2)
ExcludedProperties = $excludedProperties | Sort-Object
Users = $users | Select-Object SamAccountName, UserPrincipalName, DisplayName, DistinguishedName,
Enabled, @{N='ObjectGUID';E={$_.ObjectGUID.ToString()}}
}
$indexFile | ConvertTo-Json -Depth 5 | Out-File -FilePath (Join-Path $BackupPath "_index.json") -Encoding UTF8
Write-Progress -Activity "Backing up users" -Completed
Write-Host "`n========================================" -ForegroundColor Green
Write-Host "Backup completed" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host "Location: $BackupPath" -ForegroundColor Yellow
Write-Host "Users: $totalUsers" -ForegroundColor Yellow
Write-Host "Properties: $totalPropertiesBackedUp" -ForegroundColor Yellow
Write-Host "Average: $([math]::Round($totalPropertiesBackedUp / $totalUsers, 2)) per user" -ForegroundColor Yellow
Write-Host "`nRestore examples:" -ForegroundColor Cyan
Write-Host " Restore complete user (default):" -ForegroundColor Gray
Write-Host " .\Restore-ADUser.ps1 -BackupPath `"$BackupPath`" -SamAccountName `"username`"" -ForegroundColor White
Write-Host "`n Restore specific properties:" -ForegroundColor Gray
Write-Host " .\Restore-ADUser.ps1 -BackupPath `"$BackupPath`" -SamAccountName `"username`" -Properties `"Title`",`"Department`"" -ForegroundColor White
Write-Host "`n Preview changes (WhatIf):" -ForegroundColor Gray
Write-Host " .\Restore-ADUser.ps1 -BackupPath `"$BackupPath`" -SamAccountName `"username`" -WhatIf -ShowDifferences" -ForegroundColor White
Write-Host "========================================`n" -ForegroundColor Green