none
Проблема при выдаче прав на каталог пользователям AD с помощью Powershell RRS feed

  • Вопрос

  • Здравствуйте. Прошу совета в решении вот какой проблемы.

    Есть необходимость создания большого количества пользователей за раз (более 30, несколько академических групп студентов). Для этого написали скрипт, часть которого представлена ниже.

    function createUserStudentPM($cnName,$login,$pass,$givenName,$surName,$rusGroup,$ActionDate,$dirPath,$ouPath)
    {
           try{
                #Добавление пользователя в домен
                $enGroup=transleter($rusGroup)
                $enGroup=$enGroup.ToUpper()
                New-ADUser $cnName -SamAccountName $login -UserPrincipalName "$login@ad.ХХХ" -AccountPassword $pass -GivenName $givenName -Surname $surName -AccountExpirationDate $ActionDate -Company "ХХХ" -Department "Группа $rusGroup" -HomeDirectory "$dirPath\$enGroup\$login" -HomeDrive "H:" -path $ouPath
                Write-Host "Создан пользователь $cnName"
                Enable-ADAccount "$login" 
                Add-ADGroupMember -Identity "Группа $rusGroup" -Members "$login"
                #Создаем папку
                New-Item -Path "$dirPath\$enGroup\$login" -ItemType "directory" >> $NULL
                #Выдаем права на папку для пользователя
                $acl=Get-Acl -Path "$dirPath\$enGroup\$login"
                $rule=New-Object System.Security.AccessControl.FileSystemAccessRule "$login","FullControl","ContainerInherit,ObjectInherit","None","allow"
                $acl.AddAccessRule($rule)
                Set-Acl -Path "$dirPath\$enGroup\$login" -AclObject $acl                                                                                                                                
                                                                    
                echo "$str;$login;$strPass" | out-file -FilePath $userPass -Append
              }
           #Исключение срабатывает если такой пользователь уже существует
           catch [Microsoft.ActiveDirectory.Management.ADIdentityAlreadyExistsException]
           {
                $strError=$Error[0].Exception.Message
    	    echo "Error;Пользователь: $str;$strError" | out-file -filepath $logError -Append
                Write-Host "Пользователь: $str уже сущестует" -ForegroundColor "Red"
           }
           #Исключение срабатывает если папка уже существует
           catch [System.IO.IOException]
           {
                $strError=$Error[0].Exception.Message
    	    echo "Error;Директория $login;$strError" | out-file -filepath $logError -Append
                Write-Host "Директория $login уже сущестует" -ForegroundColor "Red"
           }
           catch [System.Management.Automation.MethodInvocationException]
           {
                $strError=$Error[0].Exception.Message
    	    echo "Error;$cnName;$strError" | out-file -filepath $logError -Append
                Write-Host "При создании логина $cnName произошла странная непредвиденная ошибка см. в заголовке скрипта." -ForegroundColor "Red"
           }
    }
    
    Get-Content $inputFile | ForEach-Object {$str=$_.split(";")
                                             $cnName=$str[0].trim(" ")
                                             $rusGroup=$str[1].trim(" ")
                                             #Проверяем существует ли группа
                                             $anse="Да"
                                             try {Get-ADGroup -Identity "Группа $rusGroup">>$NULL}
                                             #Если группа не существует, создаем её
                                             catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] 
                                             {
                                                      $anse=Read-Host "Академическая группа $rusGroup не создавалась в структуре AD. Создать группу 'Группа $rusGroup'?`n[Да/Нет]" 
                                                      if(($anse -eq "Да") -or ($anse -eq "Д")){
                                                           #Создание группы
                                                           $enGroup=transleter($rusGroup)
                                                           $enGroup=$enGroup.ToUpper()
                                                           #добовляем глобальную группу безопасности с именем группы студентов
                                                           try {
                                                                     New-ADGroup -Name "Группа $rusGroup" -SamAccountName "Группа $rusGroup" -GroupCategory Security -GroupScope Global -DisplayName "Группа $rusGroup" -Path $ouPath
                                                                     #помещаем созданную группу в группу "_Группа с персональными логинами"
                                                                     Add-ADGroupMember -Identity $group -Members "Группа $rusGroup"
                                                                     #создаем папку группы 
                                                                     New-Item -Path "$dirPath\$enGroup" -ItemType "directory" >>$NULL
                                                                     New-Item -Path "$dirPath\_GROUPS\$enGroup" -ItemType "directory" >>$NULL
                                                                     Write-Host "Группа $rusGroup успешно создана"
                                                               }
                                                               #Исключение срабатывает если такая папка уже существует
                                                           catch [System.IO.IOException]
                                                           {
                                                                  $strError=$Error[0].Exception.Message
                                                                  echo "Error;Директория $enGroup;$strError" | out-file -filepath $logError -Append
                                                                  Write-Host "Директория $enGroup уже сущестует" -ForegroundColor "Red"
                                                                  exit
                                                            }
                                                      } else {
                                                                 Write-host "Для пользователя $cnName не существует группы. Создание пользователя прервано." 
                                                             }
                                                      }
                                                      if (($anse -eq "Да") -or ($anse -eq "Д")){
                                                                #Создание пользователя
                                                                $login=$login=transleter(createLogin $cnName )
                                                                $strPass=createPass
                                                                $pass=ConvertTo-SecureString -AsPlainText -Force -String $strPass
                                                                $str=$cnName.split(" ");
                                                                #createUserStudentPM($cnName,$login,$pass,$givenName,$surName,$rusGroup,$ActionDate,$dirPath,$ouPath)
                                                                createUserStudentPM $cnName $login $pass $str[1] $str[0] $rusGroup $dateActive $dirPath $ouPath
                                                           }
                                                    }

    Скрипт запускается, на компьютере введенном в домен с правами администратора домена.

    При работе команды

    $acl.AddAccessRule($rule)

    возникает следующая ошибка: Исключение при вызове "AddAccessRule" с "1" аргументами: "Некоторые или ссылки на свойства нельзя преобразовать.

    Если выдавать права с помощью команды

    cacls $dirPath\$enGroup\$login /e /g ${login}:F
    Возникает ошибка: Сопоставление между именами пользователей и идентификаторами безопасности не было произведено

    Для проверки перед созданием каталога была добавлена команда

    Get-ADUser -Identity $login

    При этом возникает ошибка: get-aduser : Не удается найти объект с удостоверением:

    Сейчас проблема решена добавлением команды

    Start-Sleep -s 5

    перед созданием каталога.

    Вопросы:

    1. Правильно ли я понимаю, что серверу AD необходимо много времени для создания пользователя? Если выставляем параметр ожидания 1-3с. также возникает ошибка "Исключение при вызове "AddAccessRule" с "1" аргументами: "Некоторые или ссылки на свойства нельзя преобразовать.", но реже.
    2. Есть ли возможность решить эту проблему не добавлением пауз?
    3. Почему права на домашний каталог не выдаются следующими строками? Если выполнять туже последовательность через "Active Directory - пользователи и компьютеры" права на домашний каталог назначаются
    New-Item -Path "$dirPath\$enGroup\$login" -ItemType "directory"
    New-ADUser $cnName -SamAccountName $login -UserPrincipalName "$login@ad.ХХХ" -AccountPassword $pass -GivenName $givenName -Surname $surName -AccountExpirationDate $ActionDate -Company "ХХХ" -Department "Группа $rusGroup" -HomeDirectory "$dirPath\$enGroup\$login" -HomeDrive "H:" -path $ouPath






    9 февраля 2017 г. 8:48

