当显示名称中有特殊字符时获取通讯组中所有显示名称的 SMTP 地址

Getting the SMTP address for all Display Names in a Distribution Group when there is a Special Character in the Display Name

所以,我带着更多有关获取已接受发件人、ModeratedBy 和 ManagedBy 的通讯组 SMTP 地址的问题回来了。

所以我得到的脚本几乎可以完美运行。但是,当我使用显示名称从 acceptmessagesonlyfromsendorsormembers 中提取 smtp 地址列表时,除非名称中有特殊字符或其他 spaces,否则它会起作用。因此显示名称格式为 "Last, First",只要格式遵循该规则,就可以了。但是,如果姓氏中有 space,例如 "Mac Gruber, Steven" 或“#IT-Dept”,它不会获取 SMTP 地址。

我很确定问题出在我用来从 acceptmessagesonlyfromsendersormembers 属性 中列出的规范名称列表中获取显示名称的拆分逻辑中。

下面是供参考的脚本。

$props = @(
    "DisplayName"
    "SamAccountName"
    "PrimarySmtpAddress"
    @{n='Accepted Senders';e= {($_.acceptmessagesonlyfromsendersormembers | Foreach-Object {
    (Get-AdUser -Filter "DisplayName -eq '$($_.Split('/')][-1])'" -Property ProxyAddresses |
        Select-Object -Expand ProxyAddresses | Where-Object {$_ -cmatch '^SMTP:'}) -replace '^SMTP:'}) -join '; '}}
    "ModerationEnabled"
    @{N="ModeratedBy";E= {($_.ModeratedBy | ForEach-Object {
    (Get-AdUser -Filter "DisplayName -eq '$($_.Split("/")[-1])'" -Property ProxyAddresses |
        Select-Object -Expand ProxyAddresses | Where-Object {$_ -cmatch '^SMTP:'}) -replace '^SMTP:'}) -join '; '}}
    @{Name="Internal Senders Only";E={$_.RequireSenderAuthenticationEnabled}}
    @{N="ManagedBy";E= {($_.ManagedBy | ForEach-Object {
    (Get-AdUser -Filter "DisplayName -eq '$($_.Split("/")[-1])'" -Property ProxyAddresses |
        Select-Object -Expand ProxyAddresses | Where-Object {$_ -cmatch '^SMTP:'}) -replace '^SMTP:'}) -join '; '}}
        )
Get-DistributionGroup -ResultSize Unlimited | Select-Object $props -First 1000 | export-Csv x:\xxx.csv -NoTypeInformation

我们一如既往地非常感谢您的帮助。

瑞安

好的,所以问题是您的 cmdlet 正在输出 CanonicalName,这是一个计算的 属性 而不是实际存储在 AD 中的东西。在 JRV 的回答 here 的帮助下,我们有一个函数可以将 CanonicalName 转换为 DistinguishedName。 DN 可以直接传递给 Get-ADUser,这样可以简化事情。首先,函数,稍微修改以很好地接受管道输入:

Function Convert-CanonicalName{   
    Param(
            [Parameter(Mandatory, ValueFromPipeline)]
            [string[]]$CanonicalName
    )
BEGIN{
    Try{
        $NameTranslate = New-Object -ComObject NameTranslate
        [void]$NameTranslate.GetType().InvokeMember('Init', 'InvokeMethod', $NULL, $NameTranslate, @(3, 2))
    }
    Catch{
        Throw $_
    }
}
PROCESS{
    ForEach($User in $CanonicalName){
        Try{
            [void]$NameTranslate.GetType().InvokeMember('Set', 'InvokeMethod', $NULL, $NameTranslate, @(8,$User))
            $NameTranslate.GetType().InvokeMember('Get', 'InvokeMethod', $NULL, $NameTranslate, @(1))
        }
        Catch{
            Throw $_
        }
    }
}
}

这允许我们将 'MyDomain.Net/Users/Big Jimmy' 之类的内容通过管道传输到函数中,并将其 return 'CN=Big Jimmy,OU=Users,DC=MyDomain,DC=Net' 传输到管道中。

继续,让我们采用您计算的属性之一:

@{n='Accepted Senders';e= {($_.acceptmessagesonlyfromsendersormembers | Foreach-Object {
(Get-AdUser -Filter "DisplayName -eq '$($_.Split('/')][-1])'" -Property ProxyAddresses |
    Select-Object -Expand ProxyAddresses | Where-Object {$_ -cmatch '^SMTP:'}) -replace '^SMTP:'}) -join '; '}}

现在,我们实际上并不需要其中的 ForEach-Object 循环。这里的一切都将采用一系列事物并处理每个项目并将其适当地传递到管道中。所以我将放弃它,为了便于阅读,我将管道的每个部分放在自己的行上。我们要做的是从 $_.acceptmessagesonlyfromsendersormembers 获取 CanonicalNames 输出,将其通过管道传输到我们的新函数,将它们转换为 DN,将其通过管道传输到 Get-ADUser,展开 属性,过滤 SMTP,清理字符串,并加入它们。

@{n='Accepted Senders';e= {($_.acceptmessagesonlyfromsendersormembers | 
    Convert-CanonicalName |
    Get-AdUser -Property ProxyAddresses |
    Select-Object -Expand ProxyAddresses | 
    Where-Object {$_ -cmatch '^SMTP:'}) -replace '^SMTP:' -join '; '}}

您应该能够以相同的结果类似地修改您的其他项目。诚然,我没有要测试的 Exchange 服务器,但如果您获得了一组 CN,那么这应该可以完成工作。