PowerAutomate: Teamsで選択したTeamのメンバー一覧をCSVで出力する

# 背景

Teams で大量のメンバーがいる際に、特定のキーワードで検索した一覧が欲しい時があったので作ってみた。

# 概要

1. 選択したメッセージから起動することで、Team を選択<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/5b51bcf5-81a5-acec-121e-55b47e528817.png)
<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/fe50a0e7-cc02-5c96-29a8-8238b2bc4e54.png)

1. 出力したファイル名に付加する為、ID からTeam情報を取得
1. Trigger から、Rest API 用の Filter/取得上限を生成 
1. Graph API でメンバー一覧取得
1. CSV 生成
1. ファイルに保存して、リンクを取って
1. 起動した人にチャットでリンクを送付<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/cbdb2ee1-05a3-3afd-4a83-d483362719ba.png)


外観

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/6d444adc-d58c-b741-7995-164abd0e2b27.png)


# 詳細

躓きポイントは以下ぐらい？

## New Designer だと、For a selected message が現状未対応

ってことで、Old Designer に戻して作る必要がある

フローのコピーペーストも、New Designer ではまだ制約が大きいけど・・

## Graph API

1. API の使い方によっては使えない<br>
    - OK: https://graph.microsoft.com/v1.0/groups/{groupId}
    - <font color=red>NG: https://graph.microsoft.com/v1.0/groups('{groupId}')</font>
    どちらも、Graph Explorer なら問題ないのに・・　:sob: 
1. 検索方法
    - 以下で、Startswith なんかの例もあるので、よしなに


https://learn.microsoft.com/ja-jp/graph/api/group-list-members?view=graph-rest-1.0&tabs=http#example-4-use-searchand-odata-cast-to-get-user-membership-in-groups-with-display-names-that-contain-the-letters-pr-including-a-count-of-returned-objects

## サンプルコード

<summary>For a selected message adaptive card 例<details>

```json: adaptive card 

{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.4",
    "msteams": {
        "width": "full"
    },
    "body": [
        {
            "type": "TextBlock",
            "text": "このチームのメンバー一覧をCSVにして、OneDriveに保存します。",
            "weight": "Bolder",
            "size": "Medium",
            "color": "Attention"
        },
        {
            "type": "TextBlock",
            "text": "現状、人数は100人のままです。最大999。フィルター使おう",
            "wrap": true,
            "color": "Warning"
        },
        {
            "type": "Input.Text",
            "placeholder": "DisplayName に対してフィルターする文字を入れてください",
            "id": "FilterForDisplayName",
            "label": "Filter For DisplayName"
        },
        {
            "type": "Input.Number",
            "placeholder": "取得数上限を入れてください",
            "label": "取得メンバーの上限",
            "value": 100,
            "min": 1,
            "max": 999,
            "errorMessage": "メンバー上限を入れてください",
            "id": "MemberTopLImit"
        }
    ],
    "actions": [
        {
            "type": "Action.Submit",
            "title": "作成するぜ"
        }
    ]
}

```

</details></summary>

<summary>コード例<details>

