Quantcast
Channel: Japan SharePoint Support Team Blog
Viewing all 144 articles
Browse latest View live

サンプル コード : 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 要求数が増える可能性があります。万が一のことを想定し、オフピークの時間帯に実行してください。

今回の投稿は以上です。

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

 


Project Online の [Project] タイルの動作変更について

$
0
0

こんにちは、サポートの森村です。
本記事では Project Online [Project] タイルを使用した場合の動作について、弊社の米国のエンジニアが公開済みの下記ブログ記事の内容についてご案内いたします。

タイトル : Project Online: The new Home experience
タイトル : https://blogs.technet.microsoft.com/projectsupport/2018/08/15/project-online-the-new-home-experience/

Project Online 関連のサブスクリプション (Project Online PremiumProject Online ProfessionalProject Online Essentials) のライセンスを割り当てているユーザーの場合、Office 365 にサインインするとアプリケーション ランチャーに [Project] のタイルが含まれています。
本日 2018/8/28 時点では [Project] タイルをクリックすると、既定の Project Web Access サイトコレクション (PWA サイト) である、/sites/pwa にアクセスする動作となっております。
こちらの動作を、近日中に変更し、下記のような「Project ホーム画面」 (https://project.microsoft.com/) に移動する動作となる予定です。
[Project]
タイルの動作を以前のままにする、等の設定変更はできませんので、従来通り /sites/pwa PWA サイトへの直接アクセスが必要な場合は、ブックマーク等の機能を利用いただくか、あるいは Project ホーム画面最下部の [Project Web App に移動] をクリックしてください。

Project ホーム画面

画面の説明
● [新規作成] メニュー

既定の PWA サイト (/sites/pwa) 上でプロジェクトの作成権限がある場合は、こちらのメニューから既定の PWA サイト上に新規プロジェクト作成を行うことが可能です。
なお、既定の PWA サイト以外の別の PWA サイトに対し新規プロジェクトを作成することはできません。また、作成する PWA サイトを変更することもできません。

● [お気に入り]
下部の [最近] に表示されているプロジェクトをマウスでポイントし、☆マークをクリックするか、三点リーダーメニューから [お気に入りに追加] を選択すると、お気に入りのプロジェクトとして表示されます。

● [最近]
最近該当ユーザーによって作成、編集されたプロジェクトの一覧が表示されます。クリックすると該当プロジェクトが [プロジェクト センター] 上で表示されるページに移動します。
複数の PWA サイトを使用しているユーザーの場合は、既定の /sites/pwa PWA サイト以外の PWA サイトで作成したプロジェクトについても表示が行われ、またクリックすることで別 PWA サイト上のプロジェクトが表示される動作となります。

● [Project Web App に移動]
既定の PWA サイト (/sites/pwa) に移動します。

関連ブログ情報
PWA サイトにアクセスするためには、Project Online 関連のライセンス付与の他に、PWA サイトへのアクセス権付与が必要です。
詳細は下記のブログ記事などをご確認ください。

タイトル : Project Online を使用する際にはライセンスおよびアクセス権限の割り当てが必要です
アドレス : https://blogs.technet.microsoft.com/sharepoint_support/2015/04/06/project-online/

今回の投稿は以上です。


本情報の内容(添付文書、リンク先などを含む)は、作成日時点でのものであり、予告なく変更される場合があります。

構造ナビゲーション、CQWP によるパフォーマンス劣化について

$
0
0

以下の公開情報でご案内しておりますように、SharePoint Online で構造ナビゲーション、コンテンツ クエリ Web パーツ (以下、CQWP と略します) を利用するとデータベースに負荷が生じ、サイト アクセス時にパフォーマンス劣化が生じる場合がございます。

 

タイトル : SharePoint Online のパフォーマンス チューニングについて

アドレス : https://blogs.technet.microsoft.com/sharepoint_support/2018/06/25/spo-performance-tuning/

 

構造ナビゲーション、CQWP を以前からご利用されており、特に設定変更や運用の変更などを実施していないにも関わらず、突然パフォーマンスが劣化することについての疑問を頻繁にお問い合わせいただくため、以下に考えられる要因をご紹介いたします。

なお、上述の公開情報に記載のとおり、構造ナビゲーション、CQWP を利用することによってパフォーマンスが劣化する場合、データセンター側でのサーバーのリソース増強などによる対応は効果的ではありません。

よりパフォーマンスに優れる代替機能への置き換えや、パフォーマンスのチューニングが有効な対処となりますので、構造ナビゲーション、CQWP をご利用されている場合は上述の公開情報を参考にお早めに対処をご検討ください。

 

パフォーマンス劣化が生じる要因について

構造ナビゲーション、CQWP は負荷の大きなクエリがデータベースに対して実行されるため、データベースのリソースを消費し、データベースからの応答が遅延することでパフォーマンスが劣化します。

SharePoint Online は単一のデータベースに複数のサイト コレクションの情報や、テナントの規模によっては OneDrive for Business の情報も保持されるため、当該機能によるパフォーマンス劣化の影響範囲としては、最大でテナント全体となります。

 

SharePoint Online はデータセンター側で継続して動作が追加/更新されており、また SaaS 型の共有サービスのため、他のテナントとサーバーやデータベースも共有しております。

突然発生したパフォーマンスの劣化は、主にこの様な要因が影響しており、以下に考えられる具体的なシナリオをご案内いたします。

 

1.     フロントエンドサーバーの増加、キャッシュの廃止

SharePoint Online は利用者が継続して増加しており、現在多くのフロントエンドサーバーが稼働している状況となります。

構造ナビゲーションや CQWP は従来よりデータベースへの負荷が大きな機能となるため、フロントエンド サーバーのキャッシュを利用することでパフォーマンスを維持しておりました。

しかしながら、利用者の増加に伴いフロントエンド サーバーの数が増えることにより、キャッシュ ヒット率が極めて小さくなりました。

キャッシュにヒットしない場合はデータベースへ接続する動作となるため、SharePoint Online の利用者の増加と共にデータベースへの負荷がより生じやすい状況 (パフォーマンス劣化が生じやすい) となりました。

フロントエンドサーバーのキャッシュは非効率にメモリを消費するだけとなり、現時点においては構造ナビゲーションや CQWP でのキャッシュ利用は廃止されております。

 

2.     データベースが保持する情報の増加

運用を継続すると共に、データベースが保持する情報は増加することが想定されます。

また、上述の通りデータベースは複数のテナントで共有されているため、自社テナント以外が要因でデータが増えることも想定されます。

データベースが保持する情報が増えると、同じクエリでもクエリ対象のデータが増加し、一般的に負荷は増加します。

データベースが保持する情報の増加による負荷の増加は、その他の機能においては通常は影響が生じない程度となりますが、データベースへの負荷が大きい構造ナビゲーションや CQWP はより影響を受け、パフォーマンス劣化が生じる可能性があります。

 

3.     バックエンドの処理の変更

SharePoint Online はバックエンドで様々な処理やメンテナンス タスクが動作しており、これらも継続して機能が追加、更新されています。

バックエンドの処理もテナントが利用するデータベースにアクセスするため、これらの追加、更新によって以前よりもデータベースのリソース消費量が以前より相対的に大きくなる場合があります。

一般的なご利用においては影響が生じないようにバックエンドの処理も設計されておりますが、データベースへの負荷が大きい構造ナビゲーションや CQWP はより影響を受ける可能性があります。

 

 

今回の投稿は以上です。

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

[改訂版] SharePoint Online HTTP 調整 (応答コード : 429) 対策の増分バックオフ リトライ

$
0
0

過去のブログ投稿でもご案内しておりますように、CSOM などのクライアント サイド API を利用するプログラムにおいて、HTTP 調整機能への対策として増分バックオフ リトライを実装することを推奨しています。

タイトル: PowerShell サンプル : SharePoint Online HTTP 調整 (応答コード : 429) 対策の増分バックオフ リトライ
アドレス: https://blogs.technet.microsoft.com/sharepoint_support/2016/10/08/powershell-csom-sample-code-for-spo-http-429-incremental-backoff-retry/

 

従来弊社より案内していた増分バックオフ リトライのサンプル コードでは、Exponential Backoff というアルゴリズム (指数関数的にリトライ間隔を大きくする実装) を推奨していましたが、最新のベスト プラクティスにおいては、HTTP 応答の “Retry-After” ヘッダーの値を利用してリトライ間隔を指定する実装を推奨しています。本実装は、SharePoint Online だけでなく、Microsoft Graph API 等においても同様の推奨事項となります。

 

タイトル: SharePoint Online で調整またはブロックを回避する
アドレス: https://docs.microsoft.com/ja-jp/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online

タイトル: Microsoft Graph throttling guidance
アドレス: https://developer.microsoft.com/en-us/graph/docs/concepts/throttling

 

本稿では、冒頭のブログで紹介している PowerShell で実装した増分バックオフ リトライを、最新のベスト プラクティスに変更したサンプルコードを紹介します。

HTTP 調整機能への対策としては、トラフィックの修飾 (User Agent の指定) も有効となりますので、併せてサンプルコードで実装しています。

 

$siteUrl = "https://tenant.sharepoint.com"

# 必要なアセンブリをロードします
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";

# SPO に接続します
$script:context = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl);

