0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PowerAutomate:会話チャットをTeamsチャネルにクロステナント移行する

0
Last updated at Posted at 2026-06-17

きっかけ

出向先の会社合併に伴い、新会社ではM365ライセンスが別テナント発行され、現会社のTeams情報は移行されない(必要なら自力移行すべし)とアナウンスがありました。
全会話チャットの移行は厳しいにしても、対象チャットを限定し、最低限残したい項目に絞って移行したいと考え、フローを作成しました。

元々は Teamsチャネル移行 を先行して対応してましたが、会話チャット移行もあったらいいと考え、Teamsチャネル移行を加工して作ったので、一部無駄処理があるかもです💦

このフローをつくると…

会話チャットを以下条件でTeamsチャネルにメッセージ移行できます。

  • 移行メッセージの最大件数は500件
    →上限ページ数変数を変えればそれ以上に変更可能だが、オンメモリ処理が多いので限界値は大きくないかも…
  • 移行先Teamsチャネルの投稿者はPowerAutomate実行者名となるが、メッセージ冒頭に移行元メッセージの投稿者・投稿日時を記載
    →投稿者やメンション、リアクションなどユーザに紐づく情報は移行されない
  • 添付ファイルは移行先TeamsのSharePoint(/Shared Documents/移行先チャネル名フォルダ配下)に移行
    →移行されないメッセージやメッセージ添付されない共有ファイルは移行されない
    →添付ファイル容量の上限は100MB程度(PowerAutomateの上限はそれより小さいかも)、移行できない場合はエラーメッセージを表記
  • メッセージ添付画像はメッセージ内包データ(HostedContents)として埋め込み
    →メッセージデータのHostedContents含めたペイロード最大容量は4MBのため、順次処理で4MBを超えた以降のファイルは移行されずエラーメッセージを表記
  • 引用メッセージは引用元メッセージが移行されれば引用情報(MessageReference)として移行
    →引用メッセージが移行できなかった場合はエラーメッセージを表記
  • その他、上記に記載のない情報は移行されない

なお、クロステナントの場合、PowerAutomateフローは移行元で実行、移行先にも接続できる前提です。クロステナントでなく、同一テナント内でも移行可能です。

<移行イメージ>
import_demo_chat.gif

移行イメージのデータはCopilotに以下指示をしてサンプルデータ作成してます。

以下のフォーマットで試験データを作成してください。
・レコード項目はid(3桁数字)、replyToId(null固定)、subject(null固定)、user(架空日本人名)、body(日本語、HTML形式)、createdDateTime(yyyy/MM/dd HH:mm形式)、attachments([]固定)
・レコード数は30件、通信業界をテーマとしたディスカッション
・本文に実在するURLリンク(正しいAタグ形式)を加えたものを混ぜ、20文字~50文字、1~2行程度とする

移行先Teamsチャネルのレイアウトを「スレッド」形式にしたイメージです。

フロー全体像

構成は以下の通りです。

①トリガ設定

移行時に手動実行します。

②変数初期化

(変数)『変数を初期化する』で以下10個の変数を設定します。

名前 種類 初期値/補足
移行元チャットURL 文字列 Teamsの該当チャット:3点メニューの「リンクのコピー」の値(https://teams.microsoft.com/l/chat/XXXXXXXXXXXXXXXX/conversations?context=%7B%22contextType%22%3A%22chat%22%7D
移行先Team名 文字列 Teams:Teamsとチャネルに表示されるTeam名、またはTeam ID
移行先チャネル名 文字列 Teams:Teamsとチャネルに表示される該当Team配下のチャネル名、またはチャネルID
上限ページ数 整数 10(1ページあたりメッセージ50件取得、10の場合は500件となる)
メッセージ配列 アレイ (空値)
画像配列 アレイ (空値)
添付配列 アレイ (空値)
前後メッセージIDオブジェクト オブジェクト {}(空オブジェクト)
テンポラリ文字列 文字列 (空値)
テンポラリ変数 整数 (空値)

Teamsチャネル移行 との違いは以下の通りです。

  • 変数定義が「移行元チャットURL」か「移行元Team名/チャネル名」
  • 上限ページ数の値(チャネル移行はリプライ200件が含まれるため値を小さくしている)

③スコープ1:移行先設定

Teamsチャネル移行 のスコープ1と同じ処理です。


③-1) 移行先チーム一覧表示

(Microsoft Teams)『参加済みチームをリストする』で自身が所属するTeamsチーム一覧を取得します。

