You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求修改PowerShell脚本:向Azure AD组所有者发送带成员列表的邮件

问题需求

我正在编写PowerShell脚本,用于收集Azure AD组所有所有者的邮箱地址,以组名为文件名导出为TXT/CSV文件(比如GroupName.csv里包含Owner1@domain.com、Owner2@domain.com等),用于安全审计。

现在需要实现:读取指定文件夹中的组所有者CSV文件,给每个组所有者发送邮件,同时附加对应组的成员列表文件(同样以组名命名,存在另一个指定文件夹),让所有者验证组成员是否正确。

我对PowerShell了解基础,已完成导出所有者的脚本,也找到一份邮件发送脚本,请求帮忙修改适配需求。注:公司使用Outlook。


现有脚本

导出Azure AD组所有者脚本(可正常运行,可按需修改)

# 这是我目前写的导出组所有者列表并按组名保存的脚本,运行正常,可按需修改
$cred = Get-Credential Connect-AzureAD -Credential $cred
$groups = Get-AzureADGroup -All $true
ForEach($group in $groups) {
    $resultsarray = @()
    $owners = Get-AzureADGroupOwner -ObjectId $group.ObjectId -All $true
    ForEach($owner in $owners) {
        $resultsarray += [PSCustomObject] @{" " = $owner.UserPrincipalName}
        $gName = $group.DisplayName[IO.Path]::GetinvalidFileNameChars() |
        ForEach - Object{$gName = $gName.Replace(
                             $_, "_")}[IO.Path] ::GetinvalidFileNameChars() |
        ForEach - Object{$gName = $gName.Replace(
                             '[', "_")}[IO.Path] ::GetinvalidFileNameChars() |
        ForEach - Object{$gName = $gName.Replace(']', "_")}

    #$resultsarray | Export-CSV -Path D :\\Script\\AzureADOwners$gName.csv -Delimiter ',' -NoTypeInformation

    $resultsarray | Out-File -Filepath D:\\Script\\AzureADOwners$gName.txt
    }
}

网上找到的邮件发送脚本

# 这是我在网上找的脚本,所有者CSV文件路径是D:\\Script\\AzureADOwners\\,文件名为GroupName.csv

Import-Module ImportExcel
$csv_files = Get-ChildItem -Path 'D:\\Script\\AzureADOwners' -Filter '*.csv'
foreach ($csv_file in $csv_files) {
    $data = Import-Csv -Path $csv_file.FullName
    foreach ($row in $data) {
        $email_address = $row.Column1
        $attachment = D:\Script\AzureADMembers\$csv_file.csv
        Send-MailMessage -To $email_address -Subject 'Test Email' -Body 'This is a test email.' -Attachments $attachment -SmtpServer 'smtp.gmail.com' -Credential(Get-Credential)
    }
}

修改后的解决方案

1. 修正后的导出组所有者脚本

修复原脚本语法错误,优化文件名清理逻辑,优先导出为CSV(方便后续邮件脚本读取):

# 导出Azure AD组所有者到CSV文件
$cred = Get-Credential
Connect-AzureAD -Credential $cred

# 定义存储所有者文件的路径
$ownerFolder = "D:\Script\AzureADOwners"
# 确保文件夹存在,不存在则创建
if (-not (Test-Path $ownerFolder)) {
    New-Item -Path $ownerFolder -ItemType Directory | Out-Null
}

$groups = Get-AzureADGroup -All $true
foreach ($group in $groups) {
    $owners = Get-AzureADGroupOwner -ObjectId $group.ObjectId -All $true
    if ($owners) {
        # 清理组名中的非法文件名字符
        $cleanGroupName = $group.DisplayName
        [IO.Path]::GetInvalidFileNameChars() | ForEach-Object {
            $cleanGroupName = $cleanGroupName.Replace($_, "_")
        }
        # 给导出的列设置明确名称,避免读取时出错
        $ownerList = $owners | Select-Object @{Name="OwnerEmail"; Expression={$_.UserPrincipalName}}
        # 导出到CSV文件
        $exportPath = Join-Path $ownerFolder "$cleanGroupName.csv"
        $ownerList | Export-Csv -Path $exportPath -NoTypeInformation -Encoding UTF8
        Write-Host "已导出组 [$($group.DisplayName)] 的所有者到文件: $exportPath"
    } else {
        Write-Host "组 [$($group.DisplayName)] 没有所有者,跳过导出"
    }
}

2. 适配Outlook的邮件发送脚本

改用Outlook COM对象发送邮件,无需配置SMTP服务器,适配企业Outlook环境:

# 读取组所有者CSV并发送带成员列表附件的邮件(基于Outlook)
# 定义文件路径
$ownerFolder = "D:\Script\AzureADOwners"
$memberFolder = "D:\Script\AzureADMembers"

# 检查文件夹是否存在
if (-not (Test-Path $ownerFolder)) {
    Write-Error "所有者文件文件夹 [$ownerFolder] 不存在,脚本终止"
    exit 1
}
if (-not (Test-Path $memberFolder)) {
    Write-Error "成员列表文件夹 [$memberFolder] 不存在,脚本终止"
    exit 1
}

# 获取所有所有者CSV文件
$ownerCsvFiles = Get-ChildItem -Path $ownerFolder -Filter "*.csv"

# 初始化Outlook应用
$outlook = New-Object -ComObject Outlook.Application

foreach ($csvFile in $ownerCsvFiles) {
    # 获取组名(去掉文件后缀)
    $groupName = $csvFile.BaseName
    # 对应成员列表文件路径
    $memberFile = Join-Path $memberFolder "$groupName.csv"
    
    if (-not (Test-Path $memberFile)) {
        Write-Warning "组 [$groupName] 的成员列表文件不存在,跳过发送"
        continue
    }

    # 读取所有者邮箱列表
    $owners = Import-Csv -Path $csvFile.FullName
    foreach ($owner in $owners) {
        $ownerEmail = $owner.OwnerEmail
        if (-not $ownerEmail) {
            Write-Warning "文件 [$($csvFile.Name)] 中存在空邮箱地址,跳过该条目"
            continue
        }

        # 创建邮件
        $mail = $outlook.CreateItem(0)
        $mail.To = $ownerEmail
        $mail.Subject = "请验证Azure AD组 [$groupName] 的成员列表"
        $mail.Body = @"
您好,

请查看附件中的Azure AD组「$groupName」成员列表,确认所有成员归属正确。

如有异常,请及时联系IT部门。

谢谢!
"@
        # 添加成员列表附件
        $mail.Attachments.Add($memberFile)
        # 发送邮件(如需保存草稿,替换为 $mail.Save())
        $mail.Send()
        Write-Host "已向 [$ownerEmail] 发送组 [$groupName] 的验证邮件"
    }
}

# 释放Outlook COM对象,避免内存泄漏
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($outlook) | Out-Null
Remove-Variable outlook

注意事项

  • 运行导出脚本前需安装AzureAD模块:Install-Module -Name AzureAD -Force
  • 邮件脚本需在已安装Outlook且当前用户已登录Outlook的机器上运行
  • 需自行补充导出组成员列表的脚本(逻辑与导出所有者类似,使用Get-AzureADGroupMember获取成员并导出为同名CSV)
  • 确保文件夹路径正确,且当前用户对文件夹有读写权限

内容的提问来源于stack exchange,提问作者Raybanz_UK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:00:45