参照列の参照先リストを変更したい

2020/04/18

リストをテンプレート化していたものを別サイトに展開しました。しかし、参照列を含んでいることを忘れていて、参照列が選択できなくなってしまいました…

GUI からは参照元リストを変換できないようなので、列の SchemaXml を眺めていたら変更できそうだったので試してみました。

SchemaXml を眺め方はこちら

参照列の SchemaXml を確認

試しにリストを作って、別リストの「作成日時」を利用して参照列作ってみました。
http://1bed.allright.life/wp-content/uploads/2017/07/lookup01-300x195.png

その SchemaXml がこちらです。

<Field
    Type="Lookup"
    DisplayName="参照(日付と時刻)"
    Required="FALSE"
    EnforceUniqueValues="FALSE"
    List="{f5bb4f52-e0a7-4c25-abab-a3d261fde470}"
    ShowField="Created"
    UnlimitedLengthInDocumentLibrary="FALSE"
    RelationshipDeleteBehavior="None"
    ID="{55843724-0221-4ae3-ad18-414edd209754}"
    SourceID="{aca9e366-bd2b-4060-bd63-342e18395df7}"
    StaticName="testLookupDatetime"
    Name="testLookupDatetime"
    ColName="int3"
    RowOrdinal="0"
    Version="2"
    Group="" />

この中に 36 文字の英数字とハイフンでできた文字列を {} で囲っている GUID が 3 つあります。

  • List="{f5bb4f52-e0a7-4c25-abab-a3d261fde470}"
    参照元リストのリスト ID

  • ID="{55843724-0221-4ae3-ad18-414edd209754}"
    列固有の ID

  • SourceID="{aca9e366-bd2b-4060-bd63-342e18395df7}"
    この列が存在しているリストのリスト ID

参照している列の内部名 ShowField="Created" を合わせて、List 属性の値を書き換えればどうにかなるのでは?と思い試してました。

SchemaXml の List 属性を PowerShell で書き換える

下記状態と仮定してサンプルコードを載せます

  • ユーザー
    [email protected]
  • SharePoint Online の URL
    https://.sharepoint.com/sites/example
  • 参照列のあるリスト名
    参照列持ってるぜリスト
  • 参照列の内部名
    LookupDate
  • 参照元のリスト名
    私を見てリスト
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null

# 取得する SharePoint Online の URL
$url = 'https://<tenant>.sharepoint.com/sites/example'

# ユーザー名
$user = '[email protected]';

# パスワード
$secure = Read-Host -Prompt "Enter the password for ${user}(Office365)" -AsSecureString;

# SharePoint Online 認証情報
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($user, $secure);

# SharePoint Client Context インスタンスを生成
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($url)
$ctx.Credentials = $credentials

ここまではいつものおまじない的なコード。
ログインして SharePoint Client Context のインスタンスを作成しています。

ここからが本命のコード。

# 更新リスト名
$targetListName   = '参照列持ってるぜリスト';
# 更新列
$targetFields     = @('LookupDate');
# 新参照先リスト名
$toLookupListName = '私を見てリスト'

# 新参照先リスト ID 取得
$toList = $ctx.Web.Lists.GetByTitle($toLookupListName)
$ctx.Load($toList)

# 更新列の読み込み予約
$fieldsContainer = @()
foreach($fieldName in $targetFields) {
    $field = $ctx.Web.Lists.GetByTitle($targetListName).Fields.GetByInternalNameOrTitle($fieldName)
    $ctx.Load($field)
    $fieldsContainer += $field
}

# 読み込み実行
$ctx.ExecuteQuery()

# 参照先リストの書き換え
foreach($field in $fieldsContainer) {
    # SchemaXml の List 属性の値を、新参照先リストのリスト ID に書き換え
    $field.SchemaXml = $field.SchemaXml -replace 'List="(.*?)"', ('List="{'+ $toList.Id + '}"')
}

# 書き換え実行
$ctx.ExecuteQuery()

実際にはもうちょっと綺麗なスクリプトにしてますが(言い訳気味)

考察

一応手元では動いていますが、これでいいのか?という疑問と、しくじったら取り返しのつかないことになりそうなので、参考にする奇特な方がいましたらバックアップを取って自己責任でお願いします
_(:3」∠)_