D365BCは半年に1度大きなバージョンアップが行われ、概ね月に1回小さなバージョンアップが行われます。バージョンアップ時にテーブルやページなどのオブジェクトが追加作成されることが多いです。今回はPower Queryを使用してこれらの追加オブジェクトを簡単に特定する方法を照会します。また、追加オブジェクトに対する権限セットを作成する方法も紹介します。
概要
1. オブジェクト一覧の取得(比較対象の2バージョン)
2. Power Queryでオブジェクトを比較して差分を抽出
3. 差分オブジェクトの権限セットを作成
詳細手順
1. オブジェクト一覧の取得(比較対象の2バージョン)
オブジェクトの一覧はPage9174から取得できます。
以下のようにURLに’&page=9174’とつけます。
https://businesscentral.dynamics.com/[TenantID]/[EnvironmentName]?company=[CompanyName]&Page=9174
例えばこんなURLになります。
https://businesscentral.dynamics.com/abcderfg-1234-abcd-1234-abcdefghijklml/Sandbox?company=Demo&page=9174
ロールセンターのURLで末尾に’&page=9174’(または’?page=9174’)を付けるのが簡単です。

必須ではないですが、一覧の項目名を追加しておきます。右上の歯車アイコンからPersonalizeを選択。

Object Caption という列項目があるのでObject Nameの右側にドラッグ&ドロップして列項目を追加します。

このように追加されます。追加したら右上の Done ボタンを押して画面レイアウト変更を完了します。

オブジェクト一覧画面で Page タブから Open in Excel ボタンをクリック。

一覧データがExcelでダウンロードされます。

ダウンロードされたExcelファイルを適当な場所に移してファイルを開きます。このようなデータが取得できています。

ダウンロードしたBCのバージョンを確認します。

ダウンロードしたファイルのファイル名にバージョン情報を含めておくとよいでしょう。

同様に比較対象のもう一つのバージョンのBCからオブジェクト一覧をダウンロードします。

2. Power Queryでオブジェクトを比較して差分を抽出
比較用のPower Queryを作成するためのExcelファイルを適当な場所に作ります。オブジェクト一覧のExcelとは別のフォルダにしておきます。(理由は後で分かります。)

Excelを開きデータソースを指定します。
Data タブから Get Data > From File > From Folder の順に選択します。
※ちなみにPower Query のフォルダコネクタについては以下の記事を参考にしました。とても詳しく書かれています。
[Power BI Tips] フォルダーコネクタを使って、毎月追加/更新されるファイルをデータソースにした Power BI レポートの自動化 – Qiita

オブジェクト一覧を格納したフォルダを指定し、Open をクリックします。(ファイルは見えませんがフォルダが見えていれば問題ありません。)

指定したフォルダにファイル情報が表示されます。比較対象の2つのオブジェクト一覧ファイルの情報が表示されていることを確認して Transform Data をクリック。

Power Query Editor にファイル情報が読み込まれました。左端の列に Content という名前の列があります。この列の Binary にデータが入っています。Content 列の見出しの右側にある↓↓ボタンをクリックします。

ファイルの中身が展開されます。左側の枠で Table1 をクリックします。(ファイルの中身のオブジェクト一覧データがテーブルとして定義されているため、これを使用します。)OKをクリック。

ファイルの中身が Power Query Editor に展開されました。左端の列はソースファイル名です。この一覧には両方のファイルのデータが表示されています。試しに下の方にスクロールするとソースファイル名が変わります…と言いたいところですが、この画面はプレビュー画面なのでプレビューに表示する行数制限のために実際には確認できない場合があります。
ちなみに、、この画面の一覧はExcelのデータシートではなく、クエリの抽出結果のプレビューです。このことを覚えておくと Power Query の理解が進みます。

やりたいことは2つの異なるバージョンのオブジェクト一覧を比較することです。今見ているクエリには2つのバージョンのオブジェクトが両方とも含まれています。このままでは比較しにくいので、OLDバージョンのオブジェクトのみを含むクエリとNEWバージョンのオブジェクトのみを含むクエリを作成します。左端に表示されている今のクエリ RawData を右クリックして Reference を選択します。

