Foreach в foreach (вложенный) - PullRequest
       0

Foreach в foreach (вложенный)

0 голосов
/ 01 марта 2019

Я пытаюсь перебрать всех отключенных пользователей через массив групп, чтобы проверить, есть ли пользователи в какой-либо из перечисленных групп.Я думаю, что для каждого пользователя в списке прокрутите их и проверьте, присутствуют ли они в одной из перечисленных групп.Это потребует вложенных циклов foreach, верно?Вывод, который я получаю, выглядит следующим образом:

...
user1
user2
user3

is not a member of group1

Вот исходный код:

$dUsers = Get-ADUser -Filter {enabled -eq $false} |
          FT samAccountName |
          Out-String
$groups = 'Group1', 'Group2'

foreach ($dUser in $dUsers) {
    foreach ($group in $groups) {
        $members = Get-ADGroupMember -Identity $group -Recursive |
                   Select -ExpandProperty SamAccountName

        if ($members -contains $dUsers) {
            Write-Host "[+] $dUser is a member of $group"
        } else {
            Write-Host "[-] $dUser is not a member of $group"
        }
    }
}

Я дергаю себя за волосы, потому что чувствую, что есть простое решение, но яЯ потерян.


Обновление:

Я хотел поместить всех отключенных пользователей в переменную $dUsers.Это на самом деле работает, если я вручную помещаю пользователей в переменную, как это:

$dUsers = 'user1','user2','user3'

, что дает мне следующий вывод:

user1 is not a member of group1
user1 is not a member of group2
user2 is not a member of group1
user2 is not a member of group2
...

Это заставляет меня задаться вопросом, как это "проповедуется", когдапеременная:

$dUsers = Get-ADUser -Filter {enabled -eq $false} |
          FT samAccountName |
          Out-String

Кто-нибудь получил разъяснение по этому поводу?


Обновление:

Это окончательный код.Запуск занимает много времени, даже с двумя группами.

$dUsers = Get-ADUser -Filter {enabled -eq $false} | Select-Object -Expand SamAccountName
$groups = 'Group1', 'Group2'


Write-host '[+] Checking if any disabled user is member of any SSL groups'
Write-host '[+] This might take a while. Get a coffee!'
write-host '[+] Running...'`n
foreach ($dUser in $dUsers) {
    foreach ($group in $groups) {
        $members = Get-ADGroupMember -Identity $group -Recursive | Select -ExpandProperty SamAccountName

        if($members -contains $dUser) {
            Write-Host "$dUser is a member of $group"
        } Else {
         # Remove or comment out the line below to get a clutterfree list.
         # Write-Host "$dUser is not a member of $group"
        }
    }
}

Ответы [ 4 ]

0 голосов
/ 02 марта 2019

В вашем коде есть две проблемы:

  1. Вы создаете одну строку из вывода Get-ADUser.Передача выходных данных этого командлета через Format-Table (псевдоним ft), а затем Out-String создает одну строку с табличным отображением всех соответствующих имен учетных записей, включая заголовок таблицы.

    Если вы выводите $dUsersтаким образом, чтобы сделать начало и конец строки видимым, вы увидите что-то вроде этого (начальный и конечный ==, помечающий начало и конец):

    PS> $dUsers | ForEach-Object { "==$_==" }
    ==samAccountName
    --------------
    user1
    user2
    user3==
    

    Поскольку нет учетной записи симя пользователя, совпадающее с этой строкой. Ни в одной группе не найдено совпадений, и вы получаете результат, который вы наблюдали.

    Такое неправильное использование командлетов Format-* является распространенной ошибкой новичка.Люди получают красиво отформатированный вывод строки, а затем пытаются работать с этим.ТОЛЬКО используйте командлеты Format-*, когда вы представляете данные непосредственно пользователю, НИКОГДА, когда требуется или предполагается дальнейшая обработка данных.

    То, что вы на самом деле хотите, - это не строка с табличным отображением имен пользователей,но массив строк имени пользователя.Вы получаете это, расширяя свойство SamAccountName пользовательских объектов, которые вы получаете от Get-ADUser.

    $dUsers = Get-ADUser ... | Select-Object -Expand SamAccountName
    
  2. Вторая проблема, вероятно, является просто опечаткой.Ваше условие $members -contains $dUsers не будет работать, так как $members и $dUsers являются массивами (то есть после устранения первой проблемы).Оператор -contains ожидает массив в качестве первого операнда и одно значение в качестве второго операнда.

    Измените

    $members -contains $dUsers
    

    на

    $members -contains $dUser
    
0 голосов
/ 01 марта 2019

В зависимости от используемой версии PowerShell, существует командлет для этого варианта использования и других.

Что касается

Я пытаюсь зациклить всех отключенных пользователей

Просто выполните ...

Search-ADAccount -AccountDisabled | 
Select-Object -Property Name, Enabled,
@{Name = 'GroupName';Expression = {$_.DistinguishedName.Split(',')[1] -replace 'CN='}} 

# Results 

Name               Enabled GroupName                                              
----               ------- ---------                                              
...                                         
testuser2 NewTest    False Users                                                  
Guest                False Users

Или другой командлет ...

# Get disabled users and their group membership, display user and group name
ForEach ($TargetUser in (Get-ADUser -Filter {Enabled -eq $false}))
 {
 "`n" + "-"*12 + " Showing group membership for " + $TargetUser.SamAccountName
 Get-ADPrincipalGroupMembership -Identity $TargetUser.SamAccountName | Select Name
 }


