Обезличивание данных Active Directory с очисткой корзины

В разделе описывается последовательность шагов по обезличиванию данных Active Directory (AD) на сервере с ОС Windows Server, включая очистку корзины.

Предварительные требования

Для успешного выполнения описываемых шагов обеспечьте соблюдение следующих требований:

  • все действия выполняются от имени пользователя с правами на выгрузку и загрузку данных в БД AD и выполнение указанных командлет PowerShell;

  • команды выполняются на машине с установленным модулем Active Directory для Windows Powershell непосредственно на сервере либо с использованием средств удаленного администрирования;

  • последовательности команд могут выполняться непосредственно в терминале Windows PowerShell, в том числе в среде Windows PowerShell ISE, либо в виде скриптов (для удобства приводятся оба варианта);

  • для выполнения отдельных шагов требуется следующее дополнительное программное обеспечение:

    • Microsoft Excel любой версии;

    • оснастка ADSI Edit (adsiedit.msc);

    • утилита ldp для подключения к БД по LDAP с целью выполнения контрольных проверок.

Выгрузка данных пользователей

  1. Выгрузите данные любым из двух способов:

    • выполните в терминале Windows PowerShell или среде Windows PowerShell ISE следующую последовательность команд, указав в качестве входных параметров полное доменное имя сервера (server.domain.name), имя домена (domain.name), путь к CSV-файлу с данными пользователей (path-to-user-list-file) и путь к текстовому файлу со списком удаляемых пользователей (path-to-users-to-delete):

      $domainController = "<server.domain.name>"
      $domain = "<domain.name>"
      $outputFile = "<path-to-user-list-file>\UserList.csv"
      $path = "<path-to-users-to-delete>\UsersToDelete.txt"
      
      $users = Get-ADUser -Filter * -Properties * -Server $domainController
      $output = @()
      $output += "OU;Name;GivenName;SurName;DisplayName;Title;SamAccountName;UserPrincipalName;EmailAddress"
      
      foreach ($user in $users) {
          $ou = ($user.DistinguishedName -split ",", 2)[1]
          $userLine = "$ou;$($user.Name);$($user.GivenName);$($user.SurName);$($user.DisplayName);$($user.Title);$($user.SamAccountName);$($user.UserPrincipalName);$($user.EmailAddress)"
          $output += $userLine
      }
      
      $output | Out-File $outputFile
      
      Get-ADUser -filter * | select SamAccountName | Out-File -FilePath $path
      $content = Get-Content $path
      $content | Foreach {$_.TrimEnd()} | ? {$_.trim() -ne "" } | Set-Content $path
    • с помощью скрипта:

      • загрузите на сервер скрипт или создайте файл export_users.ps1 следующего содержания:

        Скрипт для выгрузки данных пользователей AD и списка пользователей
        param (
            [string]$domainController,
            [string]$domain,
            [string]$outputFile,
            [string]$path
        )
        
        $users = Get-ADUser -Filter * -Properties * -Server $domainController
        $output = @()
        $output += "OU;Name;GivenName;SurName;DisplayName;Title;SamAccountName;UserPrincipalName;EmailAddress"
        
        foreach ($user in $users) {
            $ou = ($user.DistinguishedName -split ",", 2)[1]
            $userLine = "$ou;$($user.Name);$($user.GivenName);$($user.SurName);$($user.DisplayName);$($user.Title);$($user.SamAccountName);$($user.UserPrincipalName);$($user.EmailAddress)"
            $output += $userLine
        }
        
        $output | Out-File $outputFile
        
        Get-ADUser -filter * | select SamAccountName | Out-File -FilePath $path
        $content = Get-Content $path
        $content | Foreach {$_.TrimEnd()} | ? {$_.trim() -ne "" } | Set-Content $path
      • запустите скрипт в терминале Windows PowerShell:

        ./export_users.ps1 <server.domain.name> <domain.name> <path-to-user-list-file> <path-to-users-to-delete-file>

        Входные параметры:

        • server.domain.name — полное доменное имя сервера;

        • domain.name — имя домена;

        • path-to-user-list-file — путь и имя для CSV-файла с данными пользователей;

        • path-to-users-to-delete-file — путь и имя для текстового файла со списком удаляемых пользователей.

        Пример команды запуска скрипта:

        ./export_users.ps1 WINDOWS-OT89IIK.testl.lan testl.lan C:\temp\UserList.csv C:\temp\UsersToDelete.txt
  2. Откройте созданный файл UserList.csv в текстовом редакторе, чтобы убедиться в корректности выгрузки.
    Он должен иметь следующий формат:

    OU;Name;GivenName;SurName;DisplayName;Title;SamAccountName;UserPrincipalName;EmailAddress
    CN=Users,DC=domain,DC=name;Administrator;;;;;Administrator;;
    CN=Users,DC=domain,DC=name;Guest;;;;;Guest;;
    CN=Users,DC=domain,DC=name;krbtgt;;;;;krbtgt;;
    CN=Users,DC=domain,DC=name;Ivan Ivanov;Ivan;Ivanov;Ivan Ivanov;;iivanov;iivanov@domain.name;ivanov@mail.com
    CN=Users,DC=domain,DC=name;Petr Petrov;Petr;Petrov;Petr Petrov;;ppetrov;ppetrov@domain.name;petrov@mail.com
  3. Откройте файл UsersToDelete.txt в текстовом редакторе, чтобы убедиться в корректности выгрузки.
    Он должен иметь следующий формат:

    SamAccountName
    --------------
    Administrator
    Guest
    krbtgt
    iivanov
    ppetrov
  4. В файле UsersToDelete.txt:

    • удалите заголовок;

    • удалите из списка сервисных пользователей (Administrator, Guest и т. д.);

    • удостоверьтесь, что в списке присутствуют только значения атрибута SamAccountName тех пользователей, данные которых требуется удалить. На каждой строке должно быть только одно значение SamAccountName.

      Например:

      iivanov
      ppetrov

