【C#】M365のプロフィール写真を取得する(テナント全員分)

  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る

そんな事する機会あるのかよって思ったらありました、別システムに全員分の顔写真を連携する必要が出てきました。

やりたい事としてはM365に設定されている顔写真を全員分取得になります。

単発でユーザー指定して写真を取得する事は世間的にあるようですが、今回のように全員分となるとやってる人なんてそうそういないので自分で考えるしかないです。

幸いにも断片的には情報があるのでそれを繋げれば。

そしてRestAPIかぁ・・・

まずは写真の取得方法、ヘルプにあります。

Microsoft Graphを使う事になります。

https://docs.microsoft.com/ja-jp/graph/api/profilephoto-get?view=graph-rest-1.0

なるほど、結果がメタデータとバイナリで返ってくるみたいです。
早速PoweShellで・・・

RestAPIからのバイナリデータってどうやって保存すればいいんだ・・・?

色々頭が足りてないのでC#に切り替えて、FileStreamで保存したらいけた!


で、全員分なのでユーザー一覧から取得していけばいいのかなと思い・・・

ユーザーの一覧の取得方法はこんな感じです。

https://docs.microsoft.com/ja-jp/graph/api/user-list?view=graph-rest-1.0&tabs=http

でもユーザー一覧はRestAPIから実行したら、目的のユーザーアカウントへのアクセスができない・・・

調べてみるとライブラリが別途あるよって、でもこっちじゃ写真の取得ができないじゃんうわぁぁあじゃあ両方使っちゃえってなって色々やってみると・・・

まとめるとこんな感じに


static void Main(string[] args)
{
    //認証情報
    string tenantId = ConfigurationManager.AppSettings["tenantId"].ToString();
    string resource = ConfigurationManager.AppSettings["resource"].ToString();
    string clientID = ConfigurationManager.AppSettings["clientID"].ToString();
    string clientsecret = ConfigurationManager.AppSettings["clientsecret"].ToString();
    string authUrl = ConfigurationManager.AppSettings["authUrl"].ToString();
    string OutDir = ConfigurationManager.AppSettings["OutDir"].ToString();


    //ユーザー一覧の取得
    Task<IGraphServiceUsersCollectionPage> rts = Get_Users(clientID, tenantId, clientsecret);
    IGraphServiceUsersCollectionPage rt = rts.Result;

    //認証
    AuthenticationContext authContext = new AuthenticationContext(authUrl, false);
    Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential clientCred = new Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential(clientID, clientsecret);
    Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult authResult = authContext.AcquireTokenAsync(resource, clientCred).Result;

    int LCntr = 0;

    for (int cntr = 0; cntr <= rt.CurrentPage.Count - 1; cntr++)
    {
        //画像データの取得
        //HTTPリクエストとバイナリデータの取得
        Task<HttpResponseMessage> Httpresult = Run(authResult.AccessToken, rt.CurrentPage[cntr].UserPrincipalName);
        HttpResponseMessage rs = Httpresult.Result;
        byte[] bs = null;
        bs = rs.Content.ReadAsByteArrayAsync().Result;

        if (rs.StatusCode == HttpStatusCode.OK)
        {
            //バイナリデータの保存
            using (System.IO.FileStream fs = new System.IO.FileStream(
                OutDir + rt.CurrentPage[cntr].UserPrincipalName + ".jpg",
                System.IO.FileMode.Create,
                System.IO.FileAccess.Write))
            {
                fs.Write(bs, 0, bs.Length);
            }
        }

        //最終ループで次ページが存在する場合に次のページに遷移
        if (cntr == rt.CurrentPage.Count - 1 && rt.NextPageRequest != null)
        {
            rts = rt.NextPageRequest.GetAsync();
            rt = rts.Result;
            cntr = -1;
            authResult = authContext.AcquireTokenAsync(resource, clientCred).Result;
        }
        LCntr = LCntr + 1;
    }
}


public static async Task<IGraphServiceUsersCollectionPage> Get_Users(string clientID, string tenantId, string clientsecret)
{
    IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
        .Create(clientID)
        .WithTenantId(tenantId)
        .WithClientSecret(clientsecret)
        .Build();

    IAuthenticationProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);

    GraphServiceClient graphClient = new GraphServiceClient(authProvider);

    return await graphClient.Users.Request().GetAsync();
}


public static async Task<HttpResponseMessage> Run(string graphToken, string ID)
{
    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", graphToken);
    return await client.GetAsync("https://graph.microsoft.com/v1.0/users/" + ID + "/photo/$value");
}
  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る

SNSでもご購読できます。