クロステナント移行する場合、三点メニューの接続参照で接続先を移行先に変更します


③-2) 移行先Team抽出

(データ操作)『アレイのフィルター処理』で以下パラメータを設定し、表示名またはチームIDで指定されたチーム情報を抽出します。

  • 差出人: @outputs('移行先チーム一覧表示')?['body/value']
  • 条件:(式)@or(contains(item()?['displayName'], variables('移行先Team名')),contains(item()?['id'], variables('移行先Team名')))

③-3) 移行先Team抽出結果=1件?

(コントロール)『条件』で「③-2) 移行先Team抽出」が1件かを判定します。

  • 左辺: (式)length(body('移行先Team抽出'))
  • 条件:次の値に等しい
  • 右辺: (値)1

③-4) 失敗(移行先Team名不正)

(コントロール)『終了』で処理を停止します。

  • 状態:失敗
  • メッセージ:移行先Team名(@{variables('移行先Team名')})が正しくありません

③-5) 移行先チャネル一覧表示

(Microsoft Teams)『チームの取得』で指定チーム情報を取得します。

  • チーム:(カスタム値の入力)@body('移行先Team抽出')?[0]?['id']

クロステナント移行する場合、三点メニューの接続参照で接続先を移行先に変更します


③-6) 移行先チャネル抽出

(データ操作)『アレイのフィルター処理』で以下パラメータを設定し、表示名またはチャネルIDで指定されたチャネル情報を抽出します。

  • 差出人: @outputs('移行先チャネル一覧表示')?['body/value']
  • 条件:(式)@or( contains(item()?['id'], variables('移行先チャネル名')), contains(item()?['displayName'], variables('移行先チャネル名')), contains(item()?['displayName'], if(equals(variables('移行先チャネル名'),'一般'),'General',variables('移行先チャネル名'))) )

③-7) 移行先チャネル抽出結果=1件?

(コントロール)『条件』で「③-6) 移行先チャネル抽出」が1件かを判定します。

  • 左辺: (式)length(body('移行先チャネル抽出'))
  • 条件:次の値に等しい
  • 右辺: (値)1

③-8) 失敗(移行先チャネル名不正)

(コントロール)『終了』で処理を停止します。

  • 状態:失敗
  • メッセージ:移行先チーム(@{variables('移行先Team名')})に指定チャネル(@{variables('移行先チャネル名')})がありません

③-9) HTTP要求:指定TeamIDのグループ詳細を取得

(Office365 Group)『HTTP 要求 V2 を送信する』で以下パラメータを設定し、SharePointサイト情報を取得します。

パラメータ名
URI https://graph.microsoft.com/v1.0/groups/@{body('移行先Team抽出')?[0]?['id']}/sites/root
メソッド GET
本文
コンテンツの種類 application/json

クロステナント移行する場合、三点メニューの接続参照で接続先を移行先に変更します


③-10) 移行先SharePointURL作成

(データ操作)『作成』で経過日数をふまえた日付変数を作成します。

  • 入力:@outputs('HTTP要求:指定TeamIDのグループ詳細を取得')?['body']?['webUrl']

③-11) すべてのリストとライブラリを取得

(SharePoint)『すべてのリストとライブラリを取得』で「③-10) 移行先SharePointURL作成」のライブラリを取得します。

  • サイトのアドレス:@outputs('移行先SharePointURL作成')

クロステナント移行する場合、三点メニューの接続参照で接続先を移行先に変更します


③-12) ライブラリ情報抽出

(データ操作)『アレイのフィルター処理』で以下パラメータを設定し、表示名がドキュメントのデータを抽出します。

  • 差出人: @outputs('すべてのリストとライブラリを取得')?['body/value']
  • 左辺: (式)@item()?['DisplayName']
  • 条件:次の値に等しい
  • 右辺: (値)ドキュメント

スコープ2:移行データ抽出

本スコープ2 ④-2~9、10~13とTeamsチャネル移行 のスコープ2 ④-9~16、23~26の実装は同じです(Teams Graph APIのタイトルは異なる)。


④-1) チャットID作成

(データ操作)『作成』で変数「移行元チャットURL」からチャットIDを作成します。

  • 入力:first(split(last(split(variables('移行元チャットURL'),'/chat/')),'/'))

④-2) テンポラリ変数の設定(ページカウンタリセット)

(変数)『変数の設定』でテンポラリ変数をリセット設定します。

  • 値:0

④-3) テンポラリ文字列の設定(メッセ―ジ取得URL)