Обезличивание данных пользователей

Чтобы обезличить данные пользователей, выгруженные в файл UserList.csv:

  1. Создайте пустую книгу в Microsoft Excel.

  2. На вкладке Данные нажмите Из текстового/CSV-файла.

    anonymization 1
    Рис. 1. Вкладка «Данные» в Microsoft Excel
  3. В диалоговом окне выберите CSV-файл с выгруженными данными и нажмите Импорт.

  4. В окне предварительного просмотра убедитесь в корректности отображения данных. При необходимости внесите изменения в настройки отображения и нажмите Загрузить.

    anonymization 5
    Рис. 2. Окно предварительного просмотра импортируемых данных
  5. В качестве имени листа с импортированными данными укажите "deface".

    anonymization 7
    Рис. 3. Переименование листа
  6. Откройте вкладку Конструктор и снимите флажок Строка заголовка. Если первая строка в таблице пустая, удалите ее. Таким образом, в первой строке рабочего листа должны быть заголовки столбцов из CSV-файла.

    anonymization 6
    Рис. 4. Удаление строки заголовка
  7. Нажмите Alt+F11.

  8. В окне Microsoft Visual Basic for Applications нажмите F7.

  9. В области редактора кода вставьте текст скрипта:

    Скрипт для обезличивания данных AD
    Sub Main()
    
        ChangeValuesToGenerated
        ChangeValueToHeaderValue
        ReplaceEmails
        CanonicalNameProc
        legacyExchangeDNProc
        DistinguishedNameProc
        HomeDirectoryClean
    
    End Sub
    
    Sub ChangeValuesToGenerated()
        Dim ws As Worksheet
        Dim headerArray As Variant ' Create array of headers
        Dim rng As Range
        Dim cell As Range
        Dim i As Integer
        Dim j As Integer
    
        Set ws = ThisWorkbook.Sheets("deface") ' Change your sheet name to deface
        headerArray = Array("CN", "DisplayName", "GivenName", "Name", "SamAccountName", "sn", "Surname") ' array of headers
    
        For j = LBound(headerArray) To UBound(headerArray)
            i = 1
            Set rng = ws.Rows(1).Find(What:=headerArray(j), LookIn:=xlValues, LookAt:=xlWhole)
    
            If Not rng Is Nothing Then
                For Each cell In rng.Offset(1).Resize(ws.Cells(ws.Rows.Count, rng.Column).End(xlUp).Row).Cells
                    If Not IsEmpty(cell.Value) Then
                        cell.Value = 1005000 + i
                        i = i + 1
                    End If
                Next cell
            End If
        Next j
    End Sub
    
    Sub ChangeValueToHeaderValue()
        Dim ws As Worksheet
        Dim headerArray As Variant ' Create array of headers
        Dim rng As Range
        Dim cell As Range
        Dim i As Integer
        Dim j As Integer
    
        Set ws = ThisWorkbook.Sheets("deface") ' Change your sheet name to deface
        headerArray = Array("Department", "Description", "extensionAttribute5", "City", "City_1", "Title", "userCertificate") ' array of headers
    
        For j = LBound(headerArray) To UBound(headerArray)
            Set rng = ws.Rows(1).Find(What:=headerArray(j), LookIn:=xlValues, LookAt:=xlWhole)
    
            If Not rng Is Nothing Then
                For Each cell In rng.Offset(1).Resize(ws.Cells(ws.Rows.Count, rng.Column).End(xlUp).Row).Cells
                    If Not IsEmpty(cell.Value) Then
                        cell.Value = headerArray(j)
                    End If
                Next cell
            End If
        Next j
    End Sub
    
    Sub ReplaceEmails()
        Dim ws As Worksheet
        Dim headerArray As Variant ' Create array of headers
        Dim rng As Range
        Dim cell As Range
        Dim i As Integer
        Dim j As Integer
        Dim atIndex As Integer
        Dim cellValue As String
    
        Set ws = ThisWorkbook.Sheets("deface") ' Change your sheet name to deface
        headerArray = Array("EmailAddress", "mail", "UserPrincipalName") ' array of headers
    
        For j = LBound(headerArray) To UBound(headerArray)
            i = 1
            Set rng = ws.Rows(1).Find(What:=headerArray(j), LookIn:=xlValues, LookAt:=xlWhole)
    
            If Not rng Is Nothing Then
                For Each cell In rng.Offset(1).Resize(ws.Cells(ws.Rows.Count, rng.Column).End(xlUp).Row).Cells
                    If Not IsEmpty(cell.Value) Then
                        cellValue = cell.Value
                        atIndex = InStr(cellValue, "@")
                        If atIndex > 0 And atIndex < Len(cellValue) Then
                            cell.Value = 100500 + i & "@" & Mid(cellValue, atIndex + 1) ' Get all text data after "@"
                            i = i + 1
                        Else
                            cell.Value = "" ' If "@" is not found or it is in the end of the string
                            i = i + 1
                        End If
                    End If
                Next cell
            End If
        Next j
    End Sub
    
    Sub CanonicalNameProc()
        Dim ws As Worksheet
        Dim rng As Range
        Dim cell As Range
        Dim i As Integer
        Dim cellValue As String
        Dim lastBackslashIndex As Integer
    
        Set ws = ThisWorkbook.Sheets("deface") ' Change your sheet name to deface
        i = 1
    
        ' processing "CanonicalName"
        Set rng = ws.Rows(1).Find(What:="CanonicalName", LookIn:=xlValues, LookAt:=xlWhole)
    
        If Not rng Is Nothing Then
            For Each cell In rng.Offset(1).Resize(ws.Cells(ws.Rows.Count, rng.Column).End(xlUp).Row).Cells
                If Not IsEmpty(cell.Value) Then
                    cellValue = cell.Value
                    lastBackslashIndex = InStrRev(cellValue, "/") ' Cut everything after "/" character
                    If lastBackslashIndex > 0 Then
                        cell.Value = Left(cellValue, lastBackslashIndex - 1) & "/" & 100500 + i
                    End If
                    i = i + 1
                Else
                    cell.Value = ""
                End If
            Next cell
        End If
    End Sub
    
    Sub legacyExchangeDNProc()
        Dim ws As Worksheet
        Dim rng As Range
        Dim cell As Range
        Dim i As Integer
        Dim cellValue As String
        Dim lastBackslashIndex As Integer
    
        Set ws = ThisWorkbook.Sheets("deface") ' Change your sheet name to deface
        i = 1
    
        ' processing "legacyExchangeDN"
        Set rng = ws.Rows(1).Find(What:="legacyExchangeDN", LookIn:=xlValues, LookAt:=xlWhole)
    
        If Not rng Is Nothing Then
            For Each cell In rng.Offset(1).Resize(ws.Cells(ws.Rows.Count, rng.Column).End(xlUp).Row).Cells
                If Not IsEmpty(cell.Value) Then
                    cellValue = cell.Value
                    lastBackslashIndex = InStrRev(cellValue, "-") ' Cut everything after "-" character
                    If lastBackslashIndex > 0 Then
                        cell.Value = Left(cellValue, lastBackslashIndex - 1) & "-" & 100500 + i
                    End If
                    i = i + 1
                Else
                    cell.Value = ""
                End If
            Next cell
        End If
    End Sub
    
    Sub DistinguishedNameProc()
        Dim ws As Worksheet
        Dim rng As Range
        Dim cell As Range
        Dim i As Integer
        Dim cellValue As String
        Dim equalSignIndex As Integer
        Dim commaIndex As Integer
    
        Set ws = ThisWorkbook.Sheets("deface") ' Change your sheet name to deface
        i = 1
    
        ' processing "DistinguishedName"
        Set rng = ws.Rows(1).Find(What:="DistinguishedName", LookIn:=xlValues, LookAt:=xlWhole)
    
        If Not rng Is Nothing Then
            For Each cell In rng.Offset(1).Resize(ws.Cells(ws.Rows.Count, rng.Column).End(xlUp).Row).Cells
                If Not IsEmpty(cell.Value) Then
                        cellValue = cell.Value
                        equalSignIndex = InStr(1, cellValue, "=") ' Find the place of first "="
                        commaIndex = InStr(equalSignIndex, cellValue, ",") ' Find the place of next ','
                        If equalSignIndex > 0 And commaIndex > 0 Then
                            cell.Value = Left(cellValue, equalSignIndex) & 100500 + i & Mid(cellValue, commaIndex)
                        End If
                i = i + 1
                Else
                    cell.Value = ""
                End If
            Next cell
        End If
    End Sub
    
    Sub HomeDirectoryClean()
        Dim ws As Worksheet
        Dim rng As Range
        Dim cell As Range
        Dim cellValue As String
    
        Set ws = ThisWorkbook.Sheets("deface") ' Change your sheet name to deface
    
        ' processing "HomeDirectory"
        Set rng = ws.Rows(1).Find(What:="HomeDirectory", LookIn:=xlValues, LookAt:=xlWhole)
    
        If Not rng Is Nothing Then
            For Each cell In rng.Offset(1).Resize(ws.Cells(ws.Rows.Count, rng.Column).End(xlUp).Row).Cells
                If Not IsEmpty(cell.Value) Then
                        cell.Value = ""
                End If
            Next cell
        End If
    End Sub
  10. Для запуска скрипта переместите курсор на имя функции Main() и нажмите кнопку run button на панели инструментов или клавишу F5.

    anonymization 4
    Рис. 5. Запуск скрипта
  11. Убедитесь, что все требуемые атрибуты обезличены.

  12. Сохраните лист как CSV-файл.

    Например, нажмите F12 и в раскрывающемся списке в поле Тип файла выберите CSV UTF-8 (разделитель — запятая) (*.csv). При этом в итоговом файле в качестве разделителя будет использоваться точка с запятой.
  13. Убедитесь, что у файла установлена корректная кодировка (например, UTF-8), а в качестве разделителя столбцов используется точка с запятой (;).