Ответы

  • Подозреваю, что у вас там не один контроллер, а несколько.

    Если так, то всё логично: пользователь может создаваться на одном контроллере домена, а поиск его логина для преобразования в SID (в ACL пишутся именно SID) - на другом, куда вновь добавленный пользователь ещё не среплицировался. 5 секунд - это вполне характерное время задержки между уведомлениями об изменении (по крайней мере, в Win2K оно было таким, и, кажется, с тех пор эта часть репликации не менялась).

    Чтобы избежать поиска, можно попробовать передавать в конструктор FileSystemAccessRule сразу SID нового пользователя (то, что записано ниже - это одна строчка):

    $rule=New-Object System.Security.AccessControl.FileSystemAccessRule $login.SID.Value,"FullControl","ContainerInherit,ObjectInherit","None","allow" 


    Слава России!


    • Изменено M.V.V. _ 9 февраля 2017 г. 10:05
    • Помечено в качестве ответа d-maksim 28 февраля 2017 г. 9:27
    9 февраля 2017 г. 10:05
  • 1. Зависит от времени репликации, если выполнять скрипт на опредленном DC или указывать параметр -Server DC, то проблем не должно быть.

    2. Да.

    3. Потому что данный механизм встроен в оснастку DSA.MSC, а не LDAP запросом.

    Выше уже указали про SID, но его неправильно транслировали.

    $user = New-ADUser $cnName -SamAccountName $login -UserPrincipalName "$login@ad.ХХХ" -AccountPassword $pass -GivenName $givenName -Surname $surName -AccountExpirationDate $ActionDate -Company "ХХХ" -Department "Группа $rusGroup" -HomeDirectory "$dirPath\$enGroup\$login" -HomeDrive "H:" -path $ouPath -PassThru

    и уже подставляем:

    $rule=New-Object System.Security.AccessControl.FileSystemAccessRule $user.SID.Value,"FullControl","ContainerInherit,ObjectInherit","None","allow"

    • Помечено в качестве ответа d-maksim 28 февраля 2017 г. 9:27
    10 февраля 2017 г. 10:53
    Отвечающий
  • Мы боролись с такой же проблемой в скрипте создания шар и настройки DFS.

    Действительно корень в том, что при выполнении операций репликация между DC не успевают выполниться.

    Так что можно просто первым шагом создавать пользователей по списку. Потом ждать завершения репликации. Потом назначать права.

    Второй способ (который мы использовали). Выполнять действия не удаленно, а локально на домен-контроллере и файловом сервере (через New-PSSession + Invoke-Command). По крайней мере в одном сайте это работает.


    Сазонов Илья

    https://isazonov.wordpress.com/

    • Помечено в качестве ответа d-maksim 28 февраля 2017 г. 9:26
    13 февраля 2017 г. 3:45
    Модератор

