如何提速获取12k+ M365用户信息的PowerShell脚本?
提速M365用户信息导出的方案
你的PowerShell脚本处理12000名用户耗时数小时,核心瓶颈在循环内逐个调用Get-Mailbox——每调用一次都是一次远程请求,12000次请求累积下来拖慢了整体速度。以下是两种可行的提速方案:
一、优化现有PowerShell脚本
1. 批量获取所有邮箱,用哈希表关联
把Get-Mailbox的调用从循环内移到外部,一次性获取所有邮箱数据,再通过哈希表建立用户UPN到邮箱对象的映射,循环时直接从哈希表取值,避免重复远程请求:
# 批量获取所有AAD用户 $allUsers = Get-AzureADUser -All $true # 批量获取所有邮箱,建立UPN到邮箱的哈希映射 $allMailboxes = Get-Mailbox -ResultSize Unlimited $mailboxMap = @{} foreach ($mbx in $allMailboxes) { $mailboxMap[$mbx.UserPrincipalName] = $mbx } $outputPath = 'c:\blahblahpath\M365users.csv' # 先清空文件 Clear-Content -Path $outputPath -ErrorAction SilentlyContinue # 收集所有用户对象,最后一次性导出 $outputObjects = foreach ($user in $allUsers) { # 从哈希表取对应邮箱,无则为空 $mbx = $mailboxMap[$user.UserPrincipalName] $Extension_Attributes = New-Object Psobject -Property $user.ExtensionProperty [pscustomobject] @{ "UserPrincipalName" = $user.UserPrincipalName "GivenName" = $user.GivenName "Surname" = $user.Surname "M3-DisplayName" = $user.DisplayName "JobTitle" = $user.JobTitle "Department" = $user.Department "CompanyName" = $user.CompanyName "M3-Mail" = $user.mail "M3-OtherMails" = $user.OtherMails[0] "ForwardingSmtpAddress" = $mbx.ForwardingSmtpAddress "ExternalEmailAddress" = $mbx.ExternalEmailAddress "Aliases" = $mbx.EmailAddresses "DeliverToMailboxAndForward" = $mbx.DeliverToMailboxAndForward "TelephoneNumber" = $user.TelephoneNumber "PhysicalDeliveryOfficeName" = $user.PhysicalDeliveryOfficeName "PreferredLanguage" = $user.PreferredLanguage "MailNickName" = $user.MailNickName "StreetAddress" = $user.StreetAddress "City" = $user.City "State" = $user.State "PostalCode" = $user.PostalCode "Country" = $user.Country "UsageLocation" = $user.UsageLocation "Mobile" = $user.Mobile "UserType" = $user.UserType "AccountEnabled" = $user.AccountEnabled "LastLogon" = $user.LastLogon "BlockCredential" = $user.BlockCredential "AssignedLicenses" = $user.AssignedLicenses "Created" = $Extension_Attributes.createdDateTime "MemberNumber" = $Extension_Attributes.EmployeeID "TokenExp" = $user.RefreshTokensValidFromDateTime "OLDMemNumExt" = $Extension_Attributes.extension_60a1274a0a9d4344bd172d81b06d0f50_MemberNumber "Source" = $Extension_Attributes.extension_06f8dc5952b048a1879af4e793844173_Source "M3-MemType" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_MemType "M3-Status" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_Status "EmailTeams" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_EmailTeams "M3-EmailCC" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_EmailCC "M3-EmailPri" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_EmailPri "Cert" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_Cert "M3-ExpDate" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_ExpDate "WGTitle" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_WGTitle "ChapTitle" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_ChapTitle "OtherTitle" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_LdrTitle "Othercodes" = $extension_Attributes.extension_11b052b5eb8f4c77973a06876d25a6a4_Othercodes "ChapCodes" = $extension_Attributes.extension_11b052b5eb8f4c77973a06876d25a6a4_ChapCodes "WGcodes" = $extension_Attributes.extension_11b052b5eb8f4c77973a06876d25a6a4_WGcodes "Allcodes" = $extension_Attributes.extension_a14f14664c8e457a856d24680b31c9d4_AllCodes "Cmems" = $Extension_Attributes.extension_4adef2735ffb4a9dafc9a85188ca512d_Cmems "M3-isnet" = $Extension_Attributes.extension_01816427922e40c9b55cf4364bc171ce_IsNet "SipProxyAddress" = $user.SipProxyAddress } } # 一次性导出所有数据到CSV,避免多次打开文件 $outputObjects | Export-Csv -Path $outputPath -NoTypeInformation -Force
2. 额外优化点
- 删除原脚本中无实际作用的
$path -replace ' ', ''`代码行。 - 修正原脚本未定义的
$keepinmbx变量,替换为邮箱对象的DeliverToMailboxAndForward属性。 - 修复
Allcodes字段属性名的多余空格问题。
二、用Python调用Microsoft Graph API实现更快获取
如果想进一步提速,可以用Python调用Microsoft Graph API,它支持批量请求和更高效的数据查询:
核心思路
- 通过Graph API一次性获取所有AAD用户的所需属性(包括扩展属性)。
- 再一次性获取所有邮箱的关键字段。
- 用Python字典建立用户UPN到邮箱数据的映射,合并后导出CSV。
示例代码框架
import csv from msgraph.core import GraphClient # 初始化Graph客户端(需提前完成身份验证,比如Client Credentials流) client = GraphClient(credentials=your_credentials) # 获取所有AAD用户,包含所需属性和扩展属性 users_response = client.get('/users?$select=userPrincipalName,givenName,surname,displayName,jobTitle,department,companyName,mail,otherMails,telephoneNumber,physicalDeliveryOfficeName,preferredLanguage,mailNickname,streetAddress,city,state,postalCode,country,usageLocation,mobile,userType,accountEnabled,lastSignInDateTime,blocked,assignedLicenses,refreshTokensValidFromDateTime,sipProxyAddress&$expand=extensionProperties') users = users_response.json()['value'] # 获取所有邮箱数据 mailboxes_response = client.get('/users/mailboxes?$select=userPrincipalName,forwardingSmtpAddress,externalEmailAddress,emailAddresses,deliverToMailboxAndForward') mailboxes = mailboxes_response.json()['value'] mailbox_map = {mbx['userPrincipalName']: mbx for mbx in mailboxes} # 准备输出数据 output_rows = [] for user in users: upn = user['userPrincipalName'] mbx = mailbox_map.get(upn, {}) ext_props = user.get('extensionProperties', {}) row = { 'UserPrincipalName': upn, 'GivenName': user.get('givenName'), 'Surname': user.get('surname'), 'M3-DisplayName': user.get('displayName'), 'JobTitle': user.get('jobTitle'), 'Department': user.get('department'), 'CompanyName': user.get('companyName'), 'M3-Mail': user.get('mail'), 'M3-OtherMails': user.get('otherMails', [])[0] if user.get('otherMails') else None, 'ForwardingSmtpAddress': mbx.get('forwardingSmtpAddress'), 'ExternalEmailAddress': mbx.get('externalEmailAddress'), 'Aliases': ','.join(mbx.get('emailAddresses', [])), 'DeliverToMailboxAndForward': mbx.get('deliverToMailboxAndForward'), # 其他字段按PowerShell脚本的字段顺序填充 'Created': ext_props.get('createdDateTime'), 'MemberNumber': ext_props.get('EmployeeID') } output_rows.append(row) # 导出到CSV with open('c:\\blahblahpath\\M365users.csv', 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=output_rows[0].keys()) writer.writeheader() writer.writerows(output_rows)
优势
- Graph API的批量查询效率远高于PowerShell逐个调用Cmdlet,尤其针对大规模数据。
- Python的字典映射和批量写入CSV的速度也比PowerShell循环Append更快。
内容的提问来源于stack exchange,提问作者BrownInTown
相关产品推荐
相关产品推荐

