匹配正则表达式并用特殊字符替换错误

match regex and replace bug with special charakters

我已经构建了一个脚本来读取所有 Active Directory 组成员身份并将它们保存到一个文件中。 问题是,Get-ADPrincipalGroupMembership cmdlet 会像这样输出所有组:

CN=Group_Name,OU=Example Mail,OU=Example Management, DC=domain,DC=de

所以我需要在这里做一些正则表达式 and/or 替换魔术,只用从 "CN=" 开始到第一个 ",".[=15 的第一个字符串替换整行=]

结果是这样的:

Group_Name

所以,有一个广告组不会被替换。我已经知道为什么了,但我不知道如何解决这个问题。在我们的 AD 中有一个具有特殊字符的组,如下所示:

CN=AD_Group_Name+up,OU=Example Mail,OU=Example Management, DC=domain,DC=de

因此,由于小“+”号,整行甚至都没有被触及。

有人知道为什么会这样吗?

Import-Module ActiveDirectory

# Get Username
Write-Host "Please enter the Username you want to export the AD-Groups from."
$UserName = Read-Host "Username"

# Set Working-Dir and Output-File Block:
$WorkingDir = "C:\Users\USER\Desktop"
Write-Host "Working directory is set to " + $WorkingDir
$OutputFile = $WorkingDir + "\" + $UserName + ".txt"

# Save Results to File
Get-ADPrincipalGroupMembership $UserName |
    select -Property distinguishedName |
    Out-File $OutputFile -Encoding UTF8

# RegEx-Block to find every AD-Group in Raw Output File and delete all
# unnaccessary information:
[regex]$RegEx_mark_whole_Line = "^.*"
# The ^ matches the start of a line (in Ruby) and .* will match zero or more
# characters other than a newline
[regex]$RegEx_mark_ADGroup_Name = "(?<=CN=).*?(?=,)"
# This regex matches everything behind the first "CN=" in line and stops at
# the first "," in the line. Then it should jump to the next line.

# Replace-Block (line by line): Replace whole line with just the AD group
# name (distinguishedName) of this line.
foreach ($line in Get-Content $OutputFile) {
    if ($line -like "CN=*") {
        $separator = "CN=",","
        $option = [System.StringSplitOptions]::RemoveEmptyEntries
        $ADGroup = $line.Split($separator, $option)
        (Get-Content $OutputFile) -replace $line, $ADGroup[0] |
            Set-Content $OutputFile -Encoding UTF8
    }
}

您的群组名称包含一个字符 (+),该字符在正则表达式中具有特殊含义(前一个表达式的一次或多次)。要禁用特殊字符,请在替换操作中转义搜索字符串:

... -replace [regex]::Escape($line), $ADGroup[0]

但是,我一开始就看不出你需要那个替代品的用途。基本上,您将输出文件中的一行替换为您之前已经提取的那行 的子字符串。只需将该子字符串写入输出文件即可。

$separator = 'CN=', ','
$option    = [StringSplitOptions]::RemoveEmptyEntries
(Get-Content $OutputFile) | ForEach-Object {
    $_.Split($separator, $option)[0]
} | Set-Content $OutputFile

更好的是,使用 Get-ADObject cmdlet 扩展组成员的名称:

Get-ADPrincipalGroupMembership $UserName |
    Get-ADObject |
    Select-Object -Expand Name

Ansgar 的答案在使用正则表达式方面要好得多,但我相信在这种情况下,您可以使用 IndexOf 函数做一个肮脏的解决方法。在您的 if 语句中,您可以执行以下操作:

if ($line -like "CN=*") {
    $ADGroup = $line.Substring(3, $line.IndexOf(',')-3)
    }

这里起作用的原因是您知道输出将以 CN=YourGroupName 开头,这意味着您知道所需的字符串从第 4 个字符开始。其次,您知道组名称不包含任何逗号,这意味着 IndexOf(',') 将始终找到该字符串的末尾,因此您无需担心 nth occurrence of a string in a string.

首先,这可能是个好主意,也可能不是个好主意,这取决于你在这里做什么。 CN 是 /not/ 不可变的,因此如果您将它作为密钥存储在某处,您很可能会 运行 遇到问题。不过,组的 objectGUID 属性 是一个很好的主键。

就获取此值而言,我认为您可以大大简化它。该 cmdlet 输出的 name 属性 将始终具有您想要的值:

Get-ADPrincipalGroupMembership <username> | select name