SharePointのリストアイテムの登録者と登録日時を編集する

# 記事概要
SharePointのリストアイテムは登録を行ったユーザーとその日時がそれぞれ「登録者」列、「登録日時」列に設定され、この２つの列はSharePointのUI上では編集できない。本記事では何かしらの理由で登録者や登録日時を編集したい場合に実践可能なアプローチを掲載している。

# 目的
登録者と登録日時を編集する目的としては、以下の2点が考えられる。

1. データの本来のプロパティを保持したい
2. 保守性を考慮し、既定の列のみでプロパティを設定したい

ファイルサーバー等からSharePointにデータを移行する場合、データの本来のプロパティを保持する他にも新たにユーザー列や日時列を作成してそこに登録日に該当するプロパティを設定するというアプローチが考えられるが、複数の列が混在し保守性に難がある。その為、既定の列のみで登録者や登録日時を編集するアプローチを採用する場合に下記の実装例が有用となる。

# 実装例
本記事では、Powershellを利用した2例を掲載している。
「リストの設定」画面で列名をマウスオーバーすると列の設定画面のURLが表示されるが、その末尾が列の内部名となる。登録者は**Author**、登録日時は**Created**という内部名が設定されていることがわかるので、これを元にPowerShellで各列を編集していく。
いずれの方法も実行結果は同様なので、前提条件に適ったものや取り組みやすい方法を採用し、「# サイトの情報」「# 編集する列」の部分の変数を自身の環境に合わせて変更し実行しよう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338126/f66c83d9-0f93-270f-d38b-4a669cc2b5bf.png)

## SharePoint CSOMによる実装方法
事前に[SharePoint Online Client Components SDK](https://www.microsoft.com/en-us/download/details.aspx?id=42038)をインストールすること。

```Set-ListItem.ps1
# 実行ユーザーおよびサイトの情報
$SiteURL = "https://tenant.sharepoint.com/sites/test"
$ListTitle = "EditList"
$UserName   = "ExecuteUser@tenant.com"

# 編集する列
$AuthorID = "AuthorUser@tenant.com"
[datetime]$Created = "9999年12月31日 23:59:59"

# パスワード
$Password= Read-Host -Prompt "Enter the password" -AsSecureString

# ライブラリ読み込み
Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client").location)
Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.runtime").location)

# 認証
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $Password)

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

# 登録者となるユーザーを取得
$Author = $Context.Web.EnsureUser($AuthorID)
$Context.Load($Author)

# サイト配下のリストを取得
$lists = $Context.Web.Lists
$context.Load($lists)

# タイトルからリストを取得
$list = $lists.GetByTitle($ListTitle)
$Context.Load($list)

# IDからアイテムを取得
$Item = $List.GetItemById(1)
$Context.Load($Item)

# 登録者と登録日時を編集
$Item["Author"] = $Author
$Item["Created"] = $Created
$Item.Update()
$Context.ExecuteQuery()
```

## PnP PowerShellによる実装方法
事前にinstall-moduleコマンドレットを実行すること。下記はSharePointOnlineに接続する場合のコマンド。

```
Install-Module SharePointPnPPowerShellOnline
```

```Set-ListItem.ps1
# サイトの情報
$SiteURL = "https://tenant.sharepoint.com/sites/test"
$ListTitle = "EditList"

# 編集する列
$Author = "AuthorUser@tenant.com"
[datetime]$Created = "9999年12月31日 23:59:59"

# 認証
Import-Module SharePointPnPPowerShellOnline -DisableNameChecking
Connect-PnPOnline -Url $SiteURL -Credentials (Get-Credential)

# 登録者と登録日時を編集
Set-PnPListItem -List $ListTitle -Identity 1 -Values @{"Author" = $Author; "Created" = $Created}
```

こんな感じになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338126/eb7afb1e-bc10-3b05-e9c8-5ab1430b22a4.png)

# 編集可能な範囲
## 登録者
上記の方法では**実行時点で編集権限のないユーザーやグループを登録者として変更可能**な点に留意する必要がある。


## 登録日時 
**1900/01/01 00:00:00**から**9999/12/31 23:59:59**まで登録することが可能。

# 留意事項
・本番環境での編集は必要最低限に留める
本来UI上では編集できない列であり、不用意に編集することはデータの改ざんにあたる。
「目的」にも記載したとおり、編集する正当な目的を明確にし、本番環境で実行する場合はタイミングを限定すること(ex. データ移行時)が望ましい。

・バージョン履歴を有効にする
上述のとおり「誰がどのように変更したか」を記録する為にも、SharePointのバージョン履歴は有効にすること。実行ユーザーが更新者として記録される。

# 参考文献
[PnP PowerShell の概要]
(https://docs.microsoft.com/ja-jp/powershell/sharepoint/sharepoint-pnp/sharepoint-pnp-cmdlets?view=sharepoint-ps)
[Set-PnPListItem](https://docs.microsoft.com/ja-jp/powershell/module/sharepoint-pnp/set-pnplistitem?view=sharepoint-ps)