Quantcast
Channel: Japan SharePoint Support Team Blog
Viewing all articles
Browse latest Browse all 182

サンプル コード : SharePoint 2013 形式ワークフローの状態出力

$
0
0

今回の投稿では、特定のリストに関連付けられた SharePoint 2013 形式ワークフローの各インスタンスの状態を出力する SharePoint Online用のサンプル コードをご紹介します。

SharePoint 2013 形式のワークフローの状態列は、ワークフローの状態列をクリックすれば、下記のように表示されます。

しかし、列自体に、ワークフローの実際の内部状態を表示しないため、リスト ビューなどでワークフローの状況が把握できないというご質問を受けます。

SharePoint 2013 形式ワークフローは、SharePoint 2010 形式ワークフローよりも、リトライ処理が堅牢に実装されております。

そのため、ワークフローの処理が失敗する可能性は低いですが、リトライしても成功しない処理 (. 削除済みアイテムを削除する) をリトライし続け、リトライ回数を枯渇して一旦停止になる場合もあります。

今回の投稿では、このようなシナリオにおいて SharePoint 2013 形式ワークフローの内部状態を確認し、エラーとなったワークフローを検出するサンプル スクリプトをご紹介します。

事前準備

下記の内容を実施済みのクライアント環境においては、事前準備の項目を再度実施する必要はございません。

1 : SharePoint Online Client Components SDK のダウンロード

サンプル スクリプトを実行するための実行環境として SharePoint Online Client Components SDK をダウンロードします。

以下のリンクよりダウンロード可能です。

タイトル : SharePoint Online Client Components SDK
アドレス : https://www.microsoft.com/en-us/download/details.aspx?id=42038

 

2 : スクリプトの実行ポリシーを変更する

1)PowerShell を管理者として起動します。
2) 以下のコマンドを実行し、現在の PowerShell の実行ポリシーを確認します。

Get-ExecutionPolicy

3) 以下のコマンドを実行し、PowerShell の実行ポリシーを変更します。

Set-ExecutionPolicy RemoteSigned

補足 : RemoteSigned 以上の実行ポリシー (例. Unrestricted) が指定されている場合は、指定の必要はありません。

  

コードの実行

1) 以下のコードを GetWfStatus.ps1 として保存します。

param(
 $siteUrl,
 $listName,
 $username,
 $password,
 $outfile,
 $resume = $false
)

Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.WorkflowServices.dll"

function ExecuteQueryWithIncrementalRetry($retryCount, $delay)
{
  $retryAttempts = 0;
  $backoffInterval = $delay;
  if ($retryCount -le 0)
  {
    throw "Provide a retry count greater than zero."
  }
  if ($delay -le 0)
  {
    throw "Provide a delay greater than zero."
  }
  while ($retryAttempts -lt $retryCount)
  {
    try
    {
      $script:context.ExecuteQuery();
      return;
    }
    catch [System.Net.WebException]
    {
      $response = $_.Exception.Response
      if ($response -ne $null -and $response.StatusCode -eq 429)
      {
        Write-Host ("CSOM request exceeded usage limits. Sleeping for {0} seconds before retrying." -F ($backoffInterval/1000))
        #Add delay.
        Start-Sleep -m $backoffInterval
        #Add to retry count and increase delay.
        $retryAttempts++;
        $backoffInterval = $backoffInterval * 2;
      }
      else
      {
        throw;
      }
    }
  }
  throw "Maximum retry attempts {0}, have been attempted." -F $retryCount;
}

function EnumWorkflowsInFolder($list, $ServerRelativeUrl)
{
  do
  {
    $camlQuery = New-Object Microsoft.SharePoint.Client.CamlQuery
    $camlQuery.ListItemCollectionPosition = $position
    $camlQuery.ViewXml = "<View><RowLimit>5000</RowLimit></View>";
    if ($serverRelativeUrl -ne $null)
    {
       $camlQuery.FolderServerRelativeUrl = $ServerRelativeUrl
    }
    $listItems = $list.GetItems($camlQuery);
    $script:context.Load($listItems);
    ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000

    foreach($listItem in $listItems)
    {
      if ($listItem.FileSystemObjectType -eq [Microsoft.SharePoint.Client.FileSystemObjectType]::Folder)
      {
         $script:context.Load($listItem.Folder)
         ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000
         EnumWorkflowsInFolder -List $list -ServerRelativeUrl $listItem.Folder.ServerRelativeUrl
      }

      $wfic = $script:wfis.EnumerateInstancesForListItem($list.Id, $listItem.Id);
      $script:context.Load($wfic);
      ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000
 
      foreach ($wfi in $wfic)
      {
        WriteOut -text (($listItem.Id.ToString()) + "," + (GetWorkflowSubscription -subid $wfi.WorkflowSubscriptionId) + "," + $wfi.Status) -append $true
        if ($resume)
        {
            if ($wfi.Status -eq "Suspended")
            {
                $script:wfis.ResumeWorkflow($wfi)
                ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000
                Write-Output ("Resumed workflow on Item ID = " + $listItem.Id.ToString())
            }
        }
      }
    } 
    $position = $listItems.ListItemCollectionPosition
  }
  while($position -ne $null)
}

function GetWorkflowSubscription($subid)
{
  if ($script:wfsubhash[$subid.ToString()] -eq $null)
  {    
    $sub = $script:wfss.GetSubscription($subid)
    $script:context.Load($sub)
    ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000

    $script:wfsubhash[$subid.ToString()] = $sub.Name
    return $sub.Name
  }
  else
  {
    return $script:wfsubhash[$subid.ToString()]
  }
}

function WriteOut($text, $append)
{
  if ($outfile -eq $null)
  {
    Write-Output $text
  }
  else
  {
    if ($append)
    {
      $text | Out-File $outfile -Append -Encoding UTF8
    }
    else
    {
      $text | Out-File $outfile -Encoding UTF8
    }
  }
}

$script:context = new-object Microsoft.SharePoint.Client.ClientContext($siteUrl)
$pwd = convertto-securestring $password -AsPlainText -Force
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $pwd)
$script:context.Credentials = $credentials

$wfsm = new-object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager($script:context, $script:context.Web)
$script:wfss = $wfsm.GetWorkflowSubscriptionService();
$script:wfsubhash = @{}
$script:wfis = $wfsm.GetWorkflowInstanceService();

$list = $script:context.Web.Lists.GetByTitle($listName)
$script:context.Load($list)
ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000

$wfSubs = $wfss.EnumerateSubscriptionsByList($list.Id);
$script:context.Load($wfSubs);
ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000

WriteOut -text "ItemId,WorkflowName,Status" 
EnumWorkflowsInFolder -List $list -serverRelativeUrl $null

 

2) PowerShell  を起動します。
3) スクリプトを配置したフォルダーに移動し、作成した .ps1 ファイルを以下のように実行します。

.\getwfstatus.ps1 -siteUrl https://tenant.sharepoint.com/sites/workflowsite -listName ドキュメント -username account@tenant.onmicrosoft.com -password password

パラメータ

-siteUrl ・・・ サイトのアドレス
-listName ・・・ リスト名
-username ・・・ 処理を実行するユーザー
-password ・・・ 上記ユーザーのパスワード
-outfile ・・・ 出力先ファイル (省略可 : 既定値はコンソール出力)
-resume ・・・ $true の場合 一旦停止したワークフローを強制開始 (省略可 : 既定値 $false)

補足

  • リスト ビューのしきい値と、HTTP 調整対策の内、増分バックオフ リトライに対応しています。
  • 大規模なリストに対して、本スクリプトを実行する場合、HTTP 要求数が増える可能性があります。万が一のことを想定し、オフピークの時間帯に実行してください。

今回の投稿は以上です。

本情報の内容は、作成日時点でのものであり、予告なく変更される場合があります。

 


Viewing all articles
Browse latest Browse all 182

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>