![PS 远程处理 AD、Get-ADUser 和带有局部变量的脚本块](https://linux22.com/image/691089/PS%20%E8%BF%9C%E7%A8%8B%E5%A4%84%E7%90%86%20AD%E3%80%81Get-ADUser%20%E5%92%8C%E5%B8%A6%E6%9C%89%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E7%9A%84%E8%84%9A%E6%9C%AC%E5%9D%97.png)
我正在尝试编写一个 PS 脚本,通过连接到 DC 并使用 Get-ADUser(以及用于其他用途的其他一些 cmdlet)检索信息来管理 AD 对象。我使用以下 PS 代码连接到 DC:
$global:MyDC = ($env:LOGONSERVER -replace "\\", "") + ".domain.com"
$ADsession = New-PSSession -computerName $global:MyDC
Invoke-Command -Session $ADsession -Command {Import-Module -Name ActiveDirectory}
Import-PSSession -session $ADsession -module ActiveDirectory -Prefix RM
类似这样的工作(所以我的 PS Remoting 似乎没问题):
$strUsersOU = "CN=UserOU,DC=domain,DC=com"
$strResourcesOU = "OU=Resources," + $strUsersOU
$strSharedOU = "OU=Shared," + $strUsersOU
[array]$arrADusers = @(Get-RMADUser -Filter * -SearchBase $strUsersOU -Properties DisplayName, AccountExpirationDate, lockedout, passwordexpired, enabled | Where-Object {($_.DistinguishedName -NotMatch $strSharedOU) -And ($_.DistinguishedName -NotMatch $strResourcesOU)} | sort DisplayName | select DisplayName, lockedout, passwordexpired, enabled, @{Name='AccountExpirationDate';Expression={$_.AccountExpirationDate.ToString('D')}}, DistinguishedName)
我在将 Get-RMADUser 与局部变量结合使用作为筛选表达式的一部分时遇到了问题(我正在筛选 AD 可分辨名称属性)。我使用上述数组执行了一些操作(加载到 DGV 等),然后(根据用户在 DGV 中选择的内容)我检索 DN 并使用它来从 AD 检索用户信息,如下所示(当我使用本地 AD PS 模块时,这似乎工作正常):
(是的,我在下面的命令中查询了所有属性,但我需要返回它们 - 即使它们是空值)
$global:objSelectedADuserInfo = Get-ADUser -Filter { DistinguishedName -eq $strSelectedUserDN } -SearchBase $strUsersOU -Properties *, departmentNumber, extensionAttribute1, employeeID, msExchHideFromAddressLists, "msDS-UserPasswordExpiryTimeComputed"
如果我将上述命令切换为使用 PS Remoting,我会收到过滤器脚本块的错误(将 Get-ADUser 从上述代码更改为 Get-RMADUser。如果我不使用过滤器,Get-RMADUser 可以正常工作。我今天几乎已经阅读了一千篇 KB 文章(一些在 StackExchange 上)关于如何使其工作(所以我不会在这里发布我遇到的所有不同错误,而是只发布我尝试过的代码)。我确信我现在正在努力搜索,以至于我忽略了一些简单的东西。我尝试过使用类似的东西:
(切换至)
$using:strSelectedUserDN
(我也尝试过类似的事情)
$ScriptBlockFilter = [scriptblock]::Create("DistinguishedName -eq $strSelectedUserDN")
然后将 $ScriptBlockFilter 变量传递给它,如下所示:
Get-RMADUser -Filter $ScriptBlockFilter -SearchBase …
(然后像这样:)
Invoke-Command -Session $ADsession -ArgumentList $strSelectedUserDN -ScriptBlock {param ($strSelectedUserDN) Get-RMADUser -Filter { DistinguishedName -eq $strSelectedUserDN } -SearchBase …
(以及以上所有方法的各种组合)。仍然没有运气,无论我尝试做什么,都无法让它工作。基本上,是否有可能让像这样的命令(如下)与远程 PS 会话一起工作?使用此线程开头的上述命令,我是否正确连接到远程 DC?我遗漏了什么(或搞砸了什么)?做这样的事情的最佳(正确)方法是什么?
$global:objSelectedADuserInfo = Get-RMADUser -Filter { DistinguishedName -eq $strSelectedUserDN } -SearchBase $strUsersOU -Properties *, departmentNumber, extensionAttribute1, employeeID, msExchHideFromAddressLists, "msDS-UserPasswordExpiryTimeComputed"
非常感谢您的帮助
答案1
我使用这段代码来重现你的情况:
$ADPSSession = New-PSSession -ComputerName 2008r2esxi2
Invoke-Command -Session $ADPSSession -Command { Import-Module ActiveDirectory }
Import-PSSession -Session $ADPSSession -Module ActiveDirectory -Prefix RM
然后我想尝试一个字符串 -Filter 参数,尝试了这个,但出现错误:
$LocalSam = 'joakimbs'
$x = Get-RMADUser -Filter "SamAccountName -eq $LocalSam" -Properties *
Error parsing query: 'SamAccountName -eq joakimbs' Error Message: 'syntax error' at position: '20'.
+ CategoryInfo : ParserError: (:) [Get-ADUser], ADFilterParsingException
然后我记得最近遇到了 AD cmdlet 在字符串和“脚本块”中使用的特殊语法(显然它们不被视为真正的脚本块)。
如果它感兴趣(我认为它比 [ScriptBlock]::Create() 更干净),我在变量周围添加了单引号,然后它就可以工作了:
$x = Get-RMADUser -Filter "SamAccountName -eq '$LocalSam'" -Properties *
$x.DistinguishedName
CN=joakimbs,CN=Users,DC=svendsen,DC=local
我希望我没有(再次)违反任何规则。我正在回答这个问题,但主要是为了为未来的读者补充信息。我应该把这写成评论吗?
我觉得我还应该提到 [char] 34 的内容是不必要的。您可以将双引号加倍,以便在双引号字符串内使用文字双引号,或者使用 PowerShell 转义字符(反引号 (`))转义双引号。
使用脚本块仍然允许您跳过字符转换(据我所知,该脚本块没有被完全处理,但仍被接受为 -Filter 参数的类型)。
似乎在这篇微软文章。
下面是使用单引号代替 [char] 34 和 [scriptblock]::Create() 的示例。
$SB = [ScriptBlock]::Create("SamAccountName -eq '$LocalSam'")
$SB.ToString()
SamAccountName -eq 'joakimbs'
$x = Get-RMADUser -Filter $SB -Properties *
$x.DistinguishedName
CN=joakimbs,CN=Users,DC=svendsen,DC=local
[char] 34
"
希望这对某人有帮助。
答案2
好吧,经过更多的反复尝试后,我终于可以使用它了:
$ScriptBlockFilter = [scriptblock]::Create("DistinguishedName -eq " + [char]34 + $strCurrentlySelectedUserDN + [char]34)
$global:objSelectedADuserInfo = (Get-RMADUser -Filter $ScriptBlockFilter -SearchBase $strUsersOU -Properties *, departmentNumber, extensionAttribute1, employeeID, msExchHideFromAddressLists, "msDS-UserPasswordExpiryTimeComputed")
问题(最初测试脚本块方法时)是因为获取RMAD用户过滤查询需要在远程端使用引号来过滤 AD 中的可分辨名称(并且在扩展变量时通过嵌套脚本块发送引号不起作用)。因此,通过添加[字符]34在扩展变量的每一侧,在将命令发送到远程 PS 会话之前,将扩展变量放在引号中。我还更改了命令周围的括号。一旦我做了这些事情,它就起作用了(有点)。
然后(顺便提一下),我遇到了一个问题,因为远程 PS 会话没有返回空的 AD 属性(无论我如何尝试让它工作)。当我使用获取AD用户(本地 AD 模块),它返回空属性(我已在获取AD用户命令),但使用远程 PS 会话,获取RMAD用户没有像使用本地 AD 模块时那样返回空的 AD 属性。将其与设置(在我的 PS 脚本中)结合起来:
Set-StrictMode -Version latest
这导致我的脚本在尝试从远程 PS 会话访问对象属性中不存在的属性时不断出错(即使我尝试明确查询它)。当我使用本地 AD 模块测试该对象时,该对象存在,但使用远程 PS 会话时则不存在。因此,在整个脚本中,我必须添加验证测试(如下例所示),以确保在尝试在脚本中访问属性之前该属性存在。
if ($global:objSelectedADuserInfo.PSObject.Properties['employeeID'])
{
Blah, blah
}
使用远程 PS 会话时需要注意的事项。无论如何,现在使用远程 PS 会话通过本地变量查询 AD 中的可分辨名称(或其他过滤器)时一切正常。
干杯!:-)