(変数)『変数の設定』でテンポラリ変数にメッセージ取得Graph APIのURLを設定します。

  • 式:https://graph.microsoft.com/v1.0/me/chats/@{outputs('チャットID作成')}/messages?$top=50

④-4) テンポラリ変数<最大ページ数で繰り返し

(コントロール)『Do Until』で抽出した空き会議室配列を繰り返し処理します

  • 左辺: (式)@variables('テンポラリ変数')
  • 条件:次の値以上
  • 右辺: (式)@ variables('上限ページ数')

④-5) HTTP要求:Teamsチャットメッセージ一覧取得

(Microsoft Teams)『Microsoft Graph HTTP 要求を送信する』で以下パラメータを設定し、指定チャットのメッセージ一覧を取得します。

パラメータ名
URI @{variables('テンポラリ文字列')}
メソッド GET
本文
コンテンツの種類 application/json

④-6) メインスレッド選択

(データ操作)『選択』で、「④-5) HTTP要求:Teamsチャットメッセージ一覧取得」の応答値を指定マップに選択します。

  • 開始:(式)@{body('HTTP要求:Teamsチャットメッセージ一覧取得')?['value']}
  • マップ:以下参照
パラメータ名
id @item()?['id']
replyToId @null
subject @null
createdDateTime @convertFromUtc(item()?['​createdDateTime'],'Tokyo Standard Time','yyyy/MM/dd HH:mm')
user @first(split(if(equals(item()?['from']?['user']?['displayName'],null),'',item()?['from']?['user']?['displayName']),'('))
body @item()?['body']?['content']
attachments @item()?['attachments']

④-7) 本文なしメインスレを除外抽出

(データ操作)『アレイのフィルター処理』で「④-6) メインスレッド選択」のうち、本文が設定されたデータを抽出します。

  • 差出人: @body('メインスレッド選択')
  • 条件:@and(not(equals(length(if(equals(item()?['body'],null),'',item()?['body'])), 0)),not(equals(if(equals(item()?['body'],null),'',item()?['body']), '<systemEventMessage/>')))

詳細設定モードで編集します


④-8) 今回取得分と取得済みデータの結合作成

(データ操作)『作成』で「④-7) 本文なしメインスレを除外抽出」を逆順にした配列とメッセージ配列の結合配列を作成します。

  • 値:@union(reverse(body('本文なしメインスレを除外抽出')),variables('メッセージ配列'))

④-9) メッセージ配列にメインスレッドを設定

(変数)『変数の設定』でメッセージ配列に「④-8) 今回取得分と取得済みデータの結合作成」の値を設定します。

  • 式:@{outputs('今回取得分と取得済みデータの結合作成')}

④-10) 次ページリンクあり?

(コントロール)『条件』で「④-5) HTTP要求:Teamsチャットメッセージ一覧取得」に次ページリンクの値が設定されてるかを判定します。

<And条件1>

  • 左辺: (式)@body('HTTP要求:Teamsチャットメッセージ一覧取得')
  • 条件:次の値を含む
  • 右辺: (式)concat(decodeUriComponent('%40'),'odata.nextLink')

④-11) テンポラリ文字列を設定(次ページURL)

(変数)『変数の設定』で「テンポラリ文字列」にGraph APIの次ページリンクURLを設定します。

  • 式:@{body('HTTP要求:Teamsチャットメッセージ一覧取得')?[concat(decodeUriComponent('%40'),'odata.nextLink')]}

④-12) テンポラリ変数を設定(上限ページ)

(変数)『変数の設定』で「テンポラリ変数」を上限ページ数に設定します。

  • 式:@{variables('上限ページ数')}

④-13) テンポラリ変数インクリメント

(変数)『変数の値を増やす』で「テンポラリ変数」を1増やします。

  • 値:1

⑤スコープ3:画像データ抽出

Teamsチャネル移行 のスコープ3と同じ処理です。


⑤-1) 画像あり投稿の抽出

(データ操作)『アレイのフィルター処理』で以下パラメータを設定し、画像タグを含む本文を抽出します。

  • 差出人: @variables('メッセージ配列')
  • 左辺: (式)indexOf(item()?['body'], '<img ')
  • 条件:次の値より大きい
  • 右辺: (値)0

⑤-2) 画像あり投稿で繰り返し

(コントロール)『それぞれに適用する』で抽出した画像タグありメッセージを繰り返し処理します。

  • 出力選択: @{body('画像あり投稿の抽出')}

