Microsoft Entra ID へ ユーザ情報を権限付きで一括登録してみた(C#)
はじめに
今回は、Azure Active Directory 改め、Microsoft Entra ID を C# で一括登録する方法を見ていきたいと思います。なお、ユーザの一括登録自体は、Azure Portal から作成可能ですが、同時に権限やグループを割り当てる場合は、Azure PowerShell や、Azure CLI によるコマンドレット、もしくは、今回のように C# による実装が必要となります。
本記事の ソースコードは、Git に登録しています。
サービスプリンシパルを登録する
Azure Portal を介さずに、外部から Entra ID へ接続するには、サービスプリンシパルが必要です。今回は、C# を利用するため、登録していきましょう。
Entra ID をクリックします。
アプリの登録>+新規登録をクリックします。
名前へ任意の文字列を入れ、登録をクリックします。
アプリケーション (クライアント) ID と、ディレクトリ (テナント) ID はプログラムで指定するのでメモっておきましょう。
証明書とシークレットをクリックし、新しいクライアントシークレットをクリックし、追加します。
同様に値の部分をメモっておきます。
APIのアクセス許可 をクリックし、プログラムから利用する権限を追加します。
ユーザ情報Csvファイルを用意する
一括登録するためのCsvファイルを用意します。RoleNameの部分は、ビルトインロールリファレンスを参照してください。
DisplayName,MailNickname,UserPrincipalName,Password,RoleName
John Doe,jdoe,jdoe@realisfleuze.onmicrosoft.com,Password123,Global Administrator
Jane Doe,janed,janed@realisfleuze.onmicrosoft.com,Password123,Global Reader
Alex Smith,asmith,asmith@realisfleuze.onmicrosoft.com,Password123,Guest Inviter
Maria Garcia,mgarcia,mgarcia@realisfleuze.onmicrosoft.com,Password123,Identity Governance Administrator
James Johnson,jjohnson,jjohnson@realisfleuze.onmicrosoft.com,Password123,Insights Administrator
ビルトイン ロール リファレンス
# | ロール名 | ロールID |
---|---|---|
1 | Usage Summary Reports Reader | 008a4859-bdcb-459b-b7ec-904fb5e165d6 |
2 | Edge Administrator | 02bb4ba5-2ffb-4cf7-9c57-9a86022c7aff |
3 | Attribute Log Administrator | 0398da0f-b648-4635-9415-e218f5c83c67 |
4 | Compliance Data Administrator | 042cec86-f0d6-46de-93d5-75fafe38bf52 |
5 | Identity Governance Administrator | 05d80b1e-52a6-4b86-a310-a43d937bea16 |
6 | Authentication Policy Administrator | 0af2454c-b99f-4045-9f3d-1288a970fe6d |
7 | Permissions Management Administrator | 0bdf5e13-0439-4aa2-8208-cb49c3800a5b |
8 | Insights Analyst | 10ef4940-d22c-4183-941f-1cd07d2132e8 |
9 | Cloud Application Administrator | 122a99c3-c475-453b-867b-01c14f8501e9 |
10 | Virtual Visits Administrator | 128fc433-85c2-4eba-97a9-66390a21ae71 |
11 | Authentication Administrator | 16a29b8f-7507-4113-8852-786ac36843d5 |
12 | Exchange Recipient Administrator | 174baec1-eb67-4ef1-8401-1e812268d1da |
13 | Security Administrator | 197253ba-1252-4ea6-9872-66f4d640bec8 |
14 | Attack Payload Author | 21cafa97-86c7-44a9-ad30-eb7af65563a7 |
15 | Hybrid Identity Administrator | 21f072d5-eb54-452e-93de-3dcfebca1748 |
16 | Exchange Administrator | 2a2b54bf-a200-404c-8692-68691c401662 |
17 | Reports Reader | 2a69cf00-5226-4156-82e0-0f9e15642114 |
18 | Search Administrator | 3662bd4e-73cf-41e3-a8ac-72917f2fefe6 |
19 | SharePoint Administrator | 38de9f5f-e9bf-4bfd-8a55-6e9aca01b318 |
20 | Microsoft Hardware Warranty Administrator | 3e118278-7d7c-4392-8d45-555f645ff409 |
21 | Dynamics 365 Administrator | 43da951b-73e2-4db8-a52d-43ca76060a8f |
22 | External Identity Provider Administrator | 4455dfbe-e3b4-416b-9e72-f3523cfa99bb |
23 | Intune Administrator | 46ba74ec-0417-476d-a606-0e5a8abe553c |
24 | Attribute Definition Administrator | 48f7933f-f586-4ac3-bdfd-10335ece3730 |
25 | Directory Readers | 4b37053c-1a83-42f7-83b1-c9669ec0dd5e |
26 | Security Reader | 4c5a5dda-02ee-4ec2-b28a-a8a68fa0bf44 |
27 | Domain Name Administrator | 4d953343-72fa-4c79-af57-3d70680076fc |
28 | Printer Technician | 4e61eb18-aff9-4317-8393-e516496bec6e |
29 | Global Administrator | 50e9a13a-d631-4ffe-96e1-213a2d062292 |
30 | Attribute Definition Reader | 50f9bc21-538f-45c5-88aa-6427cbf6ee8a |
31 | Privileged Role Administrator | 5525e09a-1394-4631-ad13-4d42f5c13654 |
32 | Azure Information Protection Administrator | 5653b2fd-5eec-415b-b0a4-ff95ebc59ab8 |
33 | Message Center Reader | 5c3a6d0d-cfb3-4272-9e77-b6b91907f3a6 |
34 | B2C IEF Keyset Administrator | 5cb8bd27-68e4-47ce-b827-4c2b2f1f7b22 |
35 | Extended Directory User Administrator | 5e1d4964-b92d-482e-82af-67acbad6be01 |
36 | Compliance Administrator | 63992f23-9104-46d6-854a-c1de8d20e92f |
37 | Cloud Device Administrator | 64515973-240e-4199-8e0c-987dc63c6c67 |
38 | Teams Communications Support Specialist | 6495e6a6-2715-4a0a-98cb-23aff40604c1 |
39 | Directory Writers | 695df5e6-bdb8-4eac-b800-43d4f591fba5 |
40 | B2C IEF Policy Administrator | 6ac6a26b-ee0d-4a77-a11e-0bb37a1ef392 |
41 | Azure AD Joined Device Local Administrator | 6b7aa8f0-7b33-4c73-9cb8-5c2524eb937f |
42 | Network Administrator | 709597d6-299d-4890-9c26-c4cb3a2ca841 |
43 | Viva Goals Administrator | 71c5bc03-546c-4614-b98e-b4fbbf080644 |
44 | Cloud App Security Administrator | 72daa88e-f9ac-4157-b9c1-640716aa8c20 |
45 | External ID User Flow Attribute Administrator | 7e69e700-9dc3-40fb-93c9-dd008f0cf904 |
46 | Tenant Creator | 800f4fbe-eaad-4fbd-8354-d06e8ab3ce56 |
47 | Groups Administrator | 81b59aa8-da44-4b18-9732-7347e1e4c175 |
48 | Printer Administrator | 823fbb40-af27-402c-a1d8-88a4f5d9ff34 |
49 | Azure DevOps Administrator | 83c910c3-3530-4c9c-9365-e8c445ab2b69 |
50 | Organizational Messages Writer | 845ee3fd-6225-4f59-99c9-266ac76544e6 |
51 | User Administrator | 891f52da-adb4-4eba-b645-ed37bbac1f11 |
52 | Microsoft Hardware Warranty Specialist | 8ae3e709-b9dc-4029-ac48-a8ec75f5ae8d |
53 | Privileged Authentication Administrator | 8d5a4d54-79c9-44dc-b29a-fea249bb39f2 |
54 | Viva Pulse Administrator | 8fcd9373-e612-4310-9b60-fe36a33a3704 |
55 | Teams Administrator | 9796c49d-19a3-42f9-8729-886a4743ae97 |
56 | Global Reader | 996dd2d1-83c6-40cf-9b63-9d2ee0c82581 |
57 | Attribute Assignment Administrator | 9adaef55-6632-41a6-a38e-69014027f197 |
58 | Message Center Privacy Reader | 9af871f6-26fc-4075-abe7-e5d40a6bc48a |
59 | Desktop Analytics Administrator | 9f54c392-c4f7-43c2-8180-9762bcce325b |
60 | Security Operator | 9f60703f-7d68-4b1b-a0c5-fd1ee5692efd |
61 | Search Editor | a13d0704-c97d-42f3-b5e9-e5a721490cdc |
62 | Lifecycle Workflows Administrator | a28d0ff9-a6b8-4828-b2f9-6aa259161f27 |
63 | Application Developer | a3c3c495-846d-440e-b8c9-ac9f1f0a4b4a |
64 | Windows Update Deployment Administrator | a651122d-1417-4a2a-9723-b4d452034cb1 |
65 | Teams Communications Support Engineer | a6b333d1-de2a-42cb-8bc6-f7ec5df9f11f |
66 | Conditional Access Administrator | ab434954-92be-4e1e-b2ba-5689b606ec95 |
67 | Windows 365 Administrator | b00f3766-9fa3-4b13-9e2c-ea23fe4f4ed2 |
68 | Attack Simulation Administrator | b7aa3fc0-ee2e-4443-9b97-a6f9d05de2fb |
69 | License Administrator | b8790d00-4dfc-44b0-9d7a-7b2eb17816ec |
70 | Authentication Extensibility Administrator | b89a3e0c-8ea3-403f-91c6-3083c465e49e |
71 | Insights Business Leader | bb7dc0d3-7489-4ba8-a3a0-797490add6f9 |
72 | Power Platform Administrator | c4cb3c7d-a98b-4110-8c05-12ec8eeab861 |
73 | Insights Administrator | ca478cb2-c67b-40b3-974e-45664633a182 |
74 | Kaizala Administrator | cb39e494-1e93-472c-aec7-64adafaf16fe |
75 | Service Support Administrator | ce0d0715-d3ff-4df2-abe0-6ac96471ec58 |
76 | Teams Devices Administrator | ce515022-997c-41aa-a8d2-9bd49abfdcee |
77 | External ID User Flow Administrator | d08a35d4-c377-4141-9c5f-2403424f8d5f |
78 | Attribute Assignment Reader | d3e825d7-dadb-4829-8298-09bf382859f8 |
79 | Helpdesk Administrator | d8506869-0c9e-4e6c-971e-484c28bc3d7d |
80 | User Experience Success Manager | dc0922fb-f236-41dc-a71f-8d62d3e87c52 |
81 | Knowledge Manager | dc7a6a35-8503-406f-a991-9b79fd08e779 |
82 | Knowledge Administrator | dccf39d7-ce69-49ed-b74d-f2994f4f594b |
83 | Password Administrator | dce8b44e-e0b2-42fd-b332-1fa2ae3cf34f |
84 | Skype for Business Administrator | e3ecf083-3fce-46c8-9354-6bf54fb5e1af |
85 | Fabric Administrator | e3fd3acc-9d7b-415a-8239-d277eb0bf08d |
86 | Office Apps Administrator | e94161c7-46b9-463c-b6f8-4d961b6efec1 |
87 | Yammer Administrator | eb67b367-b746-426d-b2c4-095b444f94b0 |
88 | Teams Communications Administrator | ec832fda-7852-456b-b0ff-7548521f5724 |
89 | Customer LockBox Access Approver | ee00f06f-f880-406b-befc-333b64de0625 |
90 | Guest Inviter | f295f3e0-f01c-4402-b75e-4dca68f05aac |
91 | Global Secure Access Administrator | f36d911c-a98a-454f-9c58-322ce47e19ba |
92 | Billing Administrator | f500c28f-3604-4273-8365-c06d7ee4bb9f |
93 | Application Administrator | fa822aea-7d61-42ca-8075-7264f39731d5 |
94 | Attribute Log Reader | feaa6a48-e4e0-466e-8bed-3309f4ba32ee |
プログラムの実装
コンソールアプリケーションとして、ソリューション構成は下記で実装します。
Azure テナント情報は、appsettings.json
に記載します。このファイルを環境に合わせて更新してください。
{
"AzureAd": {
"ClientId": "insert ClientId here",
"TenantId": "insert TenantId here",
"ClientSecret": "insert ClientSecret here"
}
}
GraphServiceClient
と Csv登録するサービスクラス
を DI します。
using AzureEntraUserBulkImporter.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Graph;
using Microsoft.Identity.Client;
namespace AzureEntraUserBulkImporter.DI
{
#region [DIContainer]
/// <summary>
/// 依存性注入コンテナを提供するクラス。
/// アプリケーションのサービスと構成を管理します。
/// </summary>
public static class DIContainer
{
// サービスプロバイダーのインスタンス
private static ServiceProvider Provider;
// 構成設定のインスタンス
private static IConfiguration Configuration;
/// <summary>
/// 静的コンストラクタで構成とサービスを初期化します。
/// </summary>
static DIContainer()
{
InitConfiguration();
Provider = ConfigureServices();
}
/// <summary>
/// アプリケーションの構成を初期化します。
/// appsettings.json と環境変数から設定を読み込みます。
/// </summary>
private static void InitConfiguration()
{
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
/// <summary>
/// アプリケーションで利用するサービスを設定します。
/// ロギング、EntraID認証、カスタム認証プロバイダ、メインプロセスサービスを登録します。
/// </summary>
/// <returns>構成されたサービスプロバイダー</returns>
private static ServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
services.AddLogging(builder =>
{
builder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace)
.AddConfiguration(Configuration.GetSection("Logging"))
.AddConsole()
.AddDebug();
});
services.AddSingleton<IConfiguration>(Configuration);
services.Configure<EntraIdConfig>(Configuration.GetSection("AzureAd"));
// IConfidentialClientApplication の DI 登録
services.AddSingleton<IConfidentialClientApplication>(provider =>
{
var EntraIdConfig = provider.GetRequiredService<IOptions<EntraIdConfig>>().Value;
return ConfidentialClientApplicationBuilder
.Create(EntraIdConfig.ClientId)
.WithTenantId(EntraIdConfig.TenantId)
.WithClientSecret(EntraIdConfig.ClientSecret)
.Build();
});
// CustomAuthProvider の DI 登録
services.AddSingleton<CustomAuthProvider>();
// GraphServiceClient の DI 登録
services.AddSingleton<GraphServiceClient>(provider =>
{
var authProvider = provider.GetRequiredService<CustomAuthProvider>();
return new GraphServiceClient(authProvider);
});
// IMainProcessService の DI 登録
services.AddTransient<IMainProcessService, MainProcessService>();
return services.BuildServiceProvider();
}
/// <summary>
/// 指定された型のサービスインスタンスを取得します。
/// </summary>
/// <typeparam name="TService">取得するサービスの型</typeparam>
/// <returns>サービスのインスタンス</returns>
public static TService GetService<TService>()
{
return Provider.GetService<TService>();
}
}
#endregion
}
GraphServiceClient で利用するアクセストークンを取得するために、カスタム認証プロバイダーを実装します。
using Microsoft.Graph;
using Microsoft.Identity.Client;
using System.Net.Http;
using System.Threading.Tasks;
namespace AzureEntraUserBulkImporter.Services
{
/// <summary>
/// カスタム認証プロバイダー。
/// Microsoft Graph API へのリクエストにアクセストークンを提供します。
/// </summary>
public class CustomAuthProvider : IAuthenticationProvider
{
private IConfidentialClientApplication ClientApp;
/// <summary>
/// CustomAuthProvider の新しいインスタンスを初期化します。
/// </summary>
/// <param name="clientApp">認証に使用する IConfidentialClientApplication。</param>
public CustomAuthProvider(IConfidentialClientApplication clientApp)
{
this.ClientApp = clientApp;
}
/// <summary>
/// HTTPリクエストに認証情報を付与します。
/// </summary>
/// <param name="request">認証が必要な HTTPリクエスト。</param>
/// <returns>非同期操作</returns>
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
// アプリケーションのアクセストークンを取得
var authResult = await this.ClientApp.AcquireTokenForClient(new[] { "https://graph.microsoft.com/.default" }).ExecuteAsync();
// HTTPリクエストに認証ヘッダーを追加
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
}
}
}
Csvより情報を取得し、GraphServiceClient 経由で、Microsoft Entra ID へ登録します。
using AzureEntraUserBulkImporter.Models;
using Microsoft.Extensions.Options;
using Microsoft.Graph;
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AzureEntraUserBulkImporter.Services
{
#region IMainProcessService
/// <summary>
/// Azure EntraID へユーザー情報を一括登録するプロセスインタフェースクラス
/// </summary>
public interface IMainProcessService : IDisposable
{
/// <summary>
/// メインプロセスの実行を行います。
/// </summary>
/// <param name="cts">キャンセレーショントークンソース。プロセスのキャンセルに使用されます。</param>
/// <returns>非同期操作のタスク</returns>
public Task MainProcess(CancellationTokenSource cts);
}
#endregion
#region MainProcessService
/// <summary>
/// Azure EntraID へユーザー情報を一括登録するプロセス実装クラス
/// </summary>
public class MainProcessService : IMainProcessService
{
#region Variable・Const
private readonly EntraIdConfig EntraIdConfig;
private readonly IConfidentialClientApplication ConfidentialClientApplication;
private readonly GraphServiceClient GraphClient;
#endregion
#region Constructor
/// <summary>
/// MainProcessService の新しいインスタンスを初期化します。
/// </summary>
/// <param name="EntraIdConfig">EntraID の設定。</param>
/// <param name="confidentialClientApplication">EntraID との通信に使用するクライアントアプリケーション。</param>
/// <param name="graphClient">Microsoft Graph API へのリクエストを処理するクライアント。</param>
public MainProcessService(
IOptions<EntraIdConfig> EntraIdConfig,
IConfidentialClientApplication confidentialClientApplication,
GraphServiceClient graphClient)
{
this.EntraIdConfig = EntraIdConfig.Value;
this.ConfidentialClientApplication = confidentialClientApplication;
this.GraphClient = graphClient;
}
#endregion
#region Method
/// <summary>
/// Azure EntraID へユーザー情報を一括登録するプロセスを実行します。
/// </summary>
/// <param name="cts">キャンセレーショントークンソース。</param>
public async Task MainProcess(CancellationTokenSource cts)
{
Console.WriteLine("Press any key to start user registration.");
Console.ReadKey();
// ユーザー情報をCsvより取得
var userRegisterInfos = GetUsersToRegister();
foreach (var userRegisterInfo in userRegisterInfos)
{
try
{
// ユーザ属性情報
var user = new User
{
DisplayName = userRegisterInfo.DisplayName,
MailNickname = userRegisterInfo.MailNickname,
UserPrincipalName = userRegisterInfo.UserPrincipalName,
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = userRegisterInfo.Password
},
AccountEnabled = true
};
// 全ユーザを取得し、LINQで対象のユーザが存在するか確認
var users = await this.GraphClient.Users.Request().GetAsync();
var isExist = users.CurrentPage.Any(x => x.UserPrincipalName == user.UserPrincipalName);
if (isExist == true)
{
Console.WriteLine($"User: {user.UserPrincipalName} is already exist.");
continue;
}
// ユーザーを登録
var afterInfo = await this.GraphClient.Users.Request().AddAsync(user);
// 対象のロールを取得
var targetRole = await this.GraphClient.DirectoryRoles
.Request()
.Filter($"displayName eq '{userRegisterInfo.RoleName}'")
.GetAsync();
var targetRoleId = targetRole.CurrentPage.FirstOrDefault()?.Id;
// 対象のロールが見つかった場合、ユーザーをロールに追加
if (targetRoleId != null)
{
var directoryRoleAssignment = new DirectoryObject
{
Id = afterInfo.Id
};
await this.GraphClient.DirectoryRoles[targetRoleId].Members.References
.Request()
.AddAsync(directoryRoleAssignment);
}
Console.WriteLine($"User: {afterInfo.DisplayName}, {afterInfo.Mail} is registered.");
}
catch (ServiceException ex)
{
Console.WriteLine($"Error registering user or assigning role: {ex.Message}");
}
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
/// <summary>
/// Csvファイルからユーザー情報を取得します。
/// </summary>
/// <returns></returns>
private IEnumerable<UserData> GetUsersToRegister()
{
var csvFilePath = "UserCreate.csv"; // CSVファイルのパスを設定
return System.IO.File.ReadAllLines(csvFilePath)
.Skip(1) // ヘッダー行をスキップ
.Select(line => line.Split(','))
.Select(parts => new UserData
{
DisplayName = parts[0],
MailNickname = parts[1],
UserPrincipalName = parts[2],
Password = parts[3],
RoleName = parts[4]
});
}
#endregion
#region Dispose
private bool _isDisposed = false;
/// <summary>
/// 使用済みのリソースを解放します。
/// </summary>
public void Dispose()
{
if (this._isDisposed) return;
this._isDisposed = true;
}
#endregion
}
#endregion
}
実行すると下記のように登録結果が表示されます。
ユーザの追加が確認できます。
ロールも正常に付与されているようです。
まとめ
この記事では、C# を使用して Microsoft Entra ID へユーザ情報を一括で登録し、適切なロールを割り当てるプロセスを説明しました。Azure Portal を使わずにプログラムから直接操作するためには、サービスプリンシパルの設定、適切なAPIアクセス権限の付与が必要となります。
References
Discussion