Sharepointのドキュメントライブラリ作業を自動化する【Powershell】

Sharepointのドキュメントライブラリを操作して、作業自動化をPowerhellで実現する方法の紹介です。

Sharepointのドキュメントライブラリを毎月手でチェックしていたので、これを自動実行するのが今回のお題です。まずはPowershellからSharepointにアクセスする方法から。

Sharepoint操作に必要な準備をする

Microsoftのサポートブログにほぼすべてが記載されていますので、こちらを御覧ください。

PowerShell で SharePoint CSOM を使用する際の Tips
かいつまんで言うと

  • クライアント サイド オブジェクト モデル(CSOM)を使うことでサイトコレクション配下のオブジェクトを操作できます。
  • .Net言語から操作できます。Powershellを使えばインストールも不要です。
    Windows操作の自動化もできます。
  • Sharepointバージョンに合わせたCSOMのライブラリをインストールする必要があります。

URLはすべてリンク先に手順含めて記載がありますのでそちらを参照してください。
入手できたら、アセンブリをLoadします。

#入手したSharepoint.Clientをロードします。
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null

それとアクセスしたいSharepointサイトのURLを準備します。
(サイトコレクションていう分かりにくい用語が出てきます。コレクションはMicrosoftがよく使う用語で、オブジェクトの集合体(配列)みたいな感じです。サイトコレクション=サイトオブジェクトの集合体くらいの意味。)

# SiteCollection URL 取得したいSiteCollectionのURLを指定します。Shapoint Onlineの方はこちら
# $SiteCollectionUrl = "https://tenant-name.sharepoint.com" 
# $SiteCollectionUrl = "https://tenant-name.sharepoint.com/sites/subsite" 
$SiteCollectionUrl = "http://teamsite.gcs.domain.contoso.local/sites/xxxxxx/"#オンプレミスの方はこちらの形式

通常、認証が必要だと思うので認証情報を作ります。
認証情報はGet-Credentialコマンドレットを使って入力してもらうのがかんたんです。

#Sharepointの認証をするActiveDirectoryのドメイン情報を指定します。
$Domain ="domain"
$Credential = Get-Credential  -Username "ユーザネーム"  -Message "SharePointにアクセスするユーザを指定してください"
}

上記の-Username,-Message引数は古いPowerShellだと使えないです。-Credential “ユーザネーム”オプションを使ってみてください。

ActiveDirectory認証してあるPCだったらそこから引っ張ることも可能です。

$Credential = [System.Net.CredentialCache]::DefaultNetworkCredentials

注)Sharepoint Onlineに対してDefaultNetworkCredentialsで認証が通るかは未検証です(^_^;)

PowerShellでは$env:USERDOMAINという環境変数にドメイン情報が格納されているので、これで認証済み端末かそうでないか判定できます。全体つなげると下記のようになります。

#Sharepointの認証をするActiveDirectoryのドメイン情報を指定します。
$Domain ="domain"

#Sharepointへの認証を取得します。
if($env:USERDOMAIN -eq $Domain)
{#AD認証済み端末の場合
$Credential = [System.Net.CredentialCache]::DefaultNetworkCredentials
}else{#独立端末の場合
$Credential = Get-Credential  -Username ($Domain +"\" + $env:USERNAME)  -Message "SharePointにアクセスするユーザを指定してください"
}

ここまでで、Powershellでアクセスする準備ができました。

Sharepoint操作の概念

まずはClientContextオブジェクトを用意します。Sharepointのサイトを開くブラウザをオブジェクト化(概念化)したものという理解でいいと思います。
ClientContextを作るには、サイトのURL(絶対パス)が必要です。

#SiteCollectionのURLを指定して、コンテクストを作ります。
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteCollectionUrl)

ClientContextは下記のAPIドキュメントを参照してください。。
SharePoint .NET API インデックス -Microsoft Doc

作成したContextに認証情報を付与します。

$Context.Credentials = $Credential

これでサイトコレクションにアクセスする準備ができました。でもこの$Conextオブジェクトにはまだ情報は入っていません。ブラウザにURLを入力し終わった程度の状態です。
$Context.Webプロパティを指定してロード→WebQuery(問い合わせ)を実行、でようやく読み込みが行われます。

$objWeb = $Context.Web
$Context.Load($objWeb)
$Context.ExecuteQuery()

試しに$objweb.Titleを入力すると、サイトのタイトルが表示されると思います。

データベースのSQL開発経験があればQuery準備→実行という順序を想像するとわかりやすいかもしれません。

ドキュメントライブラリの情報を取得する