⑤-3) テンポラリ変数リセット

(変数)『変数の設定』でテンポラリ変数をリセット設定します。

  • 値:0

⑤-4) imgタグ選択

(データ操作)『選択』で、メッセージ本文に含まれる画像タグを抜き出し選択します。

  • 開始:(式)@{skip(split(item()?['body'],'<img '),1)}
  • マップ:@concat('<img ',substring(item(),0,add(indexOf(item(),'>'),1)))

マップをテキストモードに切り替えて入力します


⑤-5) imgタグで繰り返し

(コントロール)『それぞれに適用する』で抽出したimgタグを繰り返し処理します。

  • 出力選択: @{body('imgタグ選択')}

⑤-6) 画像index作成

(データ操作)『作成』で画像配列内の連番を作成します。

  • 値:@{add(length(variables('画像配列')),1)}

⑤-7) 画像URL作成

(データ操作)『作成』でimgタグ内のsrc属性の値を抽出作成します。

  • 値:@{replace(substring(last(split(item(),'src="')),0,indexOf(last(split(item(),'src="')),'"')),'/chats/','/me/chats/')}

チャット貼付画像はそのままのURLではGraph APIで画像データ取得できないため、url内に「/chats/」が含まれる場合、「/me/chats/」に置換します。


⑤-8) HTTP要求:画像取得

(Office365 Group)『HTTP 要求 V2 を送信する』で「⑤-7) 画像URL作成」の画像データを取得します。

パラメータ名
URI @{outputs('画像URL作成')}
メソッド GET
本文
コンテンツの種類 application/json

⑤-9) 画像取得OK?

(コントロール)『条件』で「⑤-8) HTTP要求:画像取得」の応答が正常か判定します。

<And条件1>

  • 左辺: (式)@body('HTTP要求:画像取得')
  • 条件:次の値に等しくない
  • 右辺: (式)null

<And条件2>

  • 左辺: (式)@body('HTTP要求:画像取得')?['$content-type']
  • 条件:次の値に等しくない
  • 右辺: (式)null

前段処理が失敗した場合も処理されるよう三点メニュー→「実行条件の構成」で「に失敗しました」、「がタイムアウトしました」にもチェックを入れます。

⑤-10) テンポラリ変数閾値以内?

(コントロール)『条件』でテンポラリ変数に取得画像容量を加算した値が4,000,000Byte(≒4MB)以下か判定します。

  • 左辺: (式)add(variables('テンポラリ変数'),length(body('HTTP要求:画像取得')?['$content']))
  • 条件:次の値以下
  • 右辺: (値)4000000

Graph API:Teamsメッセージ送信は全体ペイロードが4MB(4,194,304Byte)を超えるとエラーになります。添付ファイル以外の情報も含まれるため、ここでの条件は4,000,000Byteにしています。


⑤-11) 画像配列に追加

(変数)『配列変数に追加』で「画像配列」に以下オブジェクトを追加します。

  • 値:{ "messageId": @{items('画像あり投稿で繰り返し')?['id']}, "imgTag": "@{items('imgタグで繰り返し')}", "@{decodeUriComponent('%40')}microsoft.graph.temporaryId": "@{outputs('画像index作成')}", "contentType": "@{body('HTTP要求:画像取得')?['$content-type']}", "contentBytes": "@{body('HTTP要求:画像取得')?['$content']}" }

⑤-12) テンポラリ変数を増やす

(変数)『変数の値を増やす』でテンポラリ変数に取得した画像容量を増やします。

  • 式:length(body('HTTP要求:画像取得')?['$content'])

⑥スコープ4:添付ファイル

スコープ4追加時はスコープ2の下の+メニューで「並列分岐の追加」を選択します。

Teamsチャネル移行 のスコープ4と同じ処理です。


⑥-1) 添付ありメッセージ抽出

(データ操作)『アレイのフィルター処理』で以下パラメータを設定し、添付ファイル(Attachement属性)を含むメッセージを抽出します。

  • 差出人: @variables('メッセージ配列')
  • 左辺: (式)length(item()?['attachments'])
  • 条件:次の値より大きい
  • 右辺: (値)0

⑥-2) 添付メッセージで繰り返し

(コントロール)『それぞれに適用する』で抽出した添付ありメッセージを繰り返し処理します。

  • 出力選択: @{body('添付ありメッセージ抽出')}

⑥-3) attachmentタグで繰り返し

(コントロール)『それぞれに適用する』で抽出した添付データ(attachments)を繰り返し処理します。

  • 出力選択: @{items('添付メッセージで繰り返し')?['attachments']}

⑥-4) サイトコンテンツ?

(コントロール)『条件』で添付データのContent-Typeがreference、かつパス第2階層が指定値かを判定します。

<And条件1>

  • 左辺: (式)@items('attachmentタグで繰り返し')?['contentType']
  • 条件:次の値に等しい
  • 右辺: (値)reference

<And条件2>

  • 左辺: (式)@createArray('sites','personal')
  • 条件:次の値を含む
  • 右辺: (式)split(item()?['contentUrl'],'/')?[3]

Content-Type=MessageReference(引用)はここでは加工しません。


⑥-5) 移行元ファイルコンテンツの取得

(SharePoint)『ファイル コンテンツの取得』で移行元サイトアドレスのコンテンツを取得します。

  • サイトのアドレス:(式)@join(take(split(item()?['contentUrl'],'/'),5),'/')
  • ファイル識別子:(式)@encodeUriComponent(concat('/',decodeUriComponent(join(skip(split(item()?['contentUrl'],'/'),5),'/'))))

⑥-6) コンテンツ取得正常?

(コントロール)『条件』で「⑥-5) 移行元ファイルコンテンツの取得」が正常応答、かつファイル容量が100MB以下かを判定します。

<And条件1>

  • 左辺: (式)@outputs('移行元ファイルコンテンツの取得')?['statusCode']
  • 条件:次の値に等しい
  • 右辺: (式)200

<And条件2>

  • 左辺: (式)@outputs('移行元ファイルコンテンツの取得')?['body/$content']
  • 条件:次の値に等しくない
  • 右辺: (式)null

<And条件3>

  • 左辺: (式)int(outputs('移行元ファイルコンテンツの取得')?['headers/Content-Length'])
  • 条件:次の値以下
  • 右辺: (値)100000000

前段処理が失敗した場合も処理されるよう三点メニュー→「実行条件の構成」で「に失敗しました」、「がタイムアウトしました」にもチェックを入れます。


⑥-7) 移行先ファイルの作成

(SharePoint)『ファイルの作成』で移行先SharePointに「⑥-5) 移行元ファイルコンテンツの取得」のファイルを作成します。

  • サイトのアドレス:(式)outputs('移行先SharePointURL作成')
  • フォルダパス:/Shared Documents/(式)body('移行先チャネル抽出')?[0]?['displayName']
  • ファイル名:(式)items('attachmentタグで繰り返し')?['name']
  • ファイルコンテンツ:(式)base64ToBinary(body('移行元ファイルコンテンツの取得')?['$content'])
  • OverWrite:(値)いいえ

⑥-8) 移行先ファイルメタデータの取得

(SharePoint)『パスによるファイルメタデータの取得』で移行先SharePointファイルのメタデータを取得します。

  • サイトのアドレス:(式)outputs('移行先SharePointURL作成')
  • ファイルパス:(式)decodeUriComponent(concat('/Shared Documents/',body('移行先チャネル抽出')?[0]?['displayName'],'/',item()?['name']))

前段処理が失敗した場合も処理されるよう三点メニュー→「実行条件の構成」で「に失敗しました」、「がタイムアウトしました」にもチェックを入れます。


⑥-9) 移行先ファイル共有リンクの作成

(SharePoint)『ファイルまたはフォルダーの共有リンクの作成』で移行先SharePointのファイル共有リンクを作成します。

  • サイトのアドレス:(式)outputs('移行先SharePointURL作成')
  • ライブラリ名:(式)body('ライブラリ情報抽出')?[0]?['Name']
  • 項目ID:(式)outputs('移行先ファイルメタデータの取得')?['body/ItemId']
  • リンクの種類:View and edit
  • リンクスコープ:People in your organization

前段処理が失敗した場合も処理されるよう三点メニュー→「実行条件の構成」で「に失敗しました」、「がタイムアウトしました」にもチェックを入れます。

⑥-10) 共有リンク作成正常?

(コントロール)『条件』で「⑥-9) 移行先ファイル共有リンクの作成」の値が設定されているかを判定します。

  • 左辺: (式)outputs('移行先ファイル共有リンクの作成')?['body/link/webUrl']
  • 条件:次の値に等しくない
  • 右辺: (式)null

前段処理が失敗した場合も処理されるよう三点メニュー→「実行条件の構成」で「に失敗しました」、「がタイムアウトしました」にもチェックを入れます。


⑥-11) 添付配列に追加

(変数)『配列変数に追加』で「添付配列」に添付データオブジェクトを追加します。

  • 式:{ "messageId": @{items('添付メッセージで繰り返し')?['id']}, "attachmentId": "@{items('attachmentタグで繰り返し')?['id']}", "contentUrl": "@{outputs('移行先ファイル共有リンクの作成')?['body/link/webUrl']}" }

⑦スコープ5:移行先Teamsへの投稿

スコープ5追加時は最下部の「+新しいステップ」ボタンからアクション追加し、スコープ3-4を合流させます。

Teamsチャネル移行 のスコープ5はリプライ処理が加わるため、実装内容が異なります。


⑦-1) メッセージ配列で繰り返し

(コントロール)『それぞれに適用する』で「メッセージ配列」で繰り返し処理します。

  • 出力選択: @{variables('メッセージ配列')}

⑦-2) テンポラリ文字列に本文仮設定

(変数)『変数の設定』で「テンポラリ文字列」にメッセージ本文を設定します。

  • 式:@{items('メッセージ配列で繰り返し')?['body']}

⑦-3) emojiタグ選択

(データ操作)『選択』で「テンポラリ文字列」からemojiタグを抽出します。

  • 開始:(式)@{skip(split(variables('テンポラリ文字列'),'<emoji'),1)}
  • マップ:@concat('<emoji',first(split(item(),'/emoji>')),'/emoji>')

マップをテキストモードに切り替えて入力します


⑦-4) alt・title空欄タグ抽出

(データ操作)『アレイのフィルター処理』でemojiタグのうち、alt/title属性のいずれかが空のタグを取得します。

  • 差出人: @body('emojiタグ選択')
  • 条件:@or(contains(item(), 'alt=""'),contains(item(), 'title=""'))

詳細設定モードで編集します


⑦-5) 空欄タグで繰り返し

(コントロール)『それぞれに適用する』で「⑦-4) alt・title空欄タグ抽出」で繰り返し処理します。

  • 出力選択: @{body('alt・title空欄タグ抽出')}

⑦-6) emojiサニタイズ作成

(データ操作)『作成』で「テンポラリ文字列」からalt・titleが空欄のemojiタグを除去します。

  • 値:@{replace(variables('テンポラリ文字列'),item(),'')}

⑦-7) テンポラリ文字列にサニタイズ本文設定

(変数)『変数の設定』で「テンポラリ文字列」にサニタイズ文字列を設定します。

  • 式:@{outputs('emojiサニタイズ作成')}

emojiタグのalt・title属性が空欄の場合、Graph API:Teamsメッセージ投稿がエラーになるため除去します。
本件は試験データでたまたま見つかりました。他にも罠があるかもしれません…


⑦-8) サニタイズ本文退避

(データ操作)『作成』でサニタイズが完了した「テンポラリ文字列」を退避します。

  • 値:@{variables('テンポラリ文字列')}

⑦-9) テンポラリ文字列に整形本文設定

(変数)『変数の設定』で「テンポラリ文字列」に移行元メッセージの投稿者情報を加えた「⑦-8) サニタイズ本文退避」を設定します。

  • 式:<div style="background-color:#666; color:#fff; font-size:80%;">[移行データ] @{items('メッセージ配列で繰り返し')?['user']}さんが@{items('メッセージ配列で繰り返し')?['createdDateTime']}に投稿しました。</div> @{outputs('サニタイズ本文退避')}

⑦-10) 画像抽出

(データ操作)『アレイのフィルター処理』で「画像配列」から移行元メッセージと同一のメッセージIDデータを抽出します。

  • 差出人: @variables('画像配列')
  • 左辺: (式)@item()?['messageId']
  • 条件:次の値に等しい
  • 右辺: (値)@items('メッセージ配列で繰り返し')?['id']

⑦-11) hostedContents選択

(データ操作)『選択』で、「③-10) 画像抽出」からメッセージのhostedContentsに埋め込むオブジェクト値を選択します。

  • 開始:(式)@{body('画像抽出')}
  • マップ:以下参照
パラメータ名
@concat(decodeUriComponent('%40'),'microsoft.graph.temporaryId') @item()?[concat(decodeUriComponent('%40'),'microsoft.graph.temporaryId')]
contentType @item()?['contentType']
contentBytes @item()?['contentBytes']

⑦-12) 本文Imgタグ選択