すると RawData(2)というクエリが新規作成されました。表示されているデータの内容は RawData クエリと全く同じです。Source Name 列にフィルタをかけます。プルダウンボタンを押すと選択肢が表示されます。OLDバージョンとNEWバージョンの2つのファイル名が表示されるはずですが、実際には片方しか表示されていません。これはプレビューの行数制限の問題です。 Load More をクリックします。

するとOLDバージョンとNEWバージョンの両方のファイル名が表示されました。NEWバージョンのみチェックを付けてOKをクリックします。

するとNEWバージョンのオブジェクト一覧のみが表示されました。分かりやすくするため、クエリ名を変更しておきましょう。今回は AllObjectW1-183 というクエリ名に変更しておきます。

同様にOLDバージョンのみを表示するクエリを作成します。クエリ名も変更しておきます。

バージョン情報を表す列を追加します。 Add Column タブから Custom Column ボタンをクリックします。

追加する列を定義します。シンプルに Custom Column fomura に =”W1-182” とバージョンの固定値を指定します。(Source Name 列の文字列から抽出する方法もありますが、結構面倒なので今回はシンプルに列を追加して固定値をセットします。 )

列が追加されました。値はすべて固定値 ’W1-182’ がセットされています。

列見出しを変更します。見出し部分をクリックして ’Version’ に変更します。(列追加の定義のところでやっておけばよかった。。)

もう一つのNEWバージョンのオブジェクト一覧のクエリも同様に設定します。

いよいよOLDバージョンとNEWバージョンを比較して差分を抽出します。左側のクエリの一番下の空白部分で右クリックし、New Query >Combine Merge > Merge Queries as New を選択します。(日本語の方はメニューの位置とアイコンで判断してくださいw)

以下の画面が表示されます。これは2つのテーブル/クエリを指定し、どのように結合するかを指定する画面です。

一つ目(上段)にはNEWバージョンのクエリを指定します。2つ目(下段)にはOLDバージョンのクエリを指定します。Join Kind には Left Anti(rows only in first) を指定します。一つ目のクエリにしか存在しない行のみを表示する、というオプションです。一つ目のクエリはNEWバージョンを指定しました。つまり、新しいバージョンにしか存在しないレコードを抽出する、という事です。

比較するには、どの項目が一致した場合に同じと判断するかを定義する必要があります。ここでは Object Type と Object ID の2つが一致すれば同じと判断するのが良いでしょう。(Object Name のみ変更されたケースも考えられますが、、必要ならば別途クエリを作成してください。)
Ctrlボタンを押しながら一つ目のクエリと2つ目のクエリの Object Type と Object ID 列をクリックして選択します。最後に右下のOKをクリック。

するとこのように列が絞り込まれました。今回の比較では20件の差異が検出されました。

ここに表示されているのはNEWバージョンのデータです。必須ではありませんが、結合されたOLDバージョンのデータも念のため見ておきましょう。(といっても、全部ブランクなのですが)
一番右の列の AllObjectW1-182の見出し行の↑↑ボタンをクリックします。

Object Type と Object ID をキーにして結合されてNEWバージョンのクエリとOLDバージョンのクエリのOLDバージョン(今回はv18.2)の項目一覧が表示されます。

試しに Object Type と Object ID のみを選択してOKをクリックします。

OLDバージョンのクエリの Object Type と Object ID が両方ともNullになっていることが分かります。
クエリ名は分かりやすく変更しておきましょう。そして Close & Load ボタンをクリック。

するとクエリのデータが全行読み込まれたExcelシートが作成されました。ここにはNEWバージョンにのみ存在するオブジェクトが表示されています。

本当かどうか確認してみましょう。例えば TableData:5106はOLDバージョンに存在しないはずです。OLDバージョンのオブジェクト一覧ファイルを開いてみます。確かに存在しません。

3. 差分オブジェクトの権限セットを作成
最後は追加されたオブジェクトの権限作成です。今回の例のように20個くらいであれば以下のように画面から手入力してもすぐに作成することができます。ですが、メジャーバージョンアップの場合は大量に追加されるので手入力は大変です。

権限セットのオブジェクトを大量に追加する場合はXMLファイルをエクスポートしてXMLファイルを編集してインポートするのが楽です。今回はXMLファイルを編集する際のデータをPower Queryで作成します。

最終的に作成するレイアウトを把握するため、新規で権限セットを作成し、エクスポートします。

