Назад | Перейти на главную страницу

Передача ввода списка в Get-ADComputer

Итак, я написал сценарий, который получает некоторую информацию из 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
}