```

{"id":"04e2d2b4-1d2f-4aaf-9495-46f974f30c4c","brandColor":"#8C3900","connectionReferences":{"shared_office365groups_1":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_office365groups/connections/5e96053ddc264f998e74dbe3ccf3ef9c"}},"shared_onedriveforbusiness_1":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_onedriveforbusiness/connections/shared-onedriveforbu-60023b13-318a-4e0f-a004-302d9501e437"}},"shared_teams":{"connection":{"id":"/providers/Microsoft.PowerApps/apis/shared_teams/connections/shared-teams-864099d5-54a7-4002-93b6-565ecf481128"}}},"connectorDisplayName":"Control","icon":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDMyIDMyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KIDxwYXRoIGQ9Im0wIDBoMzJ2MzJoLTMyeiIgZmlsbD0iIzhDMzkwMCIvPg0KIDxwYXRoIGQ9Im04IDEwaDE2djEyaC0xNnptMTUgMTF2LTEwaC0xNHYxMHptLTItOHY2aC0xMHYtNnptLTEgNXYtNGgtOHY0eiIgZmlsbD0iI2ZmZiIvPg0KPC9zdmc+DQo=","isTrigger":false,"operationName":"Scope","operationDefinition":{"type":"Scope","actions":{"Get_a_team":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_teams","operationId":"GetTeam","apiId":"/providers/Microsoft.PowerApps/apis/shared_teams"},"parameters":{"teamId":"@triggerBody()?['teamsFlowRunContext']?['channelData']?['team']?['aadGroupId']"},"authentication":{"type":"Raw","value":"@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"}},"runAfter":{},"metadata":{"operationMetadataId":"c6661b5a-064a-4019-a310-d3e71cd381e9"}},"Compose_Filter":{"type":"Compose","inputs":"@if(empty(triggerBody()?['cardOutputs']?['filterForDisplayName']), '', concat('&$search=\"displayName:', encodeUriComponent(triggerBody()?['cardOutputs']?['filterForDisplayName']), '\"'))","runAfter":{"Get_a_team":["Succeeded"]},"metadata":{"operationMetadataId":"ebd22013-9d6d-4dbc-963b-cb4dc4d13877"}},"Select":{"type":"Select","inputs":{"from":"@body('Send_an_HTTP_request_V2')['value']","select":{"UserPrincipalName":"@item()['userPrincipalName']","Displayname":"@item()['displayName']","SurName":"@item()['surName']","GivenName":"@item()['givenName']","Mail":"@item()['mail']"}},"runAfter":{"Send_an_HTTP_request_V2":["Succeeded"]},"metadata":{"operationMetadataId":"41e64b55-f8fd-463a-93a3-8d28cc641689"}},"Create_CSV_table":{"type":"Table","inputs":{"from":"@body('Select')","format":"CSV"},"runAfter":{"Select":["Succeeded"]},"metadata":{"operationMetadataId":"abf5d606-c041-4016-a480-834e3db4595e"}},"Create_file":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_onedriveforbusiness_1","operationId":"CreateFile","apiId":"/providers/Microsoft.PowerApps/apis/shared_onedriveforbusiness"},"parameters":{"folderPath":"/FlowCreated/MembersCsvs","name":"MembersOf@{outputs('Get_a_team')?['body/displayName']}@{if(empty(triggerBody()?['cardOutputs']?['filterForDisplayName']), '', concat('_filteredBy', triggerBody()?['cardOutputs']?['filterForDisplayName']))}_@{body('Convert_time_zone')}.csv","body":"@concat(uriComponentToString('%EF%BB%BF'), body('Create_CSV_table'))"},"authentication":{"type":"Raw","value":"@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"}},"runAfter":{"Convert_time_zone":["Succeeded"]},"runtimeConfiguration":{"contentTransfer":{"transferMode":"Chunked"}},"metadata":{"operationMetadataId":"0e9137cb-6ae5-4071-b6fb-847b34dd5e1b"}},"Create_share_link":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_onedriveforbusiness_1","operationId":"CreateShareLinkV2","apiId":"/providers/Microsoft.PowerApps/apis/shared_onedriveforbusiness"},"parameters":{"id":"@outputs('Create_file')?['body/Id']","type":"View","scope":"Organization"},"authentication":{"type":"Raw","value":"@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"}},"runAfter":{"Create_file":["Succeeded"]},"metadata":{"operationMetadataId":"70570745-93cf-4459-932c-818f1ea9c9a6"}},"Post_message_in_a_chat_or_channel":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_teams","operationId":"PostMessageToConversation","apiId":"/providers/Microsoft.PowerApps/apis/shared_teams"},"parameters":{"poster":"Flow bot","location":"Chat with Flow bot","body/recipient":"@{triggerBody()?['teamsFlowRunContext']?['from']?['aadObjectId']};","body/messageBody":"<p>@{outputs('Compose')}</p>"},"authentication":{"type":"Raw","value":"@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"}},"runAfter":{"Compose":["Succeeded"]},"metadata":{"operationMetadataId":"a64b0116-38fd-428e-96bc-0d10d223d607"}},"Compose_Top":{"type":"Compose","inputs":"@if(empty(string(triggerBody()?['cardOutputs']?['memberTopLImit'])), '', concat('&$top=', string(triggerBody()?['cardOutputs']?['memberTopLImit'])))","runAfter":{"Compose_Filter":["Succeeded"]},"metadata":{"operationMetadataId":"c2061e77-2380-49f7-b2e0-a646de2856af"}},"Send_an_HTTP_request_V2":{"type":"OpenApiConnection","inputs":{"host":{"connectionName":"shared_office365groups_1","operationId":"HttpRequestV2","apiId":"/providers/Microsoft.PowerApps/apis/shared_office365groups"},"parameters":{"Uri":"https://graph.microsoft.com/v1.0/groups/@{triggerBody()?['teamsFlowRunContext']?['channelData']?['team']?['aadGroupId']}/members/microsoft.graph.user?$count=true&$orderBy=displayName&$select=displayName,givenName,jobTitle,mail,surname,userPrincipalName,id,userPrincipalName@{outputs('Compose_Filter')}@{outputs('Compose_Top')}","Method":"GET","ContentType":"application/json","CustomHeader1":"ConsistencyLevel: eventual"},"authentication":{"type":"Raw","value":"@json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$ConnectionKey']"}},"runAfter":{"Compose_Top":["Succeeded"]},"metadata":{"operationMetadataId":"a37d42b1-e6c0-465d-ad8a-b40a70b17435"}},"Current_time":{"type":"Expression","kind":"CurrentTime","inputs":{},"runAfter":{"Create_CSV_table":["Succeeded"]},"metadata":{"operationMetadataId":"021254d1-b987-4877-b8c0-1012507b1b66"}},"Convert_time_zone":{"type":"Expression","kind":"ConvertTimeZone","inputs":{"baseTime":"@body('Current_time')","formatString":"yyyyMMdd","sourceTimeZone":"UTC","destinationTimeZone":"Tokyo Standard Time"},"runAfter":{"Current_time":["Succeeded"]},"metadata":{"operationMetadataId":"a9021c08-f59a-4342-af79-3dbc8f21b191"}},"Compose":{"type":"Compose","inputs":"<p><a href=\"@{outputs('Create_share_link')?['body/WebUrl']}\">@{outputs('Create_file')?['body/Name']}</a></p>","runAfter":{"Create_share_link":["Succeeded"]},"metadata":{"operationMetadataId":"4088f3b5-cdce-44ee-ac03-e91270e3a1ea"}}},"runAfter":{},"metadata":{"operationMetadataId":"63f93a96-4357-49c5-8d54-b86d0cbac008"}}}

```

</details></summary>



# あとがき

GraphAPI は便利なんだけど、Automate で使うと制約に意外に躓くのがたまにきず

実装コードって公開されてたら見に行きたいぐらい・・ってあるん？ :thinking: