読者です 読者をやめる 読者になる 読者になる

からめもぶろぐ。

SharePoint が得意なフレンズなんだね!すごーい!

SPClient 0.8 をリリースしました

www.powershellgallery.com

データ取得で * (アスタリスク) による指定ができるようになりました。つまり、こんな風に呼び出せます。

Get-SPClientWeb -Default -Retriavals "*,Lists.Include(*)"

これは内部的に以下のように変換されます。

clientContext.Load(clientContext.Web, web => web, web => web.Lists.IncludeWithDefaultProperties(list => list))

また、データの取得において、キャッシュを使うのをやめました。これにより、コマンドの実行ごとにサーバーへのリクエストが発生することになり、パフォーマンスの劣化が想定されますが、キャッシュをすることによる弊害のほうが大きいため、このような変更となりました。ちなみに、SharePoint 2016 の CSOM ではキャッシュの有無を指定できるようになっているようです。ぐぬぬ。

ClientRuntimeContext.DisableReturnValueCache property (Microsoft.SharePoint.Client)

CSOM で実行される Web リクエストを取得する

CSOM では内部的に Web リクエストを発行していて、どういうリクエストが流れているかを見るためには Fiddler などのツールを使わないといけないのですが、とても面倒くさいので、コードから取得できるようにしてみました。ちなみに ExecutingWebRequest イベントで取れる e.WebRequestExecutor.GetRequestStream は CanRead が false なので読み取りできません。なのでリフレクションでごにょごにょしています。

    public static class Program {

        private static void Main(string[] args) {
            var url = "<サイトの URL>";
            var userName = "<ユーザー名>";
            var rawPassword = "<パスワード>";
            var securePasseord = new SecureString();
            foreach (var c in rawPassword) {
                securePasseord.AppendChar(c);
            }
            using (var ctx = new ClientContext(url)) {
                ctx.Credentials = new SharePointOnlineCredentials(userName, securePasseord);
                ctx.ExecutingWebRequest += (sender, e) => {
                    var clientRequestType = ctx.PendingRequest.GetType();
                    var buildQueryMethod = clientRequestType.GetMethod("BuildQuery", BindingFlags.Instance | BindingFlags.NonPublic);
                    var chunkStringBuilderObject = buildQueryMethod.Invoke(ctx.PendingRequest, null);
                    var chunkStringBuilderType = chunkStringBuilderObject.GetType();
                    var createTextReaderMethod = chunkStringBuilderType.GetMethod("CreateTextReader", BindingFlags.Instance | BindingFlags.Public);
                    var textReader = createTextReaderMethod.Invoke(chunkStringBuilderObject, null) as TextReader;
                    Console.WriteLine(textReader.ReadToEnd());
                };
                var web = ctx.Web;
                ctx.Load(web);
                ctx.ExecuteQuery();
            }
            Console.ReadLine();
        }

    }

実行するとこんな感じ。

<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName=".NET Library" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009">
    <Actions>
        <ObjectPath Id="2" ObjectPathId="1" />
        <ObjectPath Id="4" ObjectPathId="3" />
        <Query Id="5" ObjectPathId="3">
            <Query SelectAllProperties="true">
                <Properties />
            </Query>
        </Query>
    </Actions>
    <ObjectPaths>
        <StaticProperty Id="1" TypeId="{3747adcd-a3c3-41b9-bfab-4a64dd2f1e0a}" Name="Current" />
        <Property Id="3" ParentId="1" Name="Web" />
    </ObjectPaths>
</Request>

SPClient 0.7 をリリースしました

www.powershellgallery.com

コンテンツ タイプを取得、追加、削除するコマンドレットを追加しました。
また、いくつかのコマンドレットについて、よりわかりやすいように動詞を変更しました。

そろそろドキュメント ライブラリやファイルを操作するコマンドレットも追加しないとですねえ。

SPClient 0.6 をリリースしました

www.powershellgallery.com

そういえば 0.5 の告知を忘れてましたが、0.6 をリリースしました。

New-SPClient 系のコマンドレットが追加されました。特に New-SPClientField 系は強力です。CSOM の場合、Field の作成は Schema.xml を理解しないとできないのですが、その知識なしでも Field が作成できるようになっています。設定できるパラメーターも UI 互換になっていますので、UI からやりたいことが直感的にコマンドレットで書くことができます。また、戻り値が作成された種類に合致するクラスで帰ってきますので、ClientRuntimeContext.CastTo メソッドを使う必要がありません。

ClientRuntimeContext.CastTo(T) method (Microsoft.SharePoint.Client)

CSOM の Site.OpenWeb メソッドで File Not Found が発生する件について

CSOM で以下のコードのように同じサイトを作成したり削除したりを繰り返すと ServerException (File Not Found) が発生します。
最初はタイミングの問題かなと思ったのですが、スリープを入れても常に発生するので、そういう問題でもなさそう。

$context.Load($context.Site)
$context.ExecuteQuery()

for ($i = 0; $i -lt 2; $i++) {
    # サイトを作成する
    $web = New-Object Microsoft.SharePoint.Client.WebCreationInformation
    $web.Url = 'TeamSite1'
    $context.Web.Webs.Add($web) | Out-Null
    $context.ExecuteQuery()

    # サイトを取得する
    $web = $context.Site.OpenWeb($context.Site.ServerRelativeUrl + '/TeamSite1')
    $context.Load($web)
    $context.ExecuteQuery()

    # サイトを削除する
    $web.DeleteObject()
    $context.ExecuteQuery()
}

そこで OpenWeb の実装を ILSpy で見てみたところ。

f:id:karamem0:20170421114549p:plain

( ゚д゚)

(つд⊂)ゴシゴシ

(;゚д゚)

Site.OpenWeb method (Microsoft.SharePoint.Client)