Get-Aduser -Filter не будет принимать переменную
Я хотел бы проверить, существует ли учетная запись пользователя в системе.
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter {sAMAccountName -eq "$SamAc"}
Я не уверен почему, но $User
всегда будет возвращать ноль, даже если {sAMAccountName -eq "$SamAc"}
должно быть правдой.
Что мне здесь не хватает?
Редактировать:
Вот чего не хватало:
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Примечание редактора: блок скрипта ( { ... }
) был заменен строкой.
8 ответов
В существующих ответах содержится ценная информация, но я думаю, что более целенаправленное резюме полезно:
ТЛ; др
НИКОГДА не используйте блок скрипта -
{ ... }
- построить-Filter
-параметр аргумента, для любого командлета.- Это работает только в очень ограниченных обстоятельствах - см. Ниже.
- Создается ошибочное впечатление, что фильтр является частью кода PowerShell, а это не так (он поддерживает только несколько операторов, чье поведение частично отличается от их аналогов в PowerShell - см.
Get-Help about_ActiveDirectory_Filter
).
ВСЕГДА используйте строку для построения
-Filter
-параметр аргумента, потому что фактический тип параметра[string]
- В данном случае:
Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
- Увидеть
Get-Help about_ActiveDirectory_Filter
- В данном случае:
Правильный и надежный подход заключается в создании строки
Любой аргумент, который вы передаете
-Filter
в любом случае сначала приводится к строке, прежде чем она передаетсяGet-ADUser
командлет, потому что-Filter
параметр имеет тип[string]
- по всем командлетам, которые поддерживают эти параметры; проверить сGet-ADUser -?
С
-Filter
в общем случае командлет должен интерпретировать эту строку, используя язык, специфичный для домена, который часто имеет мало общего с PowerShell.- В случае
Get-ADUser
этот предметно-ориентированный язык (язык запросов) задокументирован вGet-Help about_ActiveDirectory_Filter
- В случае
Используйте строковую интерполяцию PowerShell (или конкатенацию строк из литералов и переменных / ссылок / выражений), чтобы "запечь" любые переменные ссылки в строке.
Например, все следующие команды работают и являются функционально эквивалентными, используя различные методы PowerShell для построения строки, с различными стилями цитирования и escape-символом:
# All these commands are equivalent.
Get-ADUser -Filter "sAMAccountName -eq ""$SamAc"""
Get-ADUser -Filter "sAMAccountName -eq `"$SamAc`"" #`
Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Get-ADUser -Filter ('sAMAccountName -eq "' + $SamAc + '"')
Важной частью является обеспечение того, чтобы $SamAc
расширяется сразу (заменяется его значением) либо через строку в двойных кавычках "..."
или путем явной конкатенации строк (+ $SamAc + ...
).
Если $SamAc
содержит jdoe
например, команды выше передают один из следующих (эквивалентных) литералов -Filter
:
sAMAccountName -eq "jdoe"
sAMAccountName -eq 'jdoe'
Однако с типами данных, отличными от чисел и строк, вам все равно может понадобиться использовать оценку переменных поставщика AD (см. Ниже):
Например, строка [datetime]
значение (например, 08/15/2018 12:45:58
) не может быть распознан как дата провайдером AD [1].
В этом случае:
- Используйте строку в одинарных кавычках (
'...'
) - Обязательно используйте только простые ссылки на переменные (например,
$date
), а не выражения ($date.Year
или же$($date.Year)
); например:
# Note the use of '...' and be sure to use just a variable reference,
# not an expression.
# With this approach, never use embedded quoting, even with string variables.
Get-ADUser -Filter 'whenChanged -ge $date'
Предостережение: этот подход не будет работать с неявно удаленными модулями, потому что ссылка на переменную затем оценивается на удаленной машине.
Если вы указываете блок скрипта - чего вам следует избегать:
Блок скрипта при преобразовании в строку приводит к буквальному содержанию между {
а также }
- нет расширения переменной (интерполяция):
PS> {sAMAccountName -eq "$SamAc"}.ToString()
sAMAccountName -eq "$SamAc" # !! $SamAc was *not* expanded
Следовательно, это буквально sAMAccountName -eq "$SamAc"
это передается Get-ADUser
,
Get-ADUser
Возможно, чтобы поддержать синтаксис блока скриптов / быть более похожим на PowerShell, он поддерживает ссылку на переменную без кавычек - обратите внимание на отсутствие "
вокруг $SamAc
:
{ sAMAccountName -eq $SamAc } # as stated, Get-ADUser doesn't see the { and }
То есть, Get-ADUser
делает свою собственную, похожую на Powershell интерпретацию строкового литерала sAMAccountName -eq $SamAc
: так же, как вам не нужно заключать ссылку на переменную в "..."
в выражении PowerShell (например, 'Windows_NT' -eq $env:OS
), вы также не должны здесь - и на самом деле не должны, о чем свидетельствует попытка ОП провалиться.
Однако эта эмуляция обычного блока сценариев PowerShell не только сбивает с толку - потому что пользователи все еще думают, что им нужно заключить в кавычки - но также и наполовину испечена, и поэтому хрупкая:
Он не работает со ссылками на свойства или вызовами методов:
{ sAMAccountName -eq $searchObj.SamAccountName } # !! DOES NOT WORK
Он не работает с неявно удаленными модулями, потому что ссылка на переменную оценивается на удаленном компьютере и ищет там переменную.
Источник скрипта-блока путаницы
В то время как:
Get-Help about_ActiveDirectory_Filter
похвально только обсуждает строки,это
Get-Help Get-ADUser
К сожалению, он использует блоки скриптов для всех своих примеров.
За одним исключением, примеры используют только литералы внутри блоков скрипта, где проблема никогда не появляется. Это одно исключение (на момент написания статьи):
-filter { lastLogon -le $logonDate }
Этот пример работает - он использует простую ссылку на переменную без кавычек - но из-за выбора нестрокового значения никто не испытывает соблазна ошибочно применить заключающие в кавычки в этом случае - в отличие от сравнения строковых полей.
Синтаксис блока скриптов является соблазнительным и удобным, потому что цитирование становится проще: вам не нужно вложенное цитирование.
Однако по всем обсуждаемым причинам этого следует избегать.
[1] Если бы кто-то мог проверить это, было бы замечательно (лично я не могу): прямое расширение строки, эквивалентное выражению переменной-оценено-AD-провайдера
Get-ADUser -Filter 'whenChanged -ge $date'
является
Get-ADUser -Filter "whenChanged -ge '$date'"
Это означает, что провайдер AD в конечном итоге видит что-то вроде whenChanged -ge '01/15/2018 16:00:00'
как выражение фильтра; чтобы это работало, он должен (а) принять строку в качестве операнда и (б) понять формат даты / времени PowerShell, который является форматом инвариантной культуры (даты, подобные США, с указанием месяца в начале, но 24 часы)
Является ли?
Это меня немного поразило, когда я впервые начал работать с модулем ActiveDirectory, и это было сложно понять.
-Filter
Параметр для командлетов модуля ActiveDirectory фактически ищет строку. Когда вы делаете {sAMAccountName -eq "$SamAc"}
в качестве значения, он на самом деле ищет "sAMAccountName -eq ""`$SamAc"""
По сути, Powershell анализирует параметр и превращает его значение в строку и не будет интерполировать переменную. Попробуйте построить строку перед рукой, и она должна работать.
Что-то вроде этого:
$SamAc = Read-Host 'What is your username?'
$filter = "sAmAccountname -eq ""$SamAc"""
$User = Get-ADUser -Filter $filter
Я должен прокомментировать это, потому что это действительно раздражало меня, чтобы разобраться в этом.
У Джозефа Алкорна правильная идея. Параметр фильтра принимает строку, а затем оценивает ее для обработки фильтра. Что удивляет людей, так это то, что вам предоставляется возможность использовать фигурные скобки вместо {}, и это не сработает, как вы ожидаете, если бы вы использовали Where... это все равно должно рассматриваться как строка.
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Я рекомендую придерживаться кавычек, чтобы сделать их более понятными / читабельными для себя и других и избежать возможных синтаксических ошибок, или придерживаться Where{} в конвейере. При этом я считаю, что лучше всего использовать двойные кавычки снаружи и одинарные кавычки внутри, чтобы вы все равно получали определение intellisense для переменной.
Просто удалите кавычки вокруг вашей переменной:
$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter {sAMAccountName -eq $SamAc}
Это должно работать просто отлично.
if (($ADUser = Get-ADUser -filter "SamAccountName -eq '$(Read-Host Username)'") -ne $null) {$ADUser.SamAccountName} else {"Not Found"}
Мне потребовалось совсем немного, чтобы просто использовать
Не заключайте в кавычки ссылку на переменную ("$SamAc").
ТХ так много
Хорошо, я наконец-то получил работу, используя следующий синтаксис и приведенный ниже пример сверху:
Ранее:
$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Рабочая версия:
$user = Get-aduser -Filter "sAMAccountName -eq '$($SamAc)'"
Мне пришлось добавить $($) в $SamAc, прежде чем PowerShell смог получить доступ к значению переменной строки.
Надеюсь, это кому-нибудь поможет!
Небольшое дополнение, если кто-то вроде меня попал сюда и все еще рвал себе волосы:
-properties *
Было бы довольно часто использовать это в этом запросе. Не работает, я уверен, что кто-то умнее меня сможет это понять
-свойства mail,cn,wtf
и т.д. работает как ожидалось