Удаление пользователей

Перед удалением откройте файл UsersToDelete.txt и еще раз убедитесь в том, что в нем отсутствуют сервисные пользователи (Administrator, Guest и т. п.)!
  1. Для удаления пользователей выполните в терминале Windows PowerShell или среде Windows PowerShell ISE следующую последовательность команд, указав в качестве входного параметра путь к файлу со списком удаляемых пользователей (path-to-users-to-delete-file):

    $Users = Get-Content -Path <path-to-users-to-delete>\UsersToDelete.txt
    
    Foreach ($Sser in $Users){
        Remove-ADUser -identity $Sser
    }

    Например:

    $Users = Get-Content -Path C:\temp\UsersToDelete.txt
    
    Foreach ($Sser in $Users){
        Remove-ADUser -identity $Sser
    }
  2. Подтвердите необходимость удаления.

  3. Убедитесь, что перечисленные в файле пользователи удалены корректно. Например, откройте оснастку Active Directory Users and Computers, выберите имя домена в дереве каталога, выберите Users и выполните визуальную проверку списка пользователей в области просмотра справа.

Изменение срока хранения объектов в корзине

  1. Запустите оснастку ADSI Edit (adsiedit.msc).

  2. В основном меню нажмите Action, выберите Connect to…​, в выпадающем списке Select a well known Naming Context выберите Configuration и в диалоговом окне нажмите OK.

    adsi 1
    Рис. 6. Выбор контекста именования Configuration для подключения
  3. В дереве в панели слева выберите Configuration → CN=Configuration → CN=Services → CN=Windows NT → CN=Directory Service. Нажмите правую кнопку мыши на пункте CN=Directory Service и в контекстном меню выберите Properties.

    adsi 2
    Рис. 7. Путь к атрибуту MSDS-DeletedObjectLifeTime
  4. В окне свойств дважды щелкните строку с атрибутом MSDS-DeletedObjectLifeTime. В диалоговом окне редактора атрибута введите 2 в поле ввода и нажмите OK.

    adsi 3
    Рис. 8. Изменение значения атрибута MSDS-DeletedObjectLifeTime
  5. Нажмите Apply и OK. Закройте оснастку ADSI Editor.

  6. Выждите двое суток до полной очистки корзины.