(データ操作)『選択』で、「テンポラリ文字列」からimgタグを選択します。

  • 開始:(式)@{skip(split(variables('テンポラリ文字列'),'<img '),1)}
  • マップ:@concat('<img ',first(split(item(),'>')),'>')

マップをテキストモードに切り替えて入力します


⑦-13) 本文Imgタグで繰り返し

(コントロール)『それぞれに適用する』で「③-12) 本文Imgタグ選択」で繰り返し処理します。

  • 出力選択: @{body('本文Imgタグ選択')}

⑦-14) 画像配列一致確認

(データ操作)『アレイのフィルター処理』で以下パラメータを設定し、「③-10) 画像抽出」のうち、本文imgタグが一致するデータを抽出します。

  • 差出人: @body('画像抽出')
  • 左辺: (式)@item()?['imgTag']
  • 条件:次の値に等しい
  • 右辺: (値)@items('本文Imgタグで繰り返し')

⑦-15) ImgSrc作成

(データ操作)『作成』でimgタグのsrc属性を作成します。

  • 値:@{first(split(last(split(items('本文Imgタグで繰り返し'),'src="')),'"'))}

⑦-16) Img置換本文作成

(データ操作)『作成』で「テンポラリ文字列」のimg src属性をhostedContentsに差し替えした値を作成します。差し替えできなかった場合は注意文言を代入します。

  • 値:@{replace(variables('テンポラリ文字列'), if(equals(length(body('画像配列一致確認')),1), outputs('ImgSrc作成'), items('本文Imgタグで繰り返し')), if(equals(length(body('画像配列一致確認')),1), concat('../hostedContents/',body('画像配列一致確認')?[0]?[concat(decodeUriComponent('%40'),'microsoft.graph.temporaryId')],'/$value'), '<div style="background-color:#f00; color:#fff; font-size:80%;">注意:画像は移行されませんでした</div>'))}

⑦-17) Img入れ替え本文の設定

(変数)『変数の設定』で「テンポラリ文字列」を「⑦-16) Img置換本文作成」に置換設定します。

  • 式:@{outputs('Img置換本文作成')}

⑦-18) Attachment抽出

(データ操作)『アレイのフィルター処理』で「添付配列」から移行元メッセージと同一のメッセージIDデータを抽出します。

  • 差出人: @variables('添付配列')
  • 左辺: (式)@item()?['messageId']
  • 条件:次の値に等しい
  • 右辺: (値)@items('メッセージ配列で繰り返し')?['id']

⑦-19) Attachmentの変換選択

(データ操作)『選択』で、「⑦-18) Attachment抽出」から移行元データのAttachmentIDと参照URLを選択します。

  • 開始:(式)@{body('Attachment抽出')}
  • マップ:以下参照
パラメータ名
@item()?['attachmentId'] @item()?['contentUrl']

⑦-20) Attachmentオブジェクト作成

(データ操作)『作成』で「⑦-19) Attachmentの変換選択」を文字列加工→JSON変換し、配列値をオブジェクト値に変換します。

  • 値:@{json(replace(replace(replace(replace(string(body('Attachmentの変換選択')),'{',''),'}',''),'[','{'),']','}'))}

⑦-21) Attachementの差し替え選択

(データ操作)『選択』で、メッセージ配列のattachmentsから移行用attachmentsデータを選択します。

  • 開始:(式)@{items('メッセージ配列で繰り返し')?['attachments']}
  • マップ:以下参照
パラメータ名
id @if(not(equals(variables('前後メッセージIDオブジェクト')?[item()?['id']],null)),variables('前後メッセージIDオブジェクト')?[item()?['id']],item()?['id'])
contentType @item()?['contentType']
contentUrl @outputs('Attachmentオブジェクト作成')?[item()?['id']]
content @if(and(equals(item()?['contentType'],'messageReference'),not(equals(variables('前後メッセージIDオブジェクト')?[item()?['id']],null))),concat('{"messageId":"',variables('前後メッセージIDオブジェクト')?[item()?['id']],'","messagePreview":',last(split(item()?['content'],'"messagePreview":'))),null)
name @item()?['name']
thumbnailUrl null
teamsAppId null

⑦-22) Attachmentオブジェクトリファレンス抽出

(データ操作)『アレイのフィルター処理』で「⑦-21) Attachementの差し替え選択」からcontentかcontentUrlが設定されたデータを抽出します。

  • 差出人: @body('Attachementの差し替え選択')
  • 条件:@or(not(equals(item()?['content'], null)),not(equals(item()?['contentUrl'], null)))

詳細設定モードで編集します


⑦-23) 未添付データ抽出

(データ操作)『アレイのフィルター処理』で「⑦-21) Attachementの差し替え選択」からcontent・contentUrlの両方がnullのデータを抽出します。

  • 差出人: @body('Attachementの差し替え選択')
  • 条件:@and(equals(item()?['content'], null),equals(item()?['contentUrl'], null))

詳細設定モードで編集します


⑦-24) 未添付データで繰り返し

(コントロール)『それぞれに適用する』で「⑦-23) 未添付データ抽出」で繰り返し処理します。

  • 出力選択: @{body('未添付データ抽出')}

⑦-25) テンポラリ文字列に未添付ファイル名を追加

(変数)『文字列変数に追加』で「テンポラリ文字列」に添付できなかったファイル名付き注意文言を追加します。

  • 式:<div style="background-color:#f00; color:#fff; font-size:80%;">注意:@{if(equals(item()?['contentType'],'reference'),concat('添付ファイル「',items('未添付データで繰り返し')?['name'],'」'),'引用メッセージ')}は移行されませんでした</div>

⑦-26) 本文Attachment選択

(データ操作)『選択』で、「テンポラリ文字列」のattachmentタグのメッセージID値を移行後メッセージIDに置換したデータを選択します。

  • 開始:(式)@{skip(split(variables('テンポラリ文字列'),'<attachment id="'),1)}
  • マップ:@concat(if(not(equals(variables('前後メッセージIDオブジェクト')?[first(split(item(),'"'))],null)),variables('前後メッセージIDオブジェクト')?[first(split(item(),'"'))],''),'"',join(skip(split(item(),'"'),1),'"'))

マップをテキストモードに切り替えて入力します


⑦-27) メッセージID置換本文作成

(データ操作)『作成』で「テンポラリ文字列」のattachment idを「⑦-26) 本文Attachment選択」に入れ替えた文字列を作成します。

  • 入力:@{first(split(variables('テンポラリ文字列'),'<attachment id="'))}@{if(equals(length(body('本文Attachment選択')),0),'',concat('<attachment id="',join(body('本文Attachment選択'),'<attachment id="')))}

⑦-28) テンポラリ文字列のメッセージID置換設定

(変数)『変数の設定』で「テンポラリ文字列」を「⑦-27) メッセージID置換本文作成」からattachmentのID空値を除去した文字列に設定します。

  • 式:@{replace(outputs('メッセージID置換本文作成'),'<attachment id=""></attachment>','')}

⑦-29) HTTP要求:メインメッセージ送信

(Microsoft Teams)『Microsoft Graph HTTP 要求を送信する』で以下パラメータを設定し、指定チーム・チャネルにメッセージ送信します。

パラメータ名
URI https://graph.microsoft.com/v1.0/teams/@{body('移行先Team抽出')?[0]?['id']}/channels/@{body('移行先チャネル抽出')?[0]?['id']}/messages
メソッド POST
本文 { "body": { "contentType": "html", "content": "@{replace(replace(variables('テンポラリ文字列'), '\', '\\'), '"', '\"')}"}, "hostedContents": @{body('hostedContents選択')}, "attachments" : @{body('Attachmentオブジェクトリファレンス抽出')}}
コンテンツの種類 application/json

⑦-30) 前後メッセージID作成

(データ操作)『作成』で「⑦-29) HTTP要求:メインメッセージ送信」で払い出されるメッセージIDを「前後メッセージIDオブジェクト」にプロパティ設定した値を作成します。

  • 値:@{addProperty(variables('前後メッセージIDオブジェクト'),items('メッセージ配列で繰り返し')?['id'],outputs('HTTP要求:メインメッセージ送信')?['body']?['id'])}

⑦-31) 前後メッセージIDの設定

(変数)『変数の設定』で「前後メッセージIDオブジェクト」に「⑦-30) 前後メッセージID作成」の変更を設定します。

  • 式:@{outputs('前後メッセージID作成')}

(変数)『変数の値を増やす』で入力文字列の右から指定位置文字が「1」の場合は返り値に係数変数の値を加算します。(「1」以外は加算しない)

  • 値:@{if(equals(substring(triggerBody()?['text'],sub(length(triggerBody()?['text']),item()),1),'1'),variables('係数'),0)}

(変数)『文字列変数に追加』で「内容」に読取行文字列を追加します。

  • 値:@{outputs('本文先頭行取り出し')}
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?