SharePoint で選択肢列と参照列を PowerShell で付け替える(3/3)

[ブログからの転載](http://1bed.allright.life/?p=2616)

前回の続きです
下記手順の 3 番目、参照列の作成を行います

1. 選択肢列の値を使い、参照列元のリストを作成する
2. 手順 1 で作成したリストを使い、参照列を作成する
3. 選択肢列の値を参照列に移行
4. 選択肢列の削除

## 環境

前回で移行するリストはこのようになっています最初に作っていた

* リスト名: 選択肢列と参照列を付け替える

| 列名 | 内部列名 | 種類 | 値 |
| --- | --- | --- | --- |
| 目的地 | Title | 1 行テキスト | |
| 乗り物 | vehicle | 選択肢 | 車 , バイク , 自転車 , 船 , 飛行機 |
| おやつ | snack | 選択肢(複数選択可能) | ポテトチップス , アポロ , じゃがりこ , チップスター , ハイレ , かっぱえびせん |
| 乗り物 | relVehicle | 参照列 | 「乗り物マスタ」リストのアイテム |
| おやつ | relSnack | 参照列(複数選択可能) | 「おやつマスタ」リストのアイテム |

## 1. 選択肢列の値を使い、参照列元のリストを作成する

こちらは済です

* [SharePoint で選択肢列と参照列を PowerShell で付け替える(1/3)](http://1bed.saloon.jp/?p=2592) 

## 2. 「選択肢列と参照列を付け替える」に参照列を作成

こちらは済です

* [SharePoint で選択肢列と参照列を PowerShell で付け替える(2/3)](http://1bed.saloon.jp/?p=2607)


## 3. 選択肢列の値を参照列に移行

```ps1
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")

# SharePoint Online の URL
$url = 'https://<tenant>.sharepoint.com/sites/example'
# ユーザー名
$user = 'miyamiya@example.com';
# パスワード
$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($SiteURL)
$ctx.Credentials = $credentials

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

## 必要な変数定義

# 選択肢列を参照列に置き換えるリストのリスト名
$targetListName = "選択肢列と参照列を付け替える"

# コピー元選択肢列の内部列名
$baseFieldInternalName = "vehicle"
#$baseFieldInternalName = "snack"

# コピー先参照列の内部列名
$copyFieldInternalName = "relVehicle"
#$copyFieldInternalName = "relSnack"

# マスタリストの名前
$mstListName = "乗り物マスタ"
#$mstListName = "おやつマスタ"

## サーバーから値の取得

# 移行するリスト
$targetList = $ctx.Web.Lists.GetByTitle($targetListName)

# 移行するアイテム
$targetItems = $targetList.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())

# 参照列化する列
$targetField = $targetList.Fields.GetByInternalNameOrTitle($baseFieldInternalName)

# 参照列のマスタリスト
$mstList = $ctx.Web.Lists.GetByTitle($mstListName)

# 参照列のマスタアイテム
$mstItems = $mstList.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())

# 値のロード予約
$ctx.Load($targetItems)
$ctx.Load($mstItems)
$ctx.Load($targetField)
$ctx.ExecuteQuery()

# マスタデータを取得
$mstItemDatas = @()
$enumMstItems = $mstItems.GetEnumerator()
while ($enumMstItems.MoveNext()) {
    $item = $enumMstItems.Current
    $mstItemDatas += @{ 'ID' = $item.Id; 'Title' = $item.FieldValues.Title; }
}

# 移行処理
$enumTargetItems = $targetItems.GetEnumerator()
while ($enumTargetItems.MoveNext()) {
    $item = $enumTargetItems.Current

    # 参照列データの作成
    $lookupArray = @()
    foreach ($data in $item.FieldValues[$baseFieldInternalName]) {
        $lookupId = ($mstItemDatas | Where-Object 'Title' -eq $data).ID
        $lookupValue = New-Object Microsoft.SharePoint.Client.FieldLookupValue
        $lookupValue.LookupId = $lookupId
        $lookupArray += $lookupValue
    }
    $lookupValueCollection = [Microsoft.SharePoint.Client.FieldLookupValue[]] $lookupArray
    $item.Item($copyFieldInternalName) = $lookupValueCollection

    # 更新者(Editor)を上書き
    if ($internalName -ne 'Editor') {
        $nowEditorValue = New-Object Microsoft.SharePoint.Client.FieldUserValue
        $nowEditorValue.LookupId = $item.Item('Editor').LookupId
        $nowEditorValueCollection = [Microsoft.SharePoint.Client.FieldUserValue[]] $nowEditorValue
        $item.Item('Editor') = $nowEditorValueCollection
    }

    # 更新日(Modified)を上書き
    if ($baseFieldInternalName -ne 'Modified') {
        $nowModifiedValue = $item.Item('Modified')
        $item.Item('Modified') = $nowModifiedValue
    }

    # 更新予約
    $item.Update()
}

# 更新
$ctx.ExecuteQuery()

# Context の破棄
$ctx.Dispose()
```

大雑把に手順を書くと次の感じ

1. 既存データの取得
2. 選択肢列と同じ値の参照列データを作成
3. 更新者と更新日を変わらないようにする  
4. 更新