我有一个 PS 脚本,用于检查 Active Directory 中某些自定义用户的属性。 其中一项属性是“经理”。
$data = Get-ADUser $user -Properties * | Select-Object DisplayName, LockedOut, Enabled, LastLogonDate, PasswordExpired, EmailAddress, Company, Title, Manager, Office
Write-Host "9." $user "manager is" $data.manager -ForegroundColor Green
当我运行脚本时,我得到:
User's manager is CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com
问题是文本
"OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com"
对于某些用户来说会有所不同
如何修改输出并删除除
"cool.boss"
之外的所有内容?
先谢谢你了
这应该是一种或多或少安全且仍然简单的解析方法:
($data.manager -split "," | ConvertFrom-StringData).CN
使用 PowerShell 惯用的 regex 解决方案来补充此处的有用答案:
-split
,基于正则表达式的字符串分割运算符:$dn = 'CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com'
($dn -split '(?:^|,)CN=|,')[1] # -> 'cool.boss'
-replace
,基于正则表达式的字符串替换运算符:$dn = 'CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com'
$dn -replace '(?:^|,)CN=([^,]+).*', '$1' # -> 'cool.boss'
注:
上述解决方案不依赖于输入中名称-值对 (RDN) 的特定顺序(即
CN
条目不必是 first 条目),但它们确实只提取first CN
条目的值,如果存在多个,并且它们确实假设(至少)存在一个。
原则上,DN(可分辨名称)(以输入字符串为例)可以在构成 DN 的名称-值对的值中包含
,
字符 嵌入,转义为 \,
(或者,用十六进制表示法,\2C
);例如,"CN=boss\, cool,OU=Users,..."
真正强大的解决方案必须考虑到这一点,并且理想情况下还可以unescape结果值;截至撰写本文时,现有的答案都没有做到这一点;见下文。
稳健地解析 LDAP/AD DN(专有名称):
以下
Split-DN
功能:
,
字符以及其他转义序列\
,还包括以 \<hh>
形式转换转义序列,其中 hh
是两位数的十六进制。代表字符代码点的数字,转换为它们代表的实际字符(例如,\3C
,转换为 <
字符)。CN
、OU
),以及出现多次次的名称值 - 例如 OU
- 表示为 array。 调用示例:
PS> Split-DN 'CN=I \3C3 Huckabees\, I do,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com'
Name Value
---- -----
CN I <3 Huckabees, I do
OU {Users, SO, PL, RET…}
DC {domain, com}
请注意转义序列
\3C
如何转换为 <
(它代表的字符),以及 \,
如何被识别为 ,
嵌入 中的 CN
值。
由于输入字符串包含 multiple
OU
和 DC
名称-值对(所谓的 RDN,relative 专有名称),因此它们对应的哈希表条目变成了值的 arrays(在 truncated-for 中表示) -仅显示输出,带有 { ... }
,用 ,
分隔元素)。
函数
Split-DN
的源代码:
注意:为简洁起见,省略了错误处理和验证。
function Split-DN {
param(
[Parameter(Mandatory)]
[string] $DN
)
# Initialize the (ordered) output hashtable.
$oht = [ordered] @{}
# Split into name-value pairs, while correctly recognizing escaped, embedded
# commas.
$nameValuePairs = $DN -split '(?<!\\),'
$nameValuePairs.ForEach({
# Split into name and value.
# Note: Names aren't permitted to contain escaped chars.
$name, $value = ($_ -split '=', 2).Trim()
# Unescape the value, if necessary.
if ($value -and $value.Contains('\')) {
$value = [regex]::Replace($value, '(?i)\\(?:[0-9a-f]){2}|\\.', {
$char = $args[0].ToString().Substring(1)
if ($char.Length -eq 1) { # A \<literal-char> sequence.
$char # Output the character itself, without the preceding "\"
}
else { # A \<hh> escape sequence, convert the hex. code point to a char.
[char] [uint16]::Parse($char, 'AllowHexSpecifier')
}
})
}
# Add an entry to the output hashtable. If one already exists for the name,
# convert the existing value to an array, if necessary, and append the new value.
if ($existingEntry = $oht[$name]) {
$oht[$name] = ([array] $existingEntry) + $value
}
else {
$oht[$name] = $value
}
})
# Output the hashtable.
$oht
}
您可以使用
.split()
方法来获得您想要的。
$DN = "CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC =com"
$DN.Split(',').Split('=')[1]
我的建议是,将其扔到另一个
Get-ADUser
中以获得更整洁的输出的显示名称(:
你可以使用正则表达式:
$s = "CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC =com"
$pattern = [regex]"CN=.*?OU"
$r = $pattern.Replace($s, "CN=OU")
$r