エクスポートしたファイルは適当な場所に保管します。

エクスポートしたXMLファイルをExcelで開きます。

ExcelファイルではなくXMLファイルなので開く際にいくつかのオプション指定が必要です。
As an XML table を選択。

OKを選択。

XMLファイルが開かれました。これが権限セットのXMLファイルの構造です。この構造になるように Power Query Editor でクエリを作成します。

オブジェクト一覧の Power Query のEXCELに戻ります。Query タブから Edit をクリック。

Power Query Editor が開きます。先に作成したオブジェクト差分のクエリを右クリックし、Reference を選択します。

権限セットを作成するために必要な情報は Object Type と Object ID の2項目のみです。この2列を選択し(Ctrl ボタンを押したまま2つの列をクリックすると複数選択できます)、Remove Columns > Remove Other Columns ボタンを選択すると Object Type と Object ID の2項目 以外の列が削除されます。

権限セットのXMLファイルを見ながら必要な列を追加していきます。まずは Role ID 列を追加します。Add Column リボンから Custom Column ボタンを選択し追加列を定義します。列名と権限セットのオブジェクトコードを固定値 (今回は’Z_Sample’)で指定します。

同様に RoleName、Scope列を追加していきます。 次に Read Permission 列を追加します。この列は Object Type が TableData ならば ’Yes’、それ以外ならば Nullにします。こうした場合、追加列の定義式には以下のように記述します。
if [Object Type]=”TableData” then “Yes” else null

同様にInsert Permission, Modify Permission, Delete Permission を定義します。Execute Permission,は Object Type が Table Data ならば Null、それ以外は ’Yes’ を設定します。(If 関数の trueのケースの値とfalseのケースの値を入れ替えてください。)

全ての列を追加したら列の並び順を修正します。列見出しをドラッグ&ドロップすればOKです。

クエリ名を分かりやすく変更し、Close&Loadボタンをクリックします。

PermissionをエクスポートしたXMLファイルと比較します。Object Type の TableData は半角スペースを入れて’Table Data’とする必要があることに気づきます。

もう一度クエリを開きます。右側にクエリが表示されている場合は該当のクエリを右クリックして Edit ボタンを選びます。

クエリが開きました。 Object Type 列を選択した状態で、リボンの Transform タブから Replace Value を選択します。TableData をTable Dataに置き換える指定をしてOKボタンをクリック。

半角スペースが入りました。Close & Load ボタンをクリックします。

半角スペースが追加されました。あらためてXMLファイルと比較すると 権限セットではObject Type に指定できない値が含まれています。例えばENUMや20は指定できません。

クエリに戻り、オブジェクトタイプのフィルタでチェックを外して除外します。

Enumと20が除外されました。ちなみに、右側の枠の Applied Steps にこれまでの加工手順が記録されています。余談ですが、これが Power Query の肝です。Excelだと加工手順は記録されず、元データが更新されると再度自分で手順に沿って加工する必要があります。Power Query での加工手順はこのようにStepとして記録されるので元データが変わっても手順を適用するだけで加工後の結果を得ることができます。(Power Query Editor の画面に見えている一覧データは手順を適用した場合のプレビューであり、Close&Loadボタンを押した後に表示されるExcelシート状のデータこそが手順を適用した結果のデータということです。)

Close&Loadボタンを押して読み込むと以下のように表示されます。

実際に権限のXMLファイルを加工してインポートするには、もうひと手間必要になります。それについてはこちらの記事をみてください。
XMLファイルをExcelで編集(D365BCの権限セット) | IT長のネタ帳 (d3654.be)
その他
今回はオブジェクト一覧ページから Open in Excel ボタンでダウンロードしましたが、Web Service で Page:9174 を公開する方法も良いと思います。そうすればPersonalizeによる項目追加が不要になります。Web Service で公開したODataのURLを直接 Power Query で読み込むことも可能ですが、ある時点のオブジェクト一覧データ(=スナップショット)が保存できないのが難点です。
まとめ
Power Query を一度作成してしまえばバージョンアップしても簡単に差分比較できることが分かると思います。Power Query というと Power BI での利用が真っ先に頭に浮かぶかと思いますが、Excelの Power Queryを使うことで権限データの作成など加工が容易なのでぜひ活用してみてください。