Все ответы

  • Подозреваю, что у вас там не один контроллер, а несколько.

    Если так, то всё логично: пользователь может создаваться на одном контроллере домена, а поиск его логина для преобразования в SID (в ACL пишутся именно SID) - на другом, куда вновь добавленный пользователь ещё не среплицировался. 5 секунд - это вполне характерное время задержки между уведомлениями об изменении (по крайней мере, в Win2K оно было таким, и, кажется, с тех пор эта часть репликации не менялась).

    Чтобы избежать поиска, можно попробовать передавать в конструктор FileSystemAccessRule сразу SID нового пользователя (то, что записано ниже - это одна строчка):

    $rule=New-Object System.Security.AccessControl.FileSystemAccessRule $login.SID.Value,"FullControl","ContainerInherit,ObjectInherit","None","allow" 


    Слава России!


    • Изменено M.V.V. _ 9 февраля 2017 г. 10:05
    • Помечено в качестве ответа d-maksim 28 февраля 2017 г. 9:27
    9 февраля 2017 г. 10:05
  • Здравствуйте. Спасибо за ответ.

    Ваш совет не помог. Выдается ошибка.

    New-Object : Исключение при вызове ".ctor" с "5" аргументами: "Значение не может быть неопределенным.
    Имя параметра: identity"
    .\create_users.ps1:123 знак:19
    +             $rule=New-Object System.Security.AccessControl.FileSystemAccessRule  ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
        + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
    Будем создавать пачку пользователей, делать задержку и только потом выдавать права.

    10 февраля 2017 г. 3:41
  • 1. Зависит от времени репликации, если выполнять скрипт на опредленном DC или указывать параметр -Server DC, то проблем не должно быть.

    2. Да.

    3. Потому что данный механизм встроен в оснастку DSA.MSC, а не LDAP запросом.

    Выше уже указали про SID, но его неправильно транслировали.

    $user = New-ADUser $cnName -SamAccountName $login -UserPrincipalName "$login@ad.ХХХ" -AccountPassword $pass -GivenName $givenName -Surname $surName -AccountExpirationDate $ActionDate -Company "ХХХ" -Department "Группа $rusGroup" -HomeDirectory "$dirPath\$enGroup\$login" -HomeDrive "H:" -path $ouPath -PassThru

    и уже подставляем:

    $rule=New-Object System.Security.AccessControl.FileSystemAccessRule $user.SID.Value,"FullControl","ContainerInherit,ObjectInherit","None","allow"

    • Помечено в качестве ответа d-maksim 28 февраля 2017 г. 9:27
    10 февраля 2017 г. 10:53
    Отвечающий
  • Здравствуйте.

    Изменил как вы сказали, ошибка та же

    New-Object : Исключение при вызове ".ctor" с "5" аргументами: "Значение не может быть неопределенным.
    Имя параметра: identity"
    .\create_users.ps1:121 знак:19
    +             $rule=New-Object System.Security.AccessControl.FileSystemAccessRule  ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
        + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

    Можете  подробнее объяснить по первому пункту. Пробовал добавлять параметр -Server в команду

    $user=New-ADUser $cnName -SamAccountName $login -UserPrincipalName "$login@ХХХ" -AccountPassword $pass -GivenName $givenName -Surname $surName -AccountExpirationDate $ActionDate -Company "ХХХ" -Department "Группа $rusGroup" -HomeDirectory "$dirPath\$enGroup\$login" -HomeDrive "H:" -path $ouPath -Server dc01

    результат тот же.


    13 февраля 2017 г. 1:38
  • Мы боролись с такой же проблемой в скрипте создания шар и настройки DFS.

    Действительно корень в том, что при выполнении операций репликация между DC не успевают выполниться.

    Так что можно просто первым шагом создавать пользователей по списку. Потом ждать завершения репликации. Потом назначать права.

    Второй способ (который мы использовали). Выполнять действия не удаленно, а локально на домен-контроллере и файловом сервере (через New-PSSession + Invoke-Command). По крайней мере в одном сайте это работает.


    Сазонов Илья

    https://isazonov.wordpress.com/

    • Помечено в качестве ответа d-maksim 28 февраля 2017 г. 9:26
    13 февраля 2017 г. 3:45
    Модератор
  • Здравствуйте.

    Изменил как вы сказали, ошибка та же

    New-Object : Исключение при вызове ".ctor" с "5" аргументами: "Значение не может быть неопределенным.
    Имя параметра: identity"
    .\create_users.ps1:121 знак:19
    +             $rule=New-Object System.Security.AccessControl.FileSystemAccessRule  ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
        + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

    Можете  подробнее объяснить по первому пункту. Пробовал добавлять параметр -Server в команду

    $user=New-ADUser $cnName -SamAccountName $login -UserPrincipalName "$login@ХХХ" -AccountPassword $pass -GivenName $givenName -Surname $surName -AccountExpirationDate $ActionDate -Company "ХХХ" -Department "Группа $rusGroup" -HomeDirectory "$dirPath\$enGroup\$login" -HomeDrive "H:" -path $ouPath -Server dc01

    результат тот же.


    Я привел команду с -Passthru, скопируйте правильно и выполните код.
    13 февраля 2017 г. 5:46
    Отвечающий
  • Здравствуйте. Спасибо за ответ.

    Сейчас остановились на первом варианте, который нас устраивает, просто интересно есть  ли другие способы.

    13 февраля 2017 г. 8:10
  • Здравствуйте. Спасибо за ответ.

    Да действительно не заметил параметр -PassThru

    $user = New-ADUser $cnName -SamAccountName $login -UserPrincipalName "$login@ad.ХХХ" -AccountPassword $pass -GivenName $givenName -Surname $surName -AccountExpirationDate $ActionDate -Company "ХХХ" -Department "Группа $rusGroup" -HomeDirectory "$dirPath\$enGroup\$login" -HomeDrive "H:" -path $ouPath -PassThru
    Write-Host "Создан пользователь $cnName"
    Enable-ADAccount "$login" 
    Add-ADGroupMember -Identity "Группа $rusGroup" -Members "$login"
    #Создаем папку
    New-Item -Path "$dirPath\$enGroup\$login" -ItemType "directory"
    #Выдаем права на папку для пользователя на домашнюю папку
    $acl=Get-Acl -Path "$dirPath\$enGroup\$login"
    $rule=New-Object System.Security.AccessControl.FileSystemAccessRule $user.SID.Value,"FullControl","ContainerInherit,ObjectInherit","None","allow"
    $acl.AddAccessRule($rule)
    но с ним также не работает, вернулась самая первая ошибка
    Исключение при вызове "AddAccessRule" с "1" аргументами: "Некоторые или ссылки на свойства нельзя преобразовать."
    .\create_users.ps1:122 знак:13
    +             $acl.AddAccessRule($rule)
    +             ~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : IdentityNotMappedException



    13 февраля 2017 г. 8:28
  • Попробуйте:

    $Server = [DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().FindDomainController().Name
    
    $user = New-ADUser $cnName -SamAccountName $login -UserPrincipalName "$login@ad.ХХХ" -AccountPassword $pass -GivenName $givenName -Surname $surName -AccountExpirationDate $ActionDate -Company "ХХХ" -Department "Группа $rusGroup" -HomeDirectory "$dirPath\$enGroup\$login" -HomeDrive "H:" -path $ouPath -Server $Server -PassThru
    Write-Host "Создан пользователь $cnName"
    Enable-ADAccount "$login" -Server $Server
    Add-ADGroupMember -Identity "Группа $rusGroup" -Members "$login" -Server $Server
    #Создаем папку
    New-Item -Path "$dirPath\$enGroup\$login" -ItemType "directory"
    #Выдаем права на папку для пользователя на домашнюю папку
    $acl=Get-Acl -Path "$dirPath\$enGroup\$login"
    $rule=New-Object System.Security.AccessControl.FileSystemAccessRule $user.SID.Value,"FullControl","ContainerInherit,ObjectInherit","None","allow"
    $acl.AddAccessRule($rule)

    13 февраля 2017 г. 8:58
    Отвечающий
  • Здравствуйте.

    Нет, к сожалению тоже не помогло. Та же ошибка

    Исключение при вызове "AddAccessRule" с "1" аргументами: "Некоторые или ссылки на свойства нельзя преобразовать."
    .\create_users.ps1:123 знак:13
    +             $acl.AddAccessRule($rule)
    +             ~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : IdentityNotMappedException

    13 февраля 2017 г. 9:45