Мне было скучно, и мне было любопытно, как я справлюсь с этим, поэтому я продолжил и смоделировал ваш файл (и добавил немного к нему, чтобы быть уверенным, что я получу последовательные группы в одном пакете, пока естьлюбые подключенные пользователи):
$FileIn = @'
ColA,ColB
S1,User1
S1,User2
S1,User3
S2,User1
S2,User4
S3,User3
User1,S3
S4,User5
S4,User6
S5,User5
User6,S5
S6,User4
S6,User7
S7,User7
S7,User8
'@ -split '[\r\n]+'|convertfrom-csv
Затем выяснил, как отсортировать его по пакетам, убедившись, что я зациклился достаточно, чтобы подключить любую подключенную группу пользователей к одному пакету.
$AccessTo = @{}
$FileIn|Group ColA|%{$AccessTo.add($_.Name,$_.Group.ColB)}
$i=1
ForEach($Box in $AccessTo.Keys){
ForEach($User in $AccessTo[$Box]){
If(($FileIn.ColB|?{$_ -eq $User}|Select -First 1).Batch){Continue}
$BatchUsers = $AccessTo.Keys|?{$AccessTo[$_] -contains $User -or $_ -eq $User}|%{$AccessTo[$_]}|Select -Unique
Do{For($x=0;$x -lt $BatchUsers.Count;$x++){$AccessTo.Keys|?{$AccessTo[$_] -contains $BatchUsers[$x]}|%{$AccessTo[$_]}|?{$_ -notin $BatchUsers}|%{$BatchUsers+=$_}}}Until($x -eq $BatchUsers.count)
$FileIn | ?{$_.ColB -in $BatchUsers -and !$_.Batch}|%{Add-Member -InputObject $_ -NotePropertyName 'Batch' -NotePropertyValue $i}
}
$i=($FileIn.batch|sort|select -last 1)+1
}
В конце я получаю:
PS C:\Users\TMTech> $FileIn
ColA ColB Batch
---- ---- -----
S1 User1 1
S1 User2 1
S1 User3 1
S2 User1 1
S2 User4 1
S3 User3 1
User1 S3 1
S4 User5 2
S4 User6 2
S5 User5 2
User6 S5 2
S6 User4 1
S6 User7 1
S7 User7 1
S7 User8 1
Редактировать: Хорошо, была запрошена разбивка кода, так что поехали.Обратите внимание, что я использую некоторые псевдонимы, в основном: ?{...}
- это сокращение от Where{...}
, а %{...}
- это сокращение ForEach-Object{...}
.
Я начинаю с того, что получаю данные в PowerShell и сохраняю их впеременная с именем $FileIn
.Вы будете импортировать CSV, поэтому я просто буду двигаться дальше.Затем я создаю пустую хеш-таблицу.
$AccessTo = @{}
Затем я беру импортированные данные, группирую их по значению в ColA и для каждой группировки добавляю элемент в хеш-таблицу, где значение в ColAявляется ключом, а значение является массивом строк из ColB.Например, первый элемент в хеш-таблице имеет ключ S1
и значение User1
, User2
, User3
.Подобный элемент существует для каждого уникального значения в ColA.
После того, как у меня есть почтовые ящики и пользователи, которые имеют доступ к этим почтовым ящикам, организованы и сгруппированы, я перехожу к попытке их пакетировать.Я начинаю с Пакета 1, поэтому я устанавливаю переменную для этого.
$i=1
Далее я перебираю каждый $Box
(т.е. каждый ключ в хеш-таблице).Это внешний цикл, который я назову циклом почтового ящика.
ForEach($Box in $AccessTo.Keys){
В цикле почтового ящика у меня есть внутренний цикл, который проходит через каждый $User
, связанный с этим почтовым ящиком.Я назову это пользовательским циклом.
ForEach($User in $AccessTo[$Box]){
При повторном использовании данных примера первый почтовый ящик - S1
, а связанные с ним пользователи - User1
, User2
и User3
.Поэтому во внутреннем цикле я начинаю с проверки, назначен ли ему текущий пользователь.Если они это сделают, я continue
для следующего пользователя.
If(($FileIn.ColB|?{$_ -eq $User}|Select -First 1).Batch){Continue}
Затем я смотрю на каждый элемент в хеш-таблице, и если текущий $User
находится в списке пользователей для любого данного почтового ящика IВывести всех пользователей для этого почтового ящика.Это передается в команду Select
, которая получает только уникальные значения и записывается в $BatchUsers
.
$BatchUsers = $AccessTo.Keys|?{$AccessTo[$_] -contains $User -or $_ -eq $User}|%{$AccessTo[$_]}|Select -Unique
На данный момент у нас есть хорошая база пользователей, которые входят в пакет.Теперь мне просто нужно убедиться, что эти пользователи не входят в другие группы, в которые не входит текущий $User
, и если они есть, мне нужно итерировать пользователей из этих дополнительных групп, и я должен продолжать делать этопока я не перестану получать больше пользователей.Я разберем это с форматированием, которое немного легче читать:
Do{
For($x=0;$x -lt $BatchUsers.Count;$x++){
$AccessTo.Keys|
?{$AccessTo[$_] -contains $BatchUsers[$x]}|
%{$AccessTo[$_]}|
?{$_ -notin $BatchUsers}|
%{$BatchUsers+=$_}
}
}Until($x -eq $BatchUsers.count)
Я начинаю с цикла Do
/ Until
, который будет работать сам до тех пор, пока $BatchUsers.Count
не будет равно числу пользователей, которыемы рассмотрели последнюю итерацию цикла (поэтому она циклическая, пока не найдет дополнительных пользователей).Внутри этого цикла я запускаю цикл For
, который начинается с $x=0
и продолжается до тех пор, пока $x
не станет равным текущему значению $BatchUsers.Count
.Я указываю «текущее значение», потому что мы добавляем вещи в $BatchUsers
внутри цикла.
Для каждой итерации цикла мы снова смотрим на все элементы в хеш-таблице $AccessTo
For($x=0;$x -lt $BatchUsers.Count;$x++){
$AccessTo.Keys|
Мы проверяем, находится ли $x
-й элемент в $BatchUsers
вэтот элемент хеш-таблицы.
?{$AccessTo[$_] -contains $BatchUsers[$x]}|
Если это так, мы расширяем всех пользователей в этом элементе хеш-таблицы.
%{$AccessTo[$_]}|
Затем отфильтровываем тех, которые уже есть в $BatchUsers
.
?{$_ -notin $BatchUsers}|
Для каждого, которого нет в $BatchUsers
, мы добавляем его в $BatchUsers
.
%{$BatchUsers+=$_}
После завершения цикла Do
/ Until
в поисках пользователей перейдем к нашим исходным данным, спрятанным в $FileIn
Мы повторяем это, просматривая каждую запись, чтобы увидеть, находится ли значение в ColB
в $BatchUsers
, и проверяем, что ей еще не назначен пакет.
$FileIn | ?{$_.ColB -in $BatchUsers -and !$_.Batch}
Мы передаем эти записи в цикл ForEach-Object
, и для каждой из них добавляем свойство с именем Batch
со значением $i
(которое мы использовали для отслеживания текущего пакета)
$FileIn | ?{$_.ColB -in $BatchUsers -and !$_.Batch}|%{Add-Member -InputObject $_ -NotePropertyName 'Batch' -NotePropertyValue $i}
Теперь, когда у каждого в текущем пакете есть значение Пакета, мы устанавливаем $i
на единицу больше, чем самый высокий номер партии.Первоначально я просто повторял $i
, чтобы быть еще одним для каждого цикла цикла почтовых ящиков, но в один пакет входило несколько ящиков, поэтому я получил пакет 1 и пакет 4, что не имеет большого смысламне.Итак, да, установите следующую партию на единицу выше, чем последняя:
$i=($FileIn.batch|sort|select -last 1)+1
Вот и все.Если у вас есть конкретные вопросы, пожалуйста, не стесняйтесь спрашивать.