PnP PowerShell で Sharepoint を操作しよう: (4) 参照フィールドを使ったリストを作ろう

皆様こんにちは。

前回の続きで、こんどはPnP PowerShellをつかって SharePointに参照フィールド付きのリストを作ってみようと思います。

SharePointで参照フィールドを作って別のリストを参照させると、別のリストの内容を入力の選択肢として使うことができたり、ちょっぴりだけデータベースっぽい作業ができます。


まず、普通にリストを作るところまで。

```new-list.ps1
#リストの作成
$list="参照ありリスト"
$listInternal="ListWithLookupField"
New-PnPList -url  $listInternal -Title $list -Template GenericList

# 参照先リストの作成
$LinkedList="ChildList"
$LinkedListTitle="子リスト"
New-PnPList -url  $LinkedList -Title $LinkedListTitle　-Template GenericList 
```
これでリストが2つできました。

親リストの「参照ありリスト」には現在、「タイトル」というフィールドだけがあります。内部的に「更新」(Modified) という列があって、後で参照します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368667/f475f914-4154-5db6-7857-4783cec413c6.png)

参照型フィールドの作成
---

ここに、子リストのフィールドを追加します。
[Add-PnPField](https://docs.microsoft.com/en-us/powershell/module/sharepoint-pnp/add-pnpfield?view=sharepoint-ps) 命令を使うのですが、-type Lookup についてはドキュメントに記載がありません。前例をwebで探しまくってなんとかここまでたどりつきました。

参考にしたのは以下の記事です。
[GitHub - Question: Adding a lookup field with Add-PnPField #1518](https://github.com/SharePoint/PnP-PowerShell/issues/1518)

```new-LookupField.ps1
#新規に作るフィールド
$Field="LinkedField"
$FieldName="参照フィールド"

#リンク先のリストおよび、"参照フィールド"列が参照したい子リスト内のフィールド"Title"
$LinkedList="ChildList"
$LinkedListTitle="子リスト"
$LinkedField="Title"

$ctx = Get-PnPContext
$lookupField= Add-PnPField -List $list -InternalName $Field -displayname $FieldName -type Lookup
$lkField = $lookupField.TypedObject
#$lkField.LookupList=(Get-PnPList $LinkedListTitle).id #←"子リスト"で検索
$lkField.LookupList=(Get-PnPList -Identity $LinkedListTitle).id #←"ChildList"で検索
$lkField.LookupField=$LinkedField
$lkField.Update()
$ctx.ExecuteQuery()
```

こうすると、子リストの内容を入力候補として表示できる「参照フィールド」が作成できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368667/85e384f7-4e4a-9e5c-b829-cb4f4887640e.png)

新規レコードを作ろうとすると、参照フィールド欄に、子リストの内容が出ます。便利です。

ここで、表示名と内部名のどっちを使えばいいの！？と混乱しました。
Get-PnPList 命令では、-Identity を指定すると内部名(URLに出るほう) で検索が行われるのですね。
大事なところなので二度説明します。

>$ctx = Get-PnPContext
$lookupField= Add-PnPField -List *<参照型フィールドを追加したいリスト>* -InternalName *<参照型フィールドの内部名>* -displayname *<参照型フィールドの表示名>* -type **Lookup**
$lkField = $lookupField.TypedObject
 #$lkField.LookupList=(Get-PnPList <子リストの**表示名**>).id
$lkField.LookupList=(Get-PnPList -Identity <子リストの**内部名**>).id
$lkField.LookupField=<子リストの欲しいフィールドの**内部名**>
$lkField.Update()
$ctx.ExecuteQuery()

これで、手作業だと迷いそうになる参照型フィールドをスクリプトから生成できるようになりました。


参照型フィールド追加表示列の作成
---
もうひと頑張りしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368667/5bc70169-379f-f04f-e671-74e758676264.png)
こんな感じに、SharePointの画面なら表示列を追加することができるはずです。PnP ではどうするでしょう。
[Add-PnPField](https://docs.microsoft.com/en-us/powershell/module/sharepoint-pnp/add-pnpfield?view=sharepoint-ps) では、参照型フィールドについてあまりややこしい操作を受け付けてくれないので、[Add-PnPFieldFromXml](https://docs.microsoft.com/en-us/powershell/module/sharepoint-pnp/add-pnpfieldfromxml?view=sharepoint-ps) というコマンドの出番になります。何それ！？泣きそうでしたが、見よう見まねでやってみました。

フィールド定義を事前にXMLにするのですが、そこでPnP で現在いじっているサイト、リスト、参照フィールドなどのIDをXMLに代入しなくちゃいけないそうです。

```Add-PnPFieldFromXml.ps1
IDを変数に取り出す
$webid = (Get-PnPWeb).id 
$ListId=(Get-PnPList $list).id
$LinkedListId=(Get-PnPList $LinkedList).id
$FieldRefId=(Get-PnPField -List "$list" -Identity $LinkedField).id #"参照フィールド" 列のID

#新しく追加するフィールドの、子リスト上の名前、こちらのリスト上での新しい名前
$newLinkedField = "Modified"
$newLinkedFieldName = "参照フィールドの更新"
$newLinkedFieldInternalName = "LinkedFieldModified"

#XML
$xml="<Field Type='Lookup' 
ShowField=`'$newLinkedField`' 
DisplayName=`'$newLinkedFieldName`' 
Name=`'$newLinkedFieldInternalName`' 
StaticName=`'$newLinkedFieldInternalName`' 
List=`'$LinkedListId`' 
WebId=`'$webid`'  
FieldRef=`'$FieldRefId`' 
ReadOnly='TRUE' 
UnlimitedLengthInDocumentLibrary='FALSE' 
SourceID=`'$ListId`'  
Required='TRUE' />"

#実行
Add-PnPFieldFromXml -list $list -FieldXml $xml
```
ずいぶんコードが増えてしまいました。

これで、子リストから複数フィールドを参照することができるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368667/dbee14a8-a9ab-4133-3c97-9276dc79e4cb.png)

このように、参照フィールドで選択されたアイテムの更新日時が表示できるようになりました。
参照フィールドのアイテムを別のものに切り替えたり、子リストを更新するとちゃんと連動します。


以下に、実際に使ったものに近い「大分類」、「小分類」コードのリストを作成するコードを載せます。

```PowerShell:New-CategoryList.ps1
$list="小分類コードマスタ"
$listInternal="CategorySubCode"
$LinkedList="分類コードマスタ"
$LinkedListInternal="CategoryCode"

$InternalMinorCode="code"
$InternalMinorTitle="Title"
$InternalMajorCode="CategoryCode"
$InternalMajorTitle="CategoryTitle"
$DisplayMinorCode="小分類コード"
$DisplayMinorTitle="小分類"
$DisplayMajorCode="大分類コード"
$DisplayMajorTitle="大分類"

 #大分類コードリスト作成
New-PnPList -url  $LinkedListInternal -Title $LinkedList -Template GenericList
Add-PnPField -List $LinkedListInternal -DisplayName $DisplayMajorCode -InternalName $InternalMajorCode -Type Number -AddToDefaultView
Add-PnPNavigationNode -Title $LinkedList -Url $LinkedListInternal -Location QuickLaunch #左のナビゲーション(クイックランチ)に登録

#小分類コードリスト作成
New-PnPList -url  $listInternal -Title $list -Template GenericList 
Set-PnPList -Identity $listInternal -EnableAttachments $false #添付機能なし
Add-PnPNavigationNode -Title $list -Url $listInternal -Location QuickLaunch #左のナビゲーション(クイックランチ)に登録

#基本的なフィールド定義
Add-PnPField -List $listInternal -DisplayName $DisplayMinorCode -InternalName $InternalMinorCode -Type Number -AddToDefaultView
Set-PnPField -List $listInternal -Identity $InternalMinorCode -Values @{"Indexed"=$true} 
#Set-PnPField -List $listInternal -Identity $InternalMajorCode -Values @{"Indexed"=$true}
Set-PnPField -List $listInternal -Identity $InternalMinorTitle -Values @{"Title"="$DisplayMinorTitle"} 


#Lookup (参照) フィールド追加
$ctx = Get-PnPContext
    $lookupField= Add-PnPField -List $list -InternalName $InternalMajorCode -displayname $DisplayMajorCode -type Lookup
    $lkField = $lookupField.TypedObject
    $lkField.LookupList=(Get-PnPList -Identity $LinkedListInternal).id
    $lkField.LookupField=$InternalMajorCode
    $lkField.Update()
$ctx.ExecuteQuery()

#続いて追加表示フィールド追加
#https://stackoverflow.com/questions/1295050/add-a-lookup-field-to-a-content-type-in-sharepoint
$webid = (Get-PnPWeb).id
$ListId=(Get-PnPList $list).id
$LinkedListId=(Get-PnPList $LinkedList).id
$FieldRefId=(Get-PnPField -List "$list" -Identity $InternalMajorCode).id

$xml="<Field Type='Lookup' ShowField='Title' DisplayName=`'$DisplayMajorTitle`' Name=`'$InternalMajorTitle`' StaticName=`'$InternalMajorTitle`' List=`'$LinkedListId`' WebId=`'$webid`'  FieldRef=`'$FieldRefId`' ReadOnly='TRUE' UnlimitedLengthInDocumentLibrary='FALSE' SourceID=`'$ListId`'  Required='TRUE' />"
Add-PnPFieldFromXml -list $list -FieldXml $xml

#ビュー定義
Add-PnPView -List $list -Title "コード昇順" -Fields $InternalMajorCode,$InternalMajorTitle,$InternalMinorCode,$InternalMinorTitle -SetAsDefault -Query "<OrderBy><FieldRef Name=`'$InternalMajorCode`' Ascending='true'/><FieldRef Name=`'$InternalMinorCode`' Ascending='true'/></OrderBy>"
```

※ `Get-PnPField` 命令で、-list に日英どっちの名前を指定すればいいのか迷いましたが、ここではどちらの名前を指定しても動くらしいです。 

今回はここまでにします。