Загрузка обезличенных данных пользователей

  1. Загрузите на сервер скрипт или создайте файл import_users.ps1 следующего содержания:

    Скрипт для загрузки обезличенных данных пользователей AD
    Param (
      [string]$path,
      [string]$UPN,
      [string]$pass
    )
    
    $ADUsers = Import-Csv $path -Delimiter ";"
    
    
    # Import active directory module for running AD cmdlets
    Import-Module ActiveDirectory
    
    
    # Define
    $password = ConvertTo-SecureString $pass -AsPlainText -Force
    
    # Loop through each row containing user details in the CSV file
    foreach ($User in $ADUsers) {
        try {
            # Define the parameters using a hashtable
            $UserParams = @{
                SamAccountName        = $User.name
                UserPrincipalName     = "$($User.name)@$UPN"
                Name                  = $User.name
                GivenName             = $User.GivenName
                Surname               = $User.Surname
                Enabled               = $True
                DisplayName           = "$($User.GivenName) $($User.Surname)"
                Path                  = $User.ou
                EmailAddress          = $User.EmailAddress
                Title                 = $User.Title
                AccountPassword       = $password
                ChangePasswordAtLogon = $False
            }
    
            # Check to see if the user already exists in AD
            if (Get-ADUser -Filter "SamAccountName -eq '$($User.name)'") {
    
                # Give a warning if user exists
                Write-Host "A user with username $($User.name) already exists in Active Directory." -ForegroundColor Yellow
            }
            else {
                # User does not exist then proceed to create the new user account
                # Account will be created in the OU provided by the $User.ou variable read from the CSV file
                New-ADUser @UserParams
    
                # If user is created, show message.
                Write-Host "The user $($User.name) is created." -ForegroundColor Green
            }
        }
        catch {
            # Handle any errors that occur during account creation
            Write-Host "Failed to create user $($User.name) - $_" -ForegroundColor Red
        }
    }
  2. Запустите скрипт в терминале Windows PowerShell:

    ./import_users.ps1 <path-to-user-list-file> <upn-suffix> <password>

    Параметры вызова:

    • path-to-user-list-file — путь к CSV-файлу с обезличенными данными пользователей;

    • upn-suffix — суффикс UPN для импортируемых пользователей (имя домена);

    • password — пароль, который будет задан для всех импортируемых пользователей.

    Например:

    ./import_users.ps1 C:\temp\UserList.csv testl.lan PasswD123!
    import users script
    Рис. 9. Результат работы скрипта загрузки обезличенных данных пользователей

Проверка отсутствия персональных и других чувствительных данных

Для проверки может использоваться, например, утилита ldp:

  1. Нажмите клавиши Windows + R, наберите в поле ввода название утилиты ldp и нажмите OK.

  2. В строке меню выберите Options →Controls, в раскрывающемся списке Load Predefined последовательно выберите Return deleted objects и Return recycled objects.

    ldp controls
    Рис. 10. Настройка отображения удаленных объектов и объектов, помещенных в корзину, в утилите ldp
  3. Для подключения по LDAP:

    • в строке меню выберите Connection → Connect и нажмите OK;

    • в строке меню выберите Connection → Bind и нажмите OK.

  4. Для просмотра ветки с удаленными объектами:

    • в строке меню выберите View → Tree, в выпадающем списке выберите строку DC=domain,DC=name и нажмите OK;

      ldp tree view
      Рис. 11. Выбор области просмотра дерева
    • в дереве каталога раскройте список DC=domain,DC=name и выберите ветку CN=DeletedObjects,DC=domain,DC=name.

      ldp deleted objects branch
      Рис. 12. Выбор ветки
  5. Убедитесь, что в ветке отсутствуют записи.