Arrays and -contains - проверка подстрок в элементах массива - PullRequest
0 голосов
/ 09 апреля 2019

Я пытаюсь отфильтровать пользователей из определенной группы.

Я получил следующий вывод в переменной: Group1 Group2 etc...

Одна группа для каждой строки, сохраненной в массиве. Я пытаюсь отфильтровать только одну конкретную группу. Но когда я использую -contains, он всегда говорит $false, даже если там есть группа.

Мой код:

$group = get-aduser -identity name -properties memberof |
  select-object -expandproperty memberof | %{ (get-adgroup $_).name }

$contains = $group -contains "string"

$contains равно $false, даже если в массиве есть элементы, содержащие строку ...

Чего мне не хватает?

Ответы [ 2 ]

2 голосов
/ 09 апреля 2019

Похоже, вы ошиблись, предполагая, что оператор -contains PowerShell выполнит подстроку , сопоставив с элементами массива LHS.
Вместо этого он выполняет равенство тесты - как и -eq - против элементов массива - подробности см. в этом ответе .

Чтобы выполнил буквальное сопоставление подстроки с элементами массива , используйте:

# With non-literal search strings:
[bool] $contains = $group -match ([regex]::Escape($someString))

# With a string literal that doesn't contain regex metachars.,
# escaping isn't needed.
[bool] $contains = $group -match 'foo'

# With a string literal with metachars., you must individually \-escape them.
[bool] $contains = $group -match 'foo\.bar'

Примечание:

  • Вышеприведенный пример демонстрирует надежный общий способ убедиться, что строка поиска обрабатывается как литерал , используя [regex]::Escape(), что необходимо, поскольку -match ожидает регулярное выражение ( регулярное выражение ) в качестве его RHS (шаблон поиска) .

  • Бегство не всегда необходимо; в частности, это требуется только для присутствия так называемых метасимволов (имеющих специальное значение в регулярном выражении, таких как .), а когда вы используете строку литерал , вы можете выбрать напрямую \ - уберечь их; например, чтобы искать буквальную подстроку a.b, вы можете передать 'a\.b'.

    • Скорее всего, имена групп AD не требуют экранирования, но важно осознавать необходимость этого вообще.
  • Как и для всех операторов в PowerShell, по умолчанию сопоставление не учитывает регистр ; используйте вариант -cmatch для сопоставления с учетом регистра.

  • Ограниченный выше тип [bool] используется для гарантии того, что результат операции -match будет преобразован в логическое значение:

    • Хотя -match напрямую возвращает логическое значение с скалярным (не массивом) LHS, с массивом LHS оно действует как фильтр и возвращает соответствующие элементы массива вместо ; интерпретируется в булевом контексте, например в условном if, который обычно все еще дает ожидаемый результат, поскольку непустой массив интерпретируется как $true, а пустой - как $false; опять же, однако важно знать разницу.
  • На практике это редко вызывает проблемы с производительностью, но стоит отметить, что -match, действуя как фильтр с массивами, всегда совпадает с всеми элементами массива - он не останавливается при обнаружении совпадения first , как это делают операторы -contains и -in.

    • Что касается плюса, вы можете использовать -match для получения соответствующих элементов.

Ошибочное ожидание -contains выполнения подстроки , возможно, возникло из-за путаницы с одноименным, но не связанным String.Contains() методом , который действительно выполняет буквальное совпадение подстроки ; например, 'foo'.Contains('o') дает $true. Также обратите внимание, что .Contains() по умолчанию чувствителен к регистру .

PowerShell имеет оператор без для литерала соответствия подстроки.

Однако вы можете объединить универсальные функции фильтрации массивов PowerShell со строковым методом .Contains(), но учтите, что обычно он работает (потенциально намного) хуже, чем -match.

Достаточно производительная альтернатива - использовать метод массива PSv4 + .Where() следующим образом:

# Note: Substring search is case-sensitive here.
[bool] $contains = $group.Where({ $_.Contains("string") }, 'First')

С положительной стороны этот подход прекращает сопоставление, как только найдено первое совпадение.

0 голосов
/ 09 апреля 2019

Ответ был -match вместо contains.Теперь вывод верен.

...