# ユーザー名入力を促します。
Write-Host "Please input user name : "
$username = Read-Host

# パスワード入力を促します。
Write-Host "Please input password : "
$password = Read-Host -AsSecureString

$creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password);
$script:context.Credentials = $creds;

# UserAgent を指定します。
$script:context.add_ExecutingWebRequest({
    param ($source, $eventArgs);
    $request = $eventArgs.WebRequestExecutor.WebRequest;
    $request.UserAgent = "NONISV|Contoso|Application/1.0";
})

function ExecuteQueryWithIncrementalRetry {
    param (
        [parameter(Mandatory = $true)]
        [int]$retryCount
    );

    $DefaultRetryAfterInMs = 120000;
    $RetryAfterHeaderName = "Retry-After";
    $retryAttempts = 0;

    if ($retryCount -le 0) {
        throw "Provide a retry count greater than zero."
    }

    while ($retryAttempts -lt $retryCount) {
        try {
            $script:context.ExecuteQuery();
            return;
        }
        catch [System.Net.WebException] {
            $response = $_.Exception.Response

            if (($null -ne $response) -and (($response.StatusCode -eq 429) -or ($response.StatusCode -eq 503))) {
                $retryAfterHeader = $response.GetResponseHeader($RetryAfterHeaderName);
                $retryAfterInMs = $DefaultRetryAfterInMs;

                if (-not [string]::IsNullOrEmpty($retryAfterHeader)) {
                    if (-not [int]::TryParse($retryAfterHeader, [ref]$retryAfterInMs)) {
                        $retryAfterInMs = $DefaultRetryAfterInMs;
                    }
                    else {
                        $retryAfterInMs *= 1000;
                    }
                }

                Write-Output ("CSOM request exceeded usage limits. Sleeping for {0} seconds before retrying." -F ($retryAfterInMs / 1000))
                #Add delay.
                Start-Sleep -m $retryAfterInMs
                #Add to retry count.
                $retryAttempts++;
            }
            else {
                throw;
            }
        }
    }

    throw "Maximum retry attempts {0}, have been attempted." -F $retryCount;
}

# ここから実装したい任意のコードを書きます。
$web = $script:context.Web
$script:context.Load($web)
#$context.ExecuteQuery() を以下に置き換えます。
ExecuteQueryWithIncrementalRetry -retryCount 5
$web.Title = "RetryTest"
$web.Update()
#$context.ExecuteQuery() を以下に置き換えます。
ExecuteQueryWithIncrementalRetry -retryCount 5

 

 

今回の投稿は以上です。

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

Viewing all 144 articles
Browse latest View live


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