# Results
...
------------ Showing group membership for testuser1
Domain Users
Users

------------ Showing group membership for testuser2
Domain Users

Что касается ...

anмассив групп

Просто выберите или отфильтруйте DN для нужного имени группы, используя обычные операторы сравнения.

Что касается ...

К сожалению, я не очень хорошо разбираюсь в powershell.

… не забудьте потратить необходимое время, чтобы его освоить, ограничить количество заблуждений, недоразумений, ошибок и т. Д.собираюсь встретиться.Существует множество бесплатных / бесплатных видео и текстовых тренингов / презентаций по всему Интернету.

Пример: Видео

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

Пошаговое руководство: использование средства просмотра истории PowerShell в Windows Server 2012 R2

Изучение PowerShell с помощью Active DirectoryЦентр администрирования (PowerShell History Viewer)

, а также множество примеров сценариев и модулей через MS PowerShell Script / Module Gallery.

0 голосов
/ 01 марта 2019

Первое, что вы должны проверить, это когда вас интересуют только прямое или косвенное членство.В зависимости от ответа опции, которые вы получили, могут немного измениться.Вы, вероятно, столкнетесь с отличительными именами , работая над этим, поэтому проверьте, что они из себя представляют, если не знаете (в основном это путь к объекту).

Если это только прямое членство с использованием memberOf с Get-ADUser должно быть достаточно.Атрибут memberOf содержит каждое непосредственное членство в группе пользователя с полным отличительным именем группы.

Get-ADUser test -Properties MemberOf | Select-Object -ExpandProperty memberOf

Вы можете сопоставлять группы, которые вы ищете, различными способами.Вы можете получить полное отличительное имя этих групп или сделать частичное совпадение.Вам решать, как действовать дальше.

Если вам нужны также косвенные членства, возможно, вы захотите разделить свой код, чтобы сделать его проще для себя.Например, вы можете сначала найти пользователей и сохранить их.Затем найдите всех членов группы этих групп (вы уже получили это с помощью Get-ADGroupMember) и, наконец, сравните их.

В настоящее время для каждого пользователя вы снова строите полный список членов группы.Этот подход позволит сэкономить несколько ресурсов, так как вы не будете делать одни и те же запросы снова и снова.

Наконец, вы также можете использовать подход MemberOf, но получить список всех прямых и косвенных членовпользователь использует запрос LDAP.

$dn = (Get-ADUser example).DistinguishedName
$userGroups = Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn)

При таком подходе используется запрос поиска LDAP .Это может быть довольно сложно, вы также можете проверить только одну из групп, немного ее изменив.

В конце концов, ваш текущий подход должен работать.Проблема в том, что вы сравниваете объект AD со списком имен учетных записей SAM.Вам также необходимо проверить имена учетных записей SAM.

if($members -contains $dUsers.SamAccountName)
if($members -contains $dUsers | Select-Object -ExpandProperty SamAccountName)

Один из них должен работать, если вы также измените свой $dUsers.Как это в настоящее время вы в конечном итоге с гигантской струной.Вы, вероятно, можете проверить это, проверив $dUsers.length.Просто бросьте Format-Table и Out-String.

0 голосов
/ 01 марта 2019

Для групп AD есть две команды.Сначала я вижу, что вы хотите, чтобы членство отключенных пользователей было простым.

#Get the dissabled users from your AD with all their attributes (properties and select)
$dUsers = Get-ADUser -Filter {Enabled -eq $false} -Properties * | Select *
#Run a loop for each user to get the group membership
Foreach ($User in $dUsers) {
$User = $User.SamAccountName
Get-ADUser $User -Properties * | Select Name, SamAccountName, MemberOf | Format-Table -Wrap # > "D:\test\$user.txt" -HideTableHeaders
}

Это может работать, но мне не нравится вывод, который мы получаем.Я предпочитаю запускать команду groupmembership и проверять пользователей.

$GroupMembers = Get-ADGroupMember "groupname"| Select Name, SamAccountName
ForEach ($User in $GroupMembers)
{ 
$UserProperties = Get-ADUser $User.SamAccountName -Properties * | select *
If ($UserProperties.Enabled -eq $False) {
Write-Host $UserProperties.SamAccountName
}
}

Редактировать:

Дайте мне знать, подходит ли вам это.С уважением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...