Автор Тема: Перенос неактивных УЗ AD через PoSh  (Прочитано 5698 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Wizard

  • Начинающий
  • *
  • Сообщений: 35
  • Рейтинг: 0
  • Пол: Мужской
    • Просмотр профиля
  • Откуда: Санкт-Петербург
Перенос неактивных УЗ AD через PoSh
« : 20 октября 2016, 17:09:11 »
Доброго времени суток!

Прошу у вас помощи по PowerShell:
передо мной стоит задача найти неиспользуемые УЗ AD и перенести их в специальный контейнер (а в дальнейшем заблокировать их),
для этого я взял за основу скрипт из этой статьи: http://shserg.ru/posts/search-old-computer-user-accounts-in-ad/
и немного его доработал:

$InactiveDays = New-TimeSpan -days 120
$CreatedDays = New-TimeSpan -Days 30
$CreatedPass = (Get-Date) - $CreatedDays
$LastLogonTimeMark = (get-date) – $InactiveDays
$users=Get-ADuser -searchbase "cn=users, DC=gpma, DC=local" -Filter {(enabled -eq "true") -and (whencreated -lt $CreatedPass)-and (name -like "*")} -Properties lastLogontimeStamp,whenCreated, enabled |`
Where-Object {[DateTime]::FromFileTime($_.lastLogonTimestamp) -lt $LastLogonTimeMark}|`
select Name, @{Name=”LastLogon”;Expression={[datetime]::FromFileTime($_.lastLogontimeStamp)}}, whenCreated, enabled|`
sort LastLogon| ft Name,LastLogon, whenCreated,enabled –AutoSize
$count=$users.Count
$users
$users | Out-File $folder\inactiveusers.txt
Write-Host "всего $count пользователей не входило в УЗ за последние $InactiveDays дней"
$users | foreach -process (Move-ADObject -identity  -TargetPath "OU=inactive users, DC=gpma, DC=local")

Что касается поиска и вывода неактивных УЗ, вроде все работает корректно, но перенести их мне никак не удается. :dash:
Очевидно недоработка в последней строке, в частности неясно что должно быть в параметре identity. Также меня смущает что переменная $users вроде бы массив, но её отдельные элементы не выводятся:

PS C:\Users\admin_svv> $users[0]


PS C:\Users\admin_svv> $users[1]
out-lineoutput : Object reference not set to an instance of an object.
    + CategoryInfo          : NotSpecified: (:) [out-lineoutput], NullReferenceException
    + FullyQualifiedErrorId : System.NullReferenceException,Microsoft.PowerShell.Commands.OutLineOutputCommand

Пробовал последнюю строчку кода заменить на
$users | Move-ADObject  -TargetPath "OU=inactive users, DC=gpma, DC=local"

получил кучу ошибок:
Move-ADObject : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and i
ts properties do not match any of the parameters that take pipeline input.
At line:13 char:10
+ $users | Move-ADObject  -TargetPath "OU=inactive users, DC=gpma, DC=l ...

Онлайн Retif

  • Администраторы
  • Олдфаг
  • *****
  • Сообщений: 9059
  • Рейтинг: 88
  • Пол: Мужской
  • Афтар
    • Просмотр профиля
    • Мой блог
  • Откуда: Орёл
Перенос неактивных УЗ AD через PoSh
« Ответ #1 : 20 октября 2016, 17:32:36 »
в частности неясно что должно быть в параметре identity
А читать про командлет Move-ADObject вы не пробовали? Там, собственно, должна быть переменная, которая обозначает перемещаемый объект (вашего пользователя).

Оффлайн shs

  • Модератор
  • Ветеран
  • *****
  • Сообщений: 4401
  • Рейтинг: 89
    • Просмотр профиля
    • ShS's blog
  • Откуда: Default city
Перенос неактивных УЗ AD через PoSh
« Ответ #2 : 20 октября 2016, 17:46:22 »
А читать про командлет Move-ADObject вы не пробовали?
надо сначала разобраться с содержимым $users, оно у автора пустое, а мувить пустоту не будет ни один командлет


Updated: 20 October 2016, 17:54:46

выполните, посмотрите на результат
$CreatedDays = New-TimeSpan -Days 30
$CreatedPass = (Get-Date) - $CreatedDays
Get-ADuser -searchbase "cn=users, DC=gpma, DC=local" -Filter {(enabled -eq "true") -and (whencreated -lt $CreatedPass)-and (name -like "*")} -Properties lastLogontimeStamp,whenCreated, enabled


Updated: 20 October 2016, 17:59:08

вот эта часть условия фильтра
Цитировать
-and (name -like "*")
бессмысленна, ибо всегда будет всегда истинна
« Последнее редактирование: 20 октября 2016, 18:05:06 от shs »

Оффлайн Wizard

  • Начинающий
  • *
  • Сообщений: 35
  • Рейтинг: 0
  • Пол: Мужской
    • Просмотр профиля
  • Откуда: Санкт-Петербург
Перенос неактивных УЗ AD через PoSh
« Ответ #3 : 22 октября 2016, 18:47:19 »
выполните, посмотрите на результат
выполнить смогу во вторник, но думаю отработает верно.
надо сначала разобраться с содержимым $users, оно у автора пустое
оно не пустое, я такого не говорил. не выдает отдельные элементы массива (или это не массив?). всё содержимое разом выдается.
вот эта часть условия фильтра
бессмысленна, ибо всегда будет всегда истинна
Я это понимаю, добавлял это когда хотел добавить в условие поиска имя, в итоге сделал так, чтобы если что быстро можно было бы воспользоваться.

Оффлайн shs

  • Модератор
  • Ветеран
  • *****
  • Сообщений: 4401
  • Рейтинг: 89
    • Просмотр профиля
    • ShS's blog
  • Откуда: Default city
Перенос неактивных УЗ AD через PoSh
« Ответ #4 : 24 октября 2016, 12:47:27 »
оно не пустое, я такого не говорил. не выдает отдельные элементы массива (или это не массив?). всё содержимое разом выдается.
покажите результат работы
,$users|gm

обратите внимание, там вначале запятая, она обязательна


Updated: 24 October 2016, 12:53:12

для того, чтобы гарантированно получить на выходе массив, нужно использовать такую конструкцию @(Get-ADuser ...)

если вы хотите что-либо делать с данными, которые получаете при помощи конвейера, то в конце оно конвейера не ставьте оператор FT ...  Его используют для форматирования перед выводом на экран.
« Последнее редактирование: 24 октября 2016, 12:54:44 от shs »

Оффлайн Wizard

  • Начинающий
  • *
  • Сообщений: 35
  • Рейтинг: 0
  • Пол: Мужской
    • Просмотр профиля
  • Откуда: Санкт-Петербург
Перенос неактивных УЗ AD через PoSh
« Ответ #5 : 25 октября 2016, 09:22:34 »
покажите результат работы
PS C:\Users\admin_svv> , $users | gm


   TypeName: System.Object[]

Name           MemberType            Definition                                                                                                             
----           ----------            ----------                                                                                                             
Count          AliasProperty         Count = Length                                                                                                         
Add            Method                int IList.Add(System.Object value)                                                                                     
Address        Method                System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Address(int )               
Clear          Method                void IList.Clear()                                                                                                     
Clone          Method                System.Object Clone(), System.Object ICloneable.Clone()                                                                 
CompareTo      Method                int IStructuralComparable.CompareTo(System.Object other, System.Collections.IComparer comparer)                         
Contains       Method                bool IList.Contains(System.Object value)                                                                               
CopyTo         Method                void CopyTo(array array, int index), void CopyTo(array array, long index), void ICollection.CopyTo(array array, int i...
Equals         Method                bool Equals(System.Object obj), bool IStructuralEquatable.Equals(System.Object other, System.Collections.IEqualityCom...
Get            Method                System.Object Get(int )                                                                                                 
GetEnumerator  Method                System.Collections.IEnumerator GetEnumerator(), System.Collections.IEnumerator IEnumerable.GetEnumerator()             
GetHashCode    Method                int GetHashCode(), int IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer)                 
GetLength      Method                int GetLength(int dimension)                                                                                           
GetLongLength  Method                long GetLongLength(int dimension)                                                                                       
GetLowerBound  Method                int GetLowerBound(int dimension)                                                                                       
GetType        Method                type GetType()                                                                                                         
GetUpperBound  Method                int GetUpperBound(int dimension)                                                                                       
GetValue       Method                System.Object GetValue(Params int[] indices), System.Object GetValue(int index), System.Object GetValue(int index1, i...
IndexOf        Method                int IList.IndexOf(System.Object value)                                                                                 
Initialize     Method                void Initialize()                                                                                                       
Insert         Method                void IList.Insert(int index, System.Object value)                                                                       
Remove         Method                void IList.Remove(System.Object value)                                                                                 
RemoveAt       Method                void IList.RemoveAt(int index)                                                                                         
Set            Method                void Set(int , System.Object )                                                                                         
SetValue       Method                void SetValue(System.Object value, int index), void SetValue(System.Object value, int index1, int index2), void SetVa...
ToString       Method                string ToString()                                                                                                       
Item           ParameterizedProperty System.Object IList.Item(int index) {get;set;}                                                                         
IsFixedSize    Property              bool IsFixedSize {get;}                                                                                                 
IsReadOnly     Property              bool IsReadOnly {get;}                                                                                                 
IsSynchronized Property              bool IsSynchronized {get;}                                                                                             
Length         Property              int Length {get;}                                                                                                       
LongLength     Property              long LongLength {get;}                                                                                                 
Rank           Property              int Rank {get;}                                                                                                         
SyncRoot       Property              System.Object SyncRoot {get;}

если вы хотите что-либо делать с данными, которые получаете при помощи конвейера, то в конце оно конвейера не ставьте оператор FT
Просто в ходе выполнения скрипта я вывожу эти данные на экран и пишу в файл.

Всё-таки, как правильно составить последнюю строку:
$users | Move-ADObject  -TargetPath "OU=inactive users, DC=gpma, DC=local"
что должно быть после Move-ADObject?

Оффлайн Fray

  • Администратор
  • Олдфаг
  • *****
  • Сообщений: 6668
  • Рейтинг: 58
  • Пол: Мужской
    • Просмотр профиля
    • IT-Бложек
  • Откуда: Петербург
Перенос неактивных УЗ AD через PoSh
« Ответ #6 : 25 октября 2016, 09:30:46 »
что должно быть после Move-ADObject?
-Identity $._Name или какой атрибут пользователя вы на выходе получаете?

Или я не прав? :)
MCSE: Messaging, MCSE: Communication, MCSE: Productivity, MCSA: Office 365, MCPS
my blog - http://it-blojek.ru

Оффлайн shs

  • Модератор
  • Ветеран
  • *****
  • Сообщений: 4401
  • Рейтинг: 89
    • Просмотр профиля
    • ShS's blog
  • Откуда: Default city
Перенос неактивных УЗ AD через PoSh
« Ответ #7 : 25 октября 2016, 09:56:11 »
System.Object[]
Значит $users у вас - массив

Просто в ходе выполнения скрипта я вывожу эти данные на экран и пишу в файл.
это можно делать разными способами. Но, если вы используете ft (Format table)  в конце конвейера, то в переменную $users попадут уже преобразованные объекты, тип данных которых будет отличаться от типа данных, полученных вами от командлета Get-ADuser, а, значит, другие командлеты, предназначенные для работы с объектами данных AD, не будут знать как им с этими объектами работать.

Оффлайн Wizard

  • Начинающий
  • *
  • Сообщений: 35
  • Рейтинг: 0
  • Пол: Мужской
    • Просмотр профиля
  • Откуда: Санкт-Петербург
Перенос неактивных УЗ AD через PoSh
« Ответ #8 : 25 октября 2016, 14:48:46 »
Закоментил часть скрипта с выводом, и, действительно $users теперь нормальный массив:
PS C:\Users\admin_svv> $users[0]

Name        LastLogon          whenCreated         enabled
----        ---------          -----------         -------
SQLDebugger 01.01.1601 3:00:00 14.02.2013 15:57:20    True



PS C:\Users\admin_svv> $users[1]

Name LastLogon          whenCreated         enabled
---- ---------          -----------         -------
rus2 01.01.1601 3:00:00 30.04.2008 13:11:38    True



PS C:\Users\admin_svv> $users[2]

Name    LastLogon           whenCreated         enabled
----    ---------           -----------         -------
oftalm1 03.06.2014 10:00:36 27.11.2008 17:01:53    True

Думаю теперь осталось, правильно написать последнюю строку с самим переносом.
Попробовал так:
$InactiveDays = New-TimeSpan -days 120
$CreatedDays = New-TimeSpan -Days 30
$CreatedPass = (Get-Date) - $CreatedDays
$LastLogonTimeMark = (get-date) – $InactiveDays
$users=Get-ADuser -searchbase "cn=users, DC=gpma, DC=local" -Filter {(enabled -eq "true") -and (whencreated -lt $CreatedPass)-and (name -like "*")} -Properties lastLogontimeStamp,whenCreated, enabled |`
Where-Object {[DateTime]::FromFileTime($_.lastLogonTimestamp) -lt $LastLogonTimeMark}|`
select Name, @{Name=”LastLogon”;Expression={[datetime]::FromFileTime($_.lastLogontimeStamp)}}, whenCreated, enabled
<#
sort LastLogon | ft Name,LastLogon, whenCreated,enabled –AutoSize
$count=$users.Count
$users
$users | Out-File $folder\inactiveusers.txt
Write-Host "всего $count пользователей не входило в УЗ за последние $InactiveDays дней"
#>
$users | Move-ADObject -Identity $._Name -TargetPath "OU=inactiveusers, DC=gpma, DC=local"

Получаю ошибки по каждому объекту:
Move-ADObject : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and i
ts properties do not match any of the parameters that take pipeline input.
At line:15 char:10
+ $users | Move-ADObject -Identity $._Name -TargetPath "OU=inactiveuser ...
+          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (@{Name=rhevm; L...; enabled=True}:PSObject) [Move-ADObject], ParameterBindingException
    + FullyQualifiedErrorId : InputObjectNotBound,Microsoft.ActiveDirectory.Management.Commands.MoveADObject

Может там нужен командлет foreach? Если да, как его правильно применить?

Оффлайн shs

  • Модератор
  • Ветеран
  • *****
  • Сообщений: 4401
  • Рейтинг: 89
    • Просмотр профиля
    • ShS's blog
  • Откуда: Default city
Перенос неактивных УЗ AD через PoSh
« Ответ #9 : 25 октября 2016, 15:13:20 »
$users | Move-ADObject -Identity $._Name -TargetPath "OU=inactiveusers, DC=gpma, DC=local"
ну, надо же перебрать всех пользователей в массиве. Это можно сделать в цикле, например:
$users | %{Move-ADObject -Identity $_.Name -TargetPath "OU=inactiveusers,DC=gpma,DC=local"}


Updated: 25 October 2016, 15:14:32

$._Name
здесь тоже ошибка

Онлайн Retif

  • Администраторы
  • Олдфаг
  • *****
  • Сообщений: 9059
  • Рейтинг: 88
  • Пол: Мужской
  • Афтар
    • Просмотр профиля
    • Мой блог
  • Откуда: Орёл
Перенос неактивных УЗ AD через PoSh
« Ответ #10 : 25 октября 2016, 15:19:36 »
Off-Topic:
$users | %{Move-ADObject -Identity $_.Name -TargetPath "OU=inactiveusers,DC=gpma,DC=local"}
Э-эээ... можно объяснить, что это за запись цикла такая? Или нормально его написать, не в одну строку, чтоб понятно было?

Оффлайн Fray

  • Администратор
  • Олдфаг
  • *****
  • Сообщений: 6668
  • Рейтинг: 58
  • Пол: Мужской
    • Просмотр профиля
    • IT-Бложек
  • Откуда: Петербург
Перенос неактивных УЗ AD через PoSh
« Ответ #11 : 25 октября 2016, 15:21:27 »
здесь тоже ошибка
Ну да, $_. :)
MCSE: Messaging, MCSE: Communication, MCSE: Productivity, MCSA: Office 365, MCPS
my blog - http://it-blojek.ru

Оффлайн shs

  • Модератор
  • Ветеран
  • *****
  • Сообщений: 4401
  • Рейтинг: 89
    • Просмотр профиля
    • ShS's blog
  • Откуда: Default city
Перенос неактивных УЗ AD через PoSh
« Ответ #12 : 25 октября 2016, 16:58:45 »
Off-Topic:
$users | %{Move-ADObject -Identity $_.Name -TargetPath "OU=inactiveusers,DC=gpma,DC=local"}
Э-эээ... можно объяснить, что это за запись цикла такая? Или нормально его написать, не в одну строку, чтоб понятно было?
https://xaegr.wordpress.com/2008/09/26/things-2/

Get-Alias %
« Последнее редактирование: 25 октября 2016, 17:06:34 от shs »

Оффлайн Wizard

  • Начинающий
  • *
  • Сообщений: 35
  • Рейтинг: 0
  • Пол: Мужской
    • Просмотр профиля
  • Откуда: Санкт-Петербург
Перенос неактивных УЗ AD через PoSh
« Ответ #13 : 26 октября 2016, 16:07:35 »
Ох, прогресс наблюдается, но до конца так и не работает... %)

Переделал последнюю строку на
$users | %{Move-ADObject -Identity $_.Name -TargetPath "OU=inactiveusers,DC=gpma,DC=local"}

Получил ошибки по каждому пользователю:
Move-ADObject : Не удается найти объект с удостоверением: "kfre1" в "DC=gpma,DC=local".
At line:15 char:12
+ $users | %{Move-ADObject -Identity $_.Name -TargetPath "OU=inactiveus ...
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (kfre1:ADObject) [Move-ADObject], ADIdentityNotFoundException
    + FullyQualifiedErrorId : Не удается найти объект с удостоверением: "kfre1" в "DC=gpma,DC=local".,Microsoft.ActiveDirectory.Management.Commands.MoveADOb
   ject

Из них видно, что теперь имя выбирается корректно, но найти в АД эти УЗ PoSH не может.
После нехитрых манипуляций я понял, что в параметре identity необходимо указывать объект поиска, например:
Move-ADObject -Identity "cn=имя_пользователя, cn=users, DC=gpma, DC=local" -TargetPath "OU=inactiveusers,DC=gpma,DC=local"
но если в данную конструкцию добавить переменную $_.Name, выдается ошибка:
$users | %{Move-ADObject  -Identity "cn=$_.Name, cn=users, DC=gpma, DC=local"  -TargetPath "OU=inactiveusers,DC=gpma,DC=local"}
Move-ADObject : Не удается найти объект с удостоверением: "cn=@{Name=1ho6; LastLogon=06/10/2015 11:21:26; whenCreated=11/23/2012 11:50:37; enabled=True}.Name
, cn=users, DC=gpma, DC=local" в "DC=gpma,DC=local".
At line:15 char:12
+ $users | %{Move-ADObject  -Identity "cn=$_.Name, cn=users, DC=gpma, D ...
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (cn=@{Name=1ho6;...=gpma, DC=local:ADObject) [Move-ADObject], ADIdentityNotFoundException
    + FullyQualifiedErrorId : Не удается найти объект с удостоверением: "cn=@{Name=1ho6; LastLogon=06/10/2015 11:21:26; whenCreated=11/23/2012 11:50:37; ena
   bled=True}.Name, cn=users, DC=gpma, DC=local" в "DC=gpma,DC=local".,Microsoft.ActiveDirectory.Management.Commands.MoveADObject

Пробовал по-разному экспериментировать с данной конструкцией, но ничего толкового не вышло  :dash:


Оффлайн shs

  • Модератор
  • Ветеран
  • *****
  • Сообщений: 4401
  • Рейтинг: 89
    • Просмотр профиля
    • ShS's blog
  • Откуда: Default city
Перенос неактивных УЗ AD через PoSh
« Ответ #14 : 26 октября 2016, 16:16:21 »
"cn=$_.Name, cn=users, DC=gpma, DC=local"
Смотрите, что у вас получилось: внутри двойных кавычек сначала была разименована переменная $_ (вместо нее в строку было добавлено ее содержимое), а потом уже к этому содержимому прилепилось ".Name". Вам же надо, чтобы сначала вычислилось значение $_.Name, и лишь затем это значение было бы добавлено в строку. Для этого используют такую конструкцию внутри строки: $(). т.е. вам надо написать так:
"cn=$($_.Name), cn=users, DC=gpma, DC=local"



Updated: 26 October 2016, 16:19:32

Но на самом деле у объекта User есть уже нужный вам атрибут (DistinguishedName), и не надо снова заниматься его вычислением.