因此,我编写了一个脚本,用于从 AD 获取有关用户及其关联计算机的一些信息。我在网上读到了一些人们在使用 Get-ADComputer cmdlet 时遇到的问题以及一些可能存在的错误。起初我以为这就是我在这里遇到的问题,但现在我不太确定了。
我的问题是我的代码运行正常,但如果我添加一段不相关的代码来从变量中获取一些信息,它就会破坏其他东西。看一看。
全部代码: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
。所以我不知道。
谢谢大家。
答案1
我相信您的问题在于您将多种不同类型的对象写入输出管道(隐式地不将它们分配给变量)并依靠默认的 Powershell 格式规则将它们正确显示到控制台(但做不到)。
它显示第一种类型的对象,然后尝试使用与第一种相同的格式化程序显示第二种类型的对象,并且只写空行。如果您将 Get-ADUser 调用移到 Get-ADComputer 调用循环下方,则会遇到相反的问题。
假设此脚本的输出仅打算显示在控制台上,而不会由其他脚本进一步处理或与其他 cmdlet 链接,您可能希望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
}