ドキュメントライブラリの実体はリストです。Sharepointのリストをドキュメント格納に特化してカスタマイズしたのがドキュメントライブラリです。
ですので、操作としてはリストの操作とほぼ同じ書き方になります。
(Microsoftの技術ページはほぼリストの操作サンプルばっかり。困ったのでこの記事書いてます(^_^;)

情報を取得したり比較したりしようとするとCamlQueryという物を使います。

Collaborative Application Markup Language (CAML) スキーマ

つまりはXMLでQueryを書いていかないといけません。今回自分は、特定のフォルダにファイルが有るかどうかを見たいだけなのでファイルリストの一覧を取得してPowerShell側でチェックしたほうが楽そうです。

フォルダ内の一覧の取得

単にフォルダ指定したいだけなら、FolderServerRelativeUrlプロパティに指定すればできます。

#ドキュメントリスト内のフォルダへ指定するために、フォルダへのサーバルートからの相対パスを取得する
$SPLib = "DocLib" 
$SPFolder = "FolderName"  #ドキュメントライブラリの下のフォルダをここに指定します。
$SPPath = $objWeb.ServerRelativeUrl + $SPLib + "/" + $SPFolder + "/"

#CamlQeryを作って、問い合わせ先を指定するQueryを指定
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.FolderServerRelativeUrl = $SPPath
$Query.DatesInUtc =$false

DatesInUtc =$falseをつけないと、UTC(協定標準時)で時刻が返って来ます。

次にListオブジェクトを作ってやって、$Queryを指定して問い合わせ実行すればフォルダ内の一覧が返ってきます。

$ListName = "ListName"  #取得したいリストの名前を指定します。日本語で構いません。
# Create List object
$objList = $Context.Web.Lists.GetByTitle($ListName)
$objListItems = $objList.getItems($Query)
$Context.Load($objListItems)
$Context.ExecuteQuery()

取得した一覧を操作する

取得したListItemsオブジェクトは連想配列でデータが格納されています。
一覧を表示させるだけなら下記のように書けばできます。(`tはタブ文字を表示させています)

foreach($item in $objListItems){
    Write-Host  $item.Id.ToString() `t $item["FileLeafRef"] `t $item["Editor"].LookupValue `t $item["Modified"]
}

ここの$item.idは更新や削除の際のキー項目になります。

ファイルをそのまま自動で操作する場合は、$TargetFileに格納して、下記のようにフルパスを設定します。

$SPFile = $SiteCollectionUrl + "/" + $SPLib + "/" + $SPFolder + "/" + $TargetFile

このフルパスをStart-Processで実行してやったり、Interopサービスを使ってやったりすればSharepointファイルの作業を自動化できます。

ドキュメントライブラリのアイテムの作成、更新、削除

作成・更新・削除もリストに対する操作と同じです。更新・削除の場合は上で書いたIDを指定して実行します。

下記はMicrosoftのC#サンプルですがここまで読んだ方なら理解できると思います。

リスト アイテムの作成、更新、削除

特定の文字から始まるファイル名を返す関数

特定の文字列から始まるファイル名を返す関数を作ってみました。Git-Hubに載せています。

#SharePoint上の特定のファイルを返すFunction
function Get-SharePointFileName{
param(
$Domain ="domain", 
# SiteCollection URL 取得したいSiteCollectionのURLを指定します。Shapoint Onlineの方はこちら
# $SiteCollectionUrl = "https://tenant-name.sharepoint.com" 
# $SiteCollectionUrl = "https://tenant-name.sharepoint.com/sites/subsite" 
$SiteCollectionUrl = "http://teamsite.gcs.domain.contoso.local/sites/xxxxxx/", #オンプレミスの方はこちらの形式
$SPLib = "DocLib" ,
$ListName = "ListName" , #取得したいリストの名前を指定します。日本語で構いません。
$SPFolder = "FolderName" , #ドキュメントライブラリの下のフォルダをここに指定します。
#取得したいファイルの先頭文字
$FileNameLead = "FileHeader"
)
#入手したSharepoint.Clientをロードします。
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null

#Sharepointへの認証を取得する。
if($env:USERDOMAIN -eq $Domain)
{#AD認証済み端末の場合
$Credential = [System.Net.CredentialCache]::DefaultNetworkCredentials
}else{#独立端末の場合
$Credential = Get-Credential  -Username ($Domain +"\" + $env:USERNAME)  -Message "SharePointにアクセスするユーザを指定してください"
}
 #Create Context using SiteCollectionURL
 #SiteCollectionのURLを指定して、コンテクストを作ります。
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteCollectionUrl)
$Context.Credentials = $Credential

$objWeb = $Context.Web
$Context.Load($objWeb)
$Context.ExecuteQuery()

# sharepoint上のファイル・フォルダは以下のような形で表す事ができる
#$SPFile = $SiteCollectionUrl + "/" + $SPLib + "/" + $SPFolder + "/" + $TargetFile
#$SPPath = $SiteCollectionUrl + $SPLib + "/" + $SPFolder + "/"

#ドキュメントリスト内のフォルダへ指定するために、フォルダへのサーバルートからの相対パスを取得する
$SPPath = $objWeb.ServerRelativeUrl + $SPLib + "/" + $SPFolder + "/"

# Create List object
$objList = $Context.Web.Lists.GetByTitle($ListName)

#CamlQeryを作って、問い合わせ先を指定するQueryを指定
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.FolderServerRelativeUrl = $SPPath
$Query.DatesInUtc =$false

$objListItems = $objList.getItems($Query)
$Context.Load($objListItems)
$Context.ExecuteQuery()

#返すファイル名を初期化
[String]$TargetFile = ""
$AggregateTime=""
foreach($item in $objListItems)
{
    Write-Host  $item.Id.ToString() `t $item["FileLeafRef"] `t $item["Editor"].LookupValue `t $item["Modified"]
    
 $FileName = [String]$item["FileLeafRef"]
 if($FileName.StartsWith($FileNameLead)){$TargetFile = $FileName;$ModifiedTime=$item["Modified"] ;break}
}

# Dispose Context
$Context.Dispose()

#見つかったらファイル名を返す。見つからなかったら空文字列が入った配列が返る
Return $TargetFile,$ModifiedTime
}#End of Get-SharepointFilename function

おまけ

最初はUiPathとかRPAソフトで試していたんですが、Sharepointのオブジェクトを理解しないと作れないのでやめました。

Excelの操作もiteropサービスはたまにコケるのでClosedXMLとかExport-Excelとか使おうとしたんですが、URL形式での実行を許容しないのでやめました。ファイルのダウンロードして構わないのであれば、ダウンロード→実行の方が外部操作エラーが少ないと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください