使用 PowerShell 脚本进行 API 驱动的入站预配
本教程介绍如何使用 PowerShell 脚本实现 Microsoft Entra ID API 驱动的入站预配。 按照本教程中的步骤,可以将包含 HR 数据的 CSV 文件转换为批量请求有效负载,并将其发送到 Microsoft Entra 预配 /bulkUpload API 终结点。 本文还提供了有关如何将同一集成模式用于任何记录系统的指南。
集成方案
业务要求
你的记录系统定期生成包含辅助角色数据的 CSV 文件导出。 你希望实现一种集成,以便从 CSV 文件读取数据,并自动预配目标目录(对于混合用户为本地 Active Directory,对于仅云用户为 Microsoft Entra ID)中的用户账户。
实现要求
从实现的角度来看:
- 你想要使用无人参与的 PowerShell 脚本从 CSV 文件导出读取数据,并将其发送到入站预配 API 终结点。
- 在 PowerShell 脚本中,你不希望实现在记录系统和目标目录之间比较标识数据的复杂逻辑。
- 你想要使用 Microsoft Entra 预配服务来应用 IT 托管的预配规则,以在目标目录(本地 Active Directory 或 Microsoft Entra ID)中自动创建/更新/启用/禁用帐户。
集成方案变体
虽然本教程使用 CSV 文件作为记录系统,但你可以自定义示例 PowerShell 脚本,以从任何记录系统读取数据。 下面是企业集成方案变体的列表,其中 API 驱动的入站预配可以使用 PowerShell 脚本实现。
# | 记录系统 | 有关使用 PowerShell 读取源数据的集成指南 |
---|---|---|
1 | 数据库表 | 如果使用 Azure SQL 数据库或本地 SQL Server,则可以使用 Read-SqlTableData cmdlet 读取存储在 SQL 数据库的表中的数据。 可以使用 Invoke-SqlCmd cmdlet 运行 Transact-SQL 或 XQuery 脚本。 如果使用 Oracle/MySQL/Postgres 数据库,可以找到供应商发布的 PowerShell 模块,也可以找到 PowerShell 库中提供的 PowerShell 模块。 使用该模块从数据库表读取数据。 |
2 | LDAP 服务器 | 使用 System.DirectoryServices.Protocols .NET API 或 PowerShell 库中提供的一个 LDAP 模块来查询 LDAP 服务器。 了解用于从 LDAP 服务器检索用户数据的 LDAP 架构和层次结构。 |
3 | 公开 REST API 的任何系统 | 若要使用 PowerShell 从 REST API 终结点读取数据,可以使用 Microsoft.PowerShell.Utility 模块中的 Invoke-RestMethod cmdlet。 查看 REST API 的文档,了解它所需的参数和标头、它返回的格式以及它使用的身份验证方法。 然后,可以相应地调整 Invoke-RestMethod 命令。 |
4 | 公开 SOAP API 的任何系统 | 若要使用 PowerShell 从 SOAP API 终结点读取数据,可以使用 Microsoft.PowerShell.Management 模块中的 New-WebServiceProxy cmdlet。 查看 SOAP API 的文档,了解它所需的参数和标头、它返回的格式以及它使用的身份验证方法。 然后,可以相应地调整 New-WebServiceProxy 命令。 |
读取源数据后,应用预处理规则,并将记录系统中的输出转换为批量请求,该请求可发送到 Microsoft Entra 预配 bulkUpload API 终结点。
重要
如果想要与社区共享 PowerShell 集成脚本,请在 PowerShell 库 发布脚本,并在 GitHub 存储库 entra-id-inbound-provisioning
上通知我们,以便我们可以添加引用。
如何使用本教程
Microsoft Entra 入站预配 GitHub 存储库中发布的 PowerShell 示例脚本可自动执行多个任务。 它具有逻辑用来处理大型 CSV 文件并将批量请求分块,便于在每个请求中发送 50 条记录。 下面介绍如何根据集成要求对其进行测试和自定义。
注意
示例 PowerShell 脚本是按原样提供的,以供实现引用。 如果有与脚本相关的问题,或者想增强它,请使用 GitHub 项目存储库。
# | 自动化任务 | 实施指南 | 高级自定义 |
---|---|---|---|
1 | 从 CSV 文件读取辅助角色数据。 | 下载 PowerShell 脚本。 它具有现成逻辑,可以从任何 CSV 文件中读取数据。 请参阅 CSV2SCIM PowerShell 使用情况详细信息,以熟悉此脚本的不同执行模式。 | 如果记录系统不同,请检查集成方案变体部分中提供的指南,了解如何自定义 PowerShell 脚本。 |
2 | 预处理数据并将其转换为 SCIM 格式。 | 默认情况下,PowerShell 脚本将 CSV 文件中的每个记录转换为 SCIM 核心用户 + 企业用户表示形式。 按照使用标准架构生成批量请求有效负载一节中的步骤来熟悉此过程。 | 如果 CSV 文件有不同字段,请调整 AttributeMapping.psd file 文件以生成有效 SCIM 用户。 还可以使用自定义 SCIM 架构生成批量请求。 更新 PowerShell 脚本以包含任何自定义 CSV 数据验证逻辑。 |
3 | 使用证书向 Microsoft Entra ID 进行身份验证。 | 创建可以访问入站预配 API 的服务主体。 请参阅为服务主体身份验证配置客户端证书一节中的步骤,以了解如何使用客户端证书进行身份验证。 | 如果想使用托管标识而不是服务主体进行身份验证,请查看示例脚本中 Connect-MgGraph 的使用情况,并将其更新为使用托管标识。 |
4 | 在本地 Active Directory 或 Microsoft Entra ID 中预配帐户。 | 配置 API 驱动的入站预配应用。 这将生成唯一的 /bulkUpload API 终结点。 若要使用具有基于证书的身份验证的服务主体运行脚本,请参阅“使用客户端证书身份验证上传批量请求有效负载”部分中的步骤。 根据集成需求验证属性流并自定义属性映射。 | 如果计划将批量请求与自定义 SCIM 架构一起使用,请扩展预配应用架构以包含自定义 SCIM 模式元素。 |
5 | 扫描预配日志并重试预配失败的记录。 | 请参阅获取最新同步周期的预配日志一节中的步骤,以了解如何获取和分析预配日志数据。 识别失败的用户记录,并将其包含在下一个上传周期中。 | - |
6 | 将基于 PowerShell 的自动化部署到生产中。 | 验证 API 驱动的预配流并自定义 PowerShell 脚本以满足要求后,可以将自动化部署为 Azure 自动化中的 PowerShell 工作流 Runbook,或部署为计划在 Windows 服务器上运行的服务器进程。 | - |
下载 PowerShell 脚本
- 访问 GitHub 存储库
entra-id-inbound-provisioning
。 - 使用代码 ->Clone 或 代码 ->Download ZIP 选项将此存储库的内容复制到本地文件夹中。
- 导航到 PowerShell/CSV2SCIM 文件夹。 它具有以下目录结构:
- src
- CSV2SCIM.ps1 (主要脚本)
- ScimSchemaRepresentations(包含用于验证 AttributeMapping.psd1 文件的标准 SCIM 架构定义的文件夹)
- EnterpriseUser.json、Group.json、Schema.json、User.json
- 示例
- AttributeMapping.psd1(CSV 文件中的列到标准 SCIM 属性的映射示例)
- csv-with-2-records.csv(带有两条记录的 CSV 文件示例)
- csv-with-1000-records.csv(包含 1000 条记录的 CSV 文件示例)
- Test-ScriptCommands.ps1(示例用法命令)
- UseClientCertificate.ps1(用于生成自签名证书并将其作为服务主体凭据上传以在 OAuth 流中使用的脚本)
Sample1
(文件夹中具有更多关于如何将 CSV 文件列映射到 SCIM 标准属性的示例。如果为员工、分包商和实习生获得不同 CSV 文件,则可以为每个实体创建单独的 AttributeMapping.psd1 文件。)
- src
- 下载并安装最新版本的 PowerShell。
- 运行命令以启用远程签名脚本的执行:
set-executionpolicy remotesigned
- 安装以下必备模块:
Install-Module -Name Microsoft.Graph.Applications,Microsoft.Graph.Reports
使用标准架构生成批量请求负载
本节介绍如何从 CSV 文件中生成具有标准 SCIM 核心用户和企业用户属性的批量请求有效负载。
使用 CSV 文件 Samples/csv-with-2-records.csv
来说明此过程。
在 Notepad++ 或 Excel 中打开 CSV 文件
Samples/csv-with-2-records.csv
以检查文件中的列。在 Notepad++ 或 Visual Studio Code 等源代码编辑器中,打开 PowerShell 数据文件
Samples/AttributeMapping.psd1
,该文件允许将 CSV 文件列映射到 SCIM 标准架构属性。 现成文件已经预先配置了 CSV 文件列到相应 SCIM 架构属性的映射。@{ externalId = 'WorkerID' name = @{ familyName = 'LastName' givenName = 'FirstName' } active = { $_.'WorkerStatus' -eq 'Active' } userName = 'UserID' displayName = 'FullName' nickName = 'UserID' userType = 'WorkerType' title = 'JobTitle' addresses = @( @{ type = { 'work' } streetAddress = 'StreetAddress' locality = 'City' postalCode = 'ZipCode' country = 'CountryCode' } ) phoneNumbers = @( @{ type = { 'work' } value = 'OfficePhone' } ) "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" = @{ employeeNumber = 'WorkerID' costCenter = 'CostCenter' organization = 'Company' division = 'Division' department = 'Department' manager = @{ value = 'ManagerID' } } }
打开 PowerShell 并更改到目录 CSV2SCIM\src。
运行以下命令来初始化
AttributeMapping
变量。$AttributeMapping = Import-PowerShellDataFile '..\Samples\AttributeMapping.psd1'
运行以下命令以验证
AttributeMapping
文件是否具有有效 SCIM 架构属性。 如果验证成功,此命令将返回 True。.\CSV2SCIM.ps1 -Path '..\Samples\csv-with-2-records.csv' -AttributeMapping $AttributeMapping -ValidateAttributeMapping
假设
AttributeMapping
文件具有名为 userId 的无效 SCIM 属性,那么ValidateAttributeMapping
模式将显示以下错误。验证
AttributeMapping
文件有效后,运行以下命令在文件BulkRequestPayload.json
中生成批量请求,该请求包括 CSV 文件中的两条记录。.\CSV2SCIM.ps1 -Path '..\Samples\csv-with-2-records.csv' -AttributeMapping $AttributeMapping > BulkRequestPayload.json
可以打开文件的内容
BulkRequestPayload.json
,以验证是否根据文件AttributeMapping.psd1
中定义的映射设置了 SCIM 属性。可以使用 Graph 浏览器或 cURL 将上面生成的文件原样发布到与预配应用关联的 /bulkUpload API 端点。 参考:
要使用相同的 PowerShell 脚本将生成的有效负载直接上传到 API 端点,请参阅下一节。
为服务主体身份验证配置客户端证书
注意
此处的说明显示了如何生成自签名证书。 自签名证书默认不受信任,并且可能难以维护。 另外,它们可能使用过时的哈希以及不够可靠的加密套件。 为了提高安全性,请购买由知名证书颁发机构签名的证书。
- 运行以下 PowerShell 脚本以生成新自签名证书。 如果购买了由知名证书颁发机构签名的证书,则可以跳过此步骤。
生成的证书存储在 Current User\Personal\Certificates 中。 可以使用“控制面板 ->管理用户证书”选项查看它。$ClientCertificate = New-SelfSignedCertificate -Subject 'CN=CSV2SCIM' -KeyExportPolicy 'NonExportable' -CertStoreLocation Cert:\CurrentUser\My $ThumbPrint = $ClientCertificate.ThumbPrint
- 若要将此证书与有效服务主体关联,请以“应用程序管理员”身份登录到 Microsoft Entra 管理中心。
- 打开在“应用注册”下配置的服务主体。
- 从“概览”边栏选项卡中复制对象 ID。 使用值替换字符串
<AppObjectId>
。 复制应用程序(客户端)ID。稍后将使用它,它被引用为<AppClientId>
。 - 运行以下命令将证书上传到注册的服务主体。
你应在已注册应用的“证书和机密”边栏选项卡下看到证书。Connect-MgGraph -Scopes "Application.ReadWrite.All" Update-MgApplication -ApplicationId '<AppObjectId>' -KeyCredentials @{ Type = "AsymmetricX509Cert" Usage = "Verify" Key = $ClientCertificate.RawData }
- 将以下两个应用程序权限范围添加到服务主体应用:Application.Read.All 和 Synchronization.Read.All。 PowerShell 脚本通过
ServicePrincipalId
查找预配应用并获取预配JobId
时需要这些功能。
使用客户端证书身份验证上传批量请求有效负载
本节介绍如何使用受信任的客户端证书将生成的批量请求有效负载发送到入站预配 API 端点。
打开配置的 API 驱动预配应用。 从预配应用>属性>对象 ID 复制与预配应用关联的
ServicePrincipalId
。通过提供
ServicePrincipalId
、ClientId
和TenantId
的正确值来运行以下命令。$ClientCertificate = Get-ChildItem -Path cert:\CurrentUser\my\ | Where-Object {$_.Subject -eq "CN=CSV2SCIM"} $ThumbPrint = $ClientCertificate.ThumbPrint .\CSV2SCIM.ps1 -Path '..\Samples\csv-with-2-records.csv' -AttributeMapping $AttributeMapping -TenantId "contoso.onmicrosoft.com" -ServicePrincipalId "<ProvisioningAppObjectId>" -ClientId "<AppClientId>" -ClientCertificate (Get-ChildItem Cert:\CurrentUser\My\$ThumbPrint)
访问预配应用的预配日志边栏选项卡,以验证上述请求的处理情况。
使用自定义 SCIM 架构生成批量请求
本节介绍如何使用由 CSV 文件中的字段组成的自定义 SCIM 架构命名空间生成批量请求。
在 Notepad++ 或 Visual Studio Code 等源代码编辑器中,打开 PowerShell 数据文件
Samples/AttributeMapping.psd1
,该文件允许将 CSV 文件列映射到 SCIM 标准架构属性。 现成文件已经预先配置了 CSV 文件列到相应 SCIM 架构属性的映射。打开 PowerShell 并更改到目录 CSV2SCIM\src。
运行以下命令来初始化
AttributeMapping
变量。$AttributeMapping = Import-PowerShellDataFile '..\Samples\AttributeMapping.psd1'
运行以下命令以验证
AttributeMapping
文件是否具有有效 SCIM 架构属性。 如果验证成功,此命令将返回 True。.\CSV2SCIM.ps1 -Path '..\Samples\csv-with-2-records.csv' -AttributeMapping $AttributeMapping -ValidateAttributeMapping
除了 SCIM 核心用户和企业用户属性外,要获得自定义 SCIM 架构命名空间
urn:ietf:params:scim:schemas:extension:contoso:1.0:User
下所有 CSV 字段的简单列表,请运行以下命令。.\CSV2SCIM.ps1 -Path '..\Samples\csv-with-2-records.csv' -AttributeMapping $AttributeMapping -ScimSchemaNamespace "urn:ietf:params:scim:schemas:extension:contoso:1.0:User" > BulkRequestPayloadWithCustomNamespace.json
扩展预配作业架构
人力资源团队发送的数据文件通常包含更多在标准 SCIM 模式中没有直接表示的属性。 为了表示这样的属性,建议创建 SCIM 扩展架构,并在此命名空间下添加属性。
CSV2SCIM 脚本提供了名为 UpdateSchema
的执行模式,它读取 CSV 文件中的所有列,将它们添加到扩展架构命名空间下,并更新预配应用模式。
注意
如果属性扩展已存在于预配应用架构中,则此模式只会发出属性扩展已存在的警告。 因此,如果在 CSV 文件中添加了新字段,并且希望将它们作为扩展添加,那么在 UpdateSchema 模式下运行 CSV2SCIM 脚本就没有问题。
为了说明过程,将使用 CSV2SCIM 文件夹中的 CSV 文件 Samples/csv-with-2-records.csv
。
在记事本、Excel 或 TextPad 中打开 CSV 文件
Samples/csv-with-2-records.csv
,以检查文件中的列。运行以下命令:
.\CSV2SCIM.ps1 -Path '..\Samples\csv-with-2-records.csv' -UpdateSchema -ServicePrincipalId <servicePrincipalId> -TenantId "contoso.onmicrosoft.com" -ScimSchemaNamespace "urn:ietf:params:scim:schemas:extension:contoso:1.0:User"
通过打开“属性映射”页面并访问“高级选项”下的“编辑 API 属性列表”选项,可以验证对预配应用架构的更新。
“属性列表”显示新命名空间下的属性。
获取最新同步周期的预配日志
发送批量请求后,可以查询 Microsoft Entra ID 处理的最新同步周期的日志。 可以使用 PowerShell 脚本检索同步统计信息和处理详细信息,并将其保存以供分析。
要在控制台上查看日志详细信息和同步统计信息,请运行以下命令:
.\CSV2SCIM.ps1 -ServicePrincipalId <servicePrincipalId> -TenantId "contoso.onmicrosoft.com" -GetPreviousCycleLogs -NumberOfCycles 1
注意
默认情况下,NumberOfCycles 为 1。 指定数字以检索更多同步周期。
要在控制台上查看同步统计信息并将日志详细信息保存到变量中,请运行以下命令:
$logs=.\CSV2SCIM.ps1 -ServicePrincipalId <servicePrincipalId> -TenantId "contoso.onmicrosoft.com" -GetPreviousCycleLogs
要使用客户端证书身份验证运行命令,请通过提供
ServicePrincipalId
、ClientId
和TenantId
的正确值来运行命令:$ClientCertificate = Get-ChildItem -Path cert:\CurrentUser\my\ | Where-Object {$_.Subject -eq "CN=CSV2SCIM"} $ThumbPrint = $ClientCertificate.ThumbPrint $logs=.\CSV2SCIM.ps1 -ServicePrincipalId "<ProvisioningAppObjectId>" -TenantId "contoso.onmicrosoft.com" -ClientId "<AppClientId>" -ClientCertificate (Get-ChildItem Cert:\CurrentUser\My\$ThumbPrint) -GetPreviousCycleLogs -NumberOfCycles 1
要查看特定记录的详细信息,可以循环到集合中或选择其特定索引,例如:
$logs[0]
还可以使用
where-object
语句使用 sourceID 或 DisplayName 搜索特定记录。 在 ProvisioningLogs 属性中,可以找到为该特定记录所做操作的所有详细信息。$user = $logs | where sourceId -eq '1222' $user.ProvisioningLogs | fl
可以在 ModifiedProperties 属性上看到受用户影响的特定属性。
$user.ProvisioningLogs.ModifiedProperties
附录
CSV2SCIM PowerShell 使用情况详细信息
以下是 CSV2SCIM PowerShell 脚本接受的命令行参数列表。
PS > CSV2SCIM.ps1 -Path <path-to-csv-file>
[-ScimSchemaNamespace <customSCIMSchemaNamespace>]
[-AttributeMapping $AttributeMapping]
[-ServicePrincipalId <spn-guid>]
[-ValidateAttributeMapping]
[-UpdateSchema]
[-ClientId <client-id>]
[-ClientCertificate <certificate-object>]
[-RestartService]
注意
AttributeMapping
和 ValidateAttributeMapping
命令行参数指的是 CSV 列属性到标准 SCIM 架构元素的映射。
它不指在源 SCIM 架构元素与目标 Microsoft Entra/本地 Active Directory 属性之间在 Microsoft Entra 管理中心预配应用中执行的属性映射。
参数 | 说明 | 处理注解 |
---|---|---|
Path | CSV 文件的完整路径或相对路径。 例如:.\Samples\csv-with-1000-records.csv |
必需:是 |
ScimSchemaNamespace | 自定义 SCIM 架构命名空间,用于将 CSV 文件中的所有列作为属于特定命名空间的自定义 SCIM 属性发送。 例如: urn:ietf:params:scim:schemas:extension:csv:1.0:User |
强制:仅当希望: - 更新预配应用架构时,或 希望在有效负载中包含自定义 SCIM 属性时。 |
AttributeMapping | 指向 PowerShell 数据(.psd1 扩展名)文件,其将 CSV 文件中的列映射到 SCIM 核心用户和企业用户属性。 查看示例:AttributeMapping.psd file for CSV2SCIM script。 例如: powershell $AttributeMapping = Import-PowerShellDataFile '.\Samples\AttributeMapping.psd1'`-AttributeMapping $AttributeMapping |
必须:是 唯一不需要指定的情况是在使用 UpdateSchema 开关时。 |
ValidateAttributeMapping | 使用此“开关”标志可验证 AttributeMapping 文件是否包含符合 SCIM 核心和企业用户架构的属性。 | 必需:否 建议使用它来确保合规性。 |
ServicePrincipalId | 可以从预配应用>属性>对象 ID 检索的预配应用的服务主体 ID GUID 值 | 必需:仅当需要时: - 更新预配应用架构,或 - 将生成的批量请求发送到 API 端点时。 |
UpdateSchema | 使用此开关可指示脚本读取 CSV 列,并将它们作为自定义 SCIM 属性添加到预配应用架构中。 | |
ClientId | 用于 OAuth 身份验证流的 Microsoft Entra 已注册应用的客户端 ID。 此应用必须具有有效证书凭据。 | 必需:仅在执行基于证书的身份验证时。 |
ClientCertificate | 在 OAuth 流期间使用的客户端身份验证证书。 | 必需:仅在执行基于证书的身份验证时。 |
GetPreviousCycleLogs | 获取最新同步周期的预配日志。 | |
NumberOfCycles | 指定应检索多少个同步周期。 默认情况下,此值为 1。 | |
RestartService | 使用此选项,脚本会在上传数据之前暂时暂停预配作业,它会上传数据,然后再次启动作业,以确保立即处理有效负载。 | 仅在测试期间使用此选项。 |
AttributeMapping.psd 文件
此文件用于将 CSV 文件中的列映射到标准 SCIM 核心用户和企业用户属性架构元素。 文件还生成 CSV 文件内容的适当表示,作为批量请求有效负载。
在下一个示例中,将 CSV 文件中的以下列映射到其对应的 SCIM 核心用户和企业用户属性。
@{
externalId = 'WorkerID'
name = @{
familyName = 'LastName'
givenName = 'FirstName'
}
active = { $_.'WorkerStatus' -eq 'Active' }
userName = 'UserID'
displayName = 'FullName'
nickName = 'UserID'
userType = 'WorkerType'
title = 'JobTitle'
addresses = @(
@{
type = { 'work' }
streetAddress = 'StreetAddress'
locality = 'City'
postalCode = 'ZipCode'
country = 'CountryCode'
}
)
phoneNumbers = @(
@{
type = { 'work' }
value = 'OfficePhone'
}
)
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" = @{
employeeNumber = 'WorkerID'
costCenter = 'CostCenter'
organization = 'Company'
division = 'Division'
department = 'Department'
manager = @{
value = 'ManagerID'
}
}
}