Итак, я написал сценарий, который получает некоторую информацию из AD о пользователе и связанном с ним компьютере (ах). Я прочитал в Интернете о некоторых проблемах, с которыми люди сталкиваются при использовании командлета Get-ADComputer, и о некоторых возможных ошибках, связанных с ним. Сначала я подумал, что это то, с чем я здесь столкнулся, но теперь я не уверен.
Моя проблема в том, что мой код работает нормально, но если я добавлю несвязанный фрагмент кода, чтобы получить некоторую информацию из переменной, он сломает что-то еще. Взглянуть.
Весь код: http://paste.ofcode.org/Hgbiukp2XYqKnv2sdUGBKb
Рассматриваемый фрагмент кода:
## Prompt host for input
$username = Read-Host -Prompt "Enter the Username"
## Get list of computers
$ComputerList = Get-ADComputer -Filter {ManagedBy -eq $username} -Properties ManagedBy | Select-Object -ExpandProperty Name
## Compute and format results
Foreach ($Computer in $ComputerList)
{
$OnlineStatus = Test-Connection -ComputerName $Computer -BufferSize 16 -Count 1 -Quiet
If ($OnlineStatus -like "True") {$OnlineStatus = "$True"} else {$OnlineStatus = "$False"}
Get-ADComputer -Identity $Computer -Properties ManagedBy,DNSHostName,LastLogonTimestamp |
Select-Object DNSHostName,@{Name="Active";Expression={$OnlineStatus}},@{Name="LastLogonTimestamp";Expression={[datetime]::FromFileTime($_.LastLogonTimestamp)}}
}
Так что эта часть работает идеально. Теперь, если вы добавите фрагмент, который получает некоторую информацию об имени пользователя, вы увидите, что он перестает отображать вывод о компьютере AD.
## Prompt host for input
$username = Read-Host -Prompt "Enter the Username"
## Get Username info
Get-ADUser -Identity $username –Properties “DisplayName”, “msDS-UserPasswordExpiryTimeComputed”, "LockedOut" |
Select-Object -Property @{Name="Name";Expression={$_.DisplayName}},@{Name=“PWD Expiration Timestamp”;Expression={[datetime]::FromFileTime($_.“msDS-UserPasswordExpiryTimeComputed”)}},LockedOut
## Get list of computers
$ComputerList = Get-ADComputer -Filter {ManagedBy -eq $username} -Properties ManagedBy | Select-Object -ExpandProperty Name
## Compute and format results
Foreach ($Computer in $ComputerList)
{
$OnlineStatus = Test-Connection -ComputerName $Computer -BufferSize 16 -Count 1 -Quiet
If ($OnlineStatus -like "True") {$OnlineStatus = "$True"} else {$OnlineStatus = "$False"}
Get-ADComputer -Identity $Computer -Properties ManagedBy,DNSHostName,LastLogonTimestamp |
Select-Object DNSHostName,@{Name="Active";Expression={$OnlineStatus}},@{Name="LastLogonTimestamp";Expression={[datetime]::FromFileTime($_.LastLogonTimestamp)}}
}
Может кто-нибудь сказать мне, почему это так? И как исправить?
Обычно я могу понять это, просто играя с этим, но этот действительно поставил меня в тупик. Я думаю, проблема должна быть в форматировании $ComputerList
переменная, но каждый элемент в списке представляет собой строку, что и является Get-ADComputer
требует. Так что я просто не знаю.
Спасибо всем заранее.
Я считаю, что ваша проблема вращается вокруг того факта, что вы пишете несколько разных типов объектов в выходной конвейер (неявно, не назначая их переменной) и полагаясь на правила форматирования Powershell по умолчанию, чтобы правильно отображать их на консоли (что он может т).
Он отображает первый тип объекта, а затем пытается отобразить второй тип объекта, используя то же средство форматирования, что и первый, и просто записывает пустые строки. У вас возникнет противоположная проблема, если вы переместите вызов Get-ADUser ниже цикла с вызовами Get-ADComputer.
Предполагая, что выходные данные этого сценария предназначены только для отображения на консоли и не обрабатываются в дальнейшем другими сценариями или связаны с другими командлетами, вы можете использовать Write-Host
с явным форматированием для каждой части вашего вывода. Обычно это плохая идея.. Что-то вроде этого.
$user = Get-ADUser -Identity $username –Properties “DisplayName”, “msDS-UserPasswordExpiryTimeComputed”, "LockedOut"
Write-Host "User: $($user.DisplayName)`tPWD Expiration: $([datetime]::FromFileTime($_.“msDS-UserPasswordExpiryTimeComputed”))`tLockedOut: $($user.LockedOut)"
Я также хотел бы предложить несколько дополнительных советов по общей структуре вашего скрипта.
Сначала я сделаю ваш $username
переменная обязательный параметр вместо явного вызова Read-Host
. Powershell автоматически запросит его, если он еще не указан в командной строке.
Когда вы проверяете наличие пользователя, вы меняете тип объекта вашего $username
переменная из строки в ADUser
объект. Я предполагаю, что это не было вашим намерением, и просто повезло, что более поздние ссылки на него работают с использованием объекта вместо строки. Вы также делаете второй Get-ADUser
позвоните сразу после этого, чтобы получить нужные вам атрибуты, которые требуют дополнительного обращения к контроллеру домена. Я бы просто объединил их и переместил ## Get Username info
в блок try / catch. Если пользователь не существует, он все равно вызовет то же исключение. Я бы также назначил вывод новой переменной, например $user
.
При желании вы также можете пропустить всю обработку исключений и изменить Get-ADUser
призыв использовать -Filter {SamAccountName -eq $username}
параметр, а затем просто проверьте $ null, как вы это сделаете позже с Get-ADComputer
.
Вы также в конечном итоге дублируете свои вызовы Get-ADComputer. Сначала вы вызываете с фильтром, а затем повторно вызываете для каждого результата. Было бы эффективнее просто добавить DNSHostName,LastLogonTimestamp
атрибуты к первоначальному вызову, а затем перебирать полученные объекты напрямую без необходимости повторного вызова Get-ADComputer.
Вот как может выглядеть получившийся скрипт:
param(
[Parameter(Mandatory=$true,Position=0)]
[string]$username
)
# Import AD Module
Import-Module ActiveDirectory
Write-Host "Active Domain: $((Get-ADDomain).DNSRoot)"
# Get user details
$user = Get-ADUser -Filter {SamAccountName -eq $username} -Properties DisplayName,msDS-UserPasswordExpiryTimeComputed,LockedOut
If ($user -eq $null) {
Write-Error "Error: Username not found. Exiting"
Exit
}
Write-Host "Name: $($user.DisplayName)"
Write-Host "PWD Expiration Timestamp: $([datetime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed'))"
Write-Host "LockedOut: $($user.LockedOut)"
# Get managed computers
$ComputerList = Get-ADComputer -Filter {ManagedBy -eq $username} -Properties ManagedBy,DNSHostName,LastLogonTimestamp
# Error-Handling: If no computers found
If ($ComputerList -eq $null) {
Write-Error "No computers found"
Exit
}
# Compute and format results
ForEach ($computer in $ComputerList) {
$OnlineStatus = Test-Connection -ComputerName $computer.Name -BufferSize 16 -Count 1 -Quiet
# since this is now the only type of object we will be putting on the pipeline,
# it's ok to just do that now
$computer | Select-Object DNSHostName,@{L="Active";E={$OnlineStatus}},@{L="LastLogonTimestamp";E={[datetime]::FromFileTime($_.LastLogonTimestamp)}} | Write-Output
}