Windows PowerShell コンテンツ プロバイダーを作成する

このトピックでは、ユーザーがデータ ストア内の項目Windows PowerShell操作できるデータ プロバイダーを作成する方法について説明します。 その結果、項目の内容を操作できるプロバイダーは、コンテンツ プロバイダーのWindows PowerShellされます。

注意

このプロバイダーの C# ソース ファイル (AccessDBSampleProvider06.cs) は、Microsoft Windows Software Development Kit for Windows Vista および .NET Framework 3.0 ランタイム コンポーネントを使用してダウンロードできます。 ダウンロード手順については、「インストール方法」および「Windows PowerShell SDK のダウンロード」をWindows PowerShellしてください。 ダウンロードしたソース ファイルは ディレクトリで使用 <PowerShell Samples> できます。 その他のプロバイダー実装のWindows PowerShellについては、「 Designing Your Windows PowerShell Provider 」を参照してください

コンテンツ プロバイダー Windows PowerShellを定義する

コンテンツWindows PowerShell、System.Management.Automation.Provider.Icontentcmdletproviderインターフェイスをサポートする .NET クラスを作成する必要があります。 このセクションで説明する項目プロバイダーのクラス定義を次に示します。

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider, IContentCmdletProvider

このクラス定義では 、System.Management.Automation.Provider.Cmdletproviderattribute 属性に 2 つのパラメーターが含まれています。 1 番目のパラメーターは、このパラメーターで使用されるプロバイダーのユーザー Windows PowerShell。 2 番目のパラメーターは、Windows PowerShell実行時にプロバイダーがランタイムに公開する特定の機能Windows PowerShell指定します。 このプロバイダーでは、特定の機能Windows PowerShell追加されません。

基本クラスの機能を定義する

「Design Your Windows PowerShell Provider」で説明したように、System.Management.Automation.Provider.Navigationcmdletproviderクラスは、異なるプロバイダー機能を提供する他のいくつかのクラスから派生します。 したがってWindows PowerShellプロバイダーでは、通常、これらのクラスによって提供される機能すべてが定義されます。

セッション固有の初期化情報を追加する機能を実装する方法と、プロバイダーによって使用されるリソースを解放する方法の詳細については、「基本的な初期化プロバイダーの作成」をWindows PowerShellしてください。 ただし、ここで説明するプロバイダーを含むほとんどのプロバイダーでは、この機能の既定の実装を使用できます。この実装は、Windows PowerShell。

データ ストアにアクセスするには、プロバイダーが System.Management.Automation.Provider.Drivecmdletprovider 基本クラスのメソッドを実装する必要があります。 これらのメソッドの実装の詳細については、「 Creating a Windows PowerShell Drive Provider 」を参照してください

項目の取得、設定、クリアなど、データ ストアの項目を操作するには、プロバイダーが System.Management.Automation.Provider.Itemcmdletprovider 基本クラスによって提供されるメソッドを実装する必要があります。 これらのメソッドの実装の詳細については、「項目プロバイダーの作成Windows PowerShell参照してください

多層データ ストアで動作するには、プロバイダーが System.Management.Automation.Provider.Containercmdletprovider 基本クラスによって提供されるメソッドを実装する必要があります。 これらのメソッドの実装の詳細については、「コンテナー プロバイダーの作成」Windows PowerShell参照してください

再帰コマンド、入れ子になったコンテナー、および相対パスをサポートするには、プロバイダーが System.Management.Automation.Provider.Navigationcmdletprovider 基本クラスを実装する必要があります。 さらに、この Windows PowerShell コンテンツ プロバイダーはSystem.Management.Automation.Provider.IcontentcmdletproviderインターフェイスをSystem.Management.Automation.Provider.Navigationcmdletprovider基本クラスにアタッチできます。そのため、そのクラスによって提供されるメソッドを実装する必要があります。 詳細については、これらのメソッドの実装に関するページを参照してください。「 Implement a Navigation Windows PowerShell Provider 」を参照してください

コンテンツ リーダーの実装

項目からコンテンツを読み取る場合、プロバイダーは System.Management.Automation.Provider.Icontentreaderから派生するコンテンツ リーダー クラスを実装する必要があります。 このプロバイダーのコンテンツ リーダーを使用すると、データ テーブル内の行の内容にアクセスできます。 コンテンツ リーダー クラスは、指定された行からデータを取得し、そのデータを表すリスト、コンテンツ リーダーを移動する Seek メソッド、コンテンツ リーダーを閉じる Close メソッド 、Dispose メソッドを返す Read メソッドを定義します。

public class AccessDBContentReader : IContentReader
{
    // A provider instance is required so as to get "content"
    private AccessDBProvider provider;
    private string path;
    private long currentOffset;

    internal AccessDBContentReader(string path, AccessDBProvider provider)
    {
        this.path = path;
        this.provider = provider;
    }

    /// <summary>
    /// Read the specified number of rows from the source.
    /// </summary>
    /// <param name="readCount">The number of items to 
    /// return.</param>
    /// <returns>An array of elements read.</returns>
    public IList Read(long readCount)
    {
        // Read the number of rows specified by readCount and increment
        // offset
        string tableName;
        int rowNumber;
        PathType type = provider.GetNamesFromPath(path, out tableName, out rowNumber);

        Collection<DatabaseRowInfo> rows =
            provider.GetRows(tableName);
        Collection<DataRow> results = new Collection<DataRow>();

        if (currentOffset < 0 || currentOffset >= rows.Count)
        {
            return null;
        }

        int rowsRead = 0;

        while (rowsRead < readCount && currentOffset < rows.Count)
        {
            results.Add(rows[(int)currentOffset].Data);
            rowsRead++;
            currentOffset++;
        }

        return results;
    } // Read

    /// <summary>
    /// Moves the content reader specified number of rows from the 
    /// origin
    /// </summary>
    /// <param name="offset">Number of rows to offset</param>
    /// <param name="origin">Starting row from which to offset</param>
    public void Seek(long offset, System.IO.SeekOrigin origin)
    {
        // get the number of rows in the table which will help in
        // calculating current position
        string tableName;
        int rowNumber;

        PathType type = provider.GetNamesFromPath(path, out tableName, out rowNumber);

        if (type == PathType.Invalid)
        {
            throw new ArgumentException("Path specified must represent a table or a row :" + path);
        }

        if (type == PathType.Table)
        {
            Collection<DatabaseRowInfo> rows = provider.GetRows(tableName);

            int numRows = rows.Count;

            if (offset > rows.Count)
            {
                throw new
                       ArgumentException(
                           "Offset cannot be greater than the number of rows available"
                                        );
            }

            if (origin == System.IO.SeekOrigin.Begin)
            {
                // starting from Beginning with an index 0, the current offset
                // has to be advanced to offset - 1
                currentOffset = offset - 1;
            }
            else if (origin == System.IO.SeekOrigin.End)
            {
                // starting from the end which is numRows - 1, the current
                // offset is so much less than numRows - 1
                currentOffset = numRows - 1 - offset;
            }
            else
            {
                // calculate from the previous value of current offset
                // advancing forward always
                currentOffset += offset;
            }
        } // if (type...
        else
        {
            // for row, the offset will always be set to 0
            currentOffset = 0;
        }

    } // Seek

    /// <summary>
    /// Closes the content reader, so all members are reset
    /// </summary>
    public void Close()
    {
        Dispose();
    } // Close

    /// <summary>
    /// Dispose any resources being used
    /// </summary>
    public void Dispose()
    {
        Seek(0, System.IO.SeekOrigin.Begin);
        
        GC.SuppressFinalize(this);
    } // Dispose
} // AccessDBContentReader

コンテンツ ライターの実装

項目にコンテンツを書き込むには、プロバイダーが System.Management.Automation.Provider.Icontentwriterから派生したコンテンツ ライター クラスを実装する必要があります。 コンテンツ ライター クラスは、指定した行コンテンツを書き込む Write メソッド、コンテンツ ライターを移動する Seek メソッド、コンテンツ ライターを閉じる Close メソッド 、Dispose メソッドを定義します。

public class AccessDBContentWriter : IContentWriter
{
    // A provider instance is required so as to get "content"
    private AccessDBProvider provider;
    private string path;
    private long currentOffset;

    internal AccessDBContentWriter(string path, AccessDBProvider provider)
    {
        this.path = path;
        this.provider = provider;
    }

    /// <summary>
    /// Write the specified row contents in the source
    /// </summary>
    /// <param name="content"> The contents to be written to the source.
    /// </param>
    /// <returns>An array of elements which were successfully written to 
    /// the source</returns>
    /// 
    public IList Write(IList content)
    {
        if (content == null)
        {
            return null;
        }

        // Get the total number of rows currently available it will 
        // determine how much to overwrite and how much to append at
        // the end
        string tableName;
        int rowNumber;
        PathType type = provider.GetNamesFromPath(path, out tableName, out rowNumber);

        if (type == PathType.Table)
        {
            OdbcDataAdapter da = provider.GetAdapterForTable(tableName);
            if (da == null)
            {
                return null;
            }

            DataSet ds = provider.GetDataSetForTable(da, tableName);
            DataTable table = provider.GetDataTable(ds, tableName);

            string[] colValues = (content[0] as string).Split(',');

            // set the specified row
            DataRow row = table.NewRow();

            for (int i = 0; i < colValues.Length; i++)
            {
                if (!String.IsNullOrEmpty(colValues[i]))
                {
                    row[i] = colValues[i];
                }
            }

            //table.Rows.InsertAt(row, rowNumber);
            // Update the table
            table.Rows.Add(row);
            da.Update(ds, tableName);
            
        }
        else 
        {
            throw new InvalidOperationException("Operation not supported. Content can be added only for tables");
        }

        return null;
    } // Write

    /// <summary>
    /// Moves the content reader specified number of rows from the 
    /// origin
    /// </summary>
    /// <param name="offset">Number of rows to offset</param>
    /// <param name="origin">Starting row from which to offset</param>
    public void Seek(long offset, System.IO.SeekOrigin origin)
    {
        // get the number of rows in the table which will help in
        // calculating current position
        string tableName;
        int rowNumber;

        PathType type = provider.GetNamesFromPath(path, out tableName, out rowNumber);

        if (type == PathType.Invalid)
        {
            throw new ArgumentException("Path specified should represent either a table or a row : " + path);
        }

        Collection<DatabaseRowInfo> rows =
               provider.GetRows(tableName);

        int numRows = rows.Count;

        if (offset > rows.Count)
        {
            throw new
                   ArgumentException(
                       "Offset cannot be greater than the number of rows available"
                                           );
        }

        if (origin == System.IO.SeekOrigin.Begin)
        {
            // starting from Beginning with an index 0, the current offset
            // has to be advanced to offset - 1
            currentOffset = offset - 1;
        }
        else if (origin == System.IO.SeekOrigin.End)
        {
            // starting from the end which is numRows - 1, the current
            // offset is so much less than numRows - 1
            currentOffset = numRows - 1 - offset;
        }
        else
        {
            // calculate from the previous value of current offset
            // advancing forward always
            currentOffset += offset;
        }

    } // Seek

    /// <summary>
    /// Closes the content reader, so all members are reset
    /// </summary>
    public void Close()
    {
        Dispose();
    } // Close

    /// <summary>
    /// Dispose any resources being used
    /// </summary>
    public void Dispose()
    {
        Seek(0, System.IO.SeekOrigin.Begin);

        GC.SuppressFinalize(this);
    } // Dispose
} // AccessDBContentWriter

コンテンツ リーダーの取得

項目からコンテンツを取得するには、コマンドレットをサポートするために、プロバイダーが System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader* を実装する必要 Get-Content があります。 このメソッドは、指定したパスにある項目のコンテンツ リーダーを返します。 その後、リーダー オブジェクトを開いてコンテンツを読み取ります。

このプロバイダーのこのメソッドに対する System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader* の実装を次に示します。

public IContentReader GetContentReader(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type == PathType.Invalid)
    {
        ThrowTerminatingInvalidPathException(path);
    }
    else if (type == PathType.Row)
    {
        throw new InvalidOperationException("contents can be obtained only for tables");
    }

    return new AccessDBContentReader(path, this);
} // GetContentReader
public IContentReader GetContentReader(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type == PathType.Invalid)
    {
        ThrowTerminatingInvalidPathException(path);
    }
    else if (type == PathType.Row)
    {
        throw new InvalidOperationException("contents can be obtained only for tables");
    }

    return new AccessDBContentReader(path, this);
} // GetContentReader

GetContentReader の実装に関する注意

System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader*の実装には、次の条件が適用される場合があります。

動的パラメーターを Get-Content コマンドレットにアタッチする

コマンドレット Get-Content では、実行時に動的に指定される追加のパラメーターが必要になる場合があります。 これらの動的パラメーターを指定するには、Windows PowerShell コンテンツ プロバイダーがSystem.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreaderdynamicparameters*メソッドを実装する必要があります。 このメソッドは、指定されたパスにある項目の動的パラメーターを取得し、コマンドレット クラスまたは System.Management.Automation.Runtimedefinedparameterdictionary オブジェクトに似た属性を解析するプロパティとフィールドを持つオブジェクトを返します。 このWindows PowerShell返されたオブジェクトを使用して、コマンドレットにパラメーターを追加します。

このWindows PowerShellプロバイダーは、このメソッドを実装していない場合があります。 ただし、次のコードは、このメソッドの既定の実装です。

public object GetContentReaderDynamicParameters(string path)
{
    return null;
}
public object GetContentReaderDynamicParameters(string path)
{
    return null;
}

コンテンツ ライターの取得

項目にコンテンツを書き込むには、プロバイダーが および コマンドレットをサポートするためにSystem.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter*を実装する必要があります。 Set-Content Add-Content このメソッドは、指定したパスにある項目のコンテンツ ライターを返します。

このメソッドの System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter* の実装を次に示します。

public IContentWriter GetContentWriter(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type == PathType.Invalid)
    {
        ThrowTerminatingInvalidPathException(path);
    }
    else if (type == PathType.Row)
    {
        throw new InvalidOperationException("contents can be added only to tables");
    }

    return new AccessDBContentWriter(path, this);
}
public IContentWriter GetContentWriter(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type == PathType.Invalid)
    {
        ThrowTerminatingInvalidPathException(path);
    }
    else if (type == PathType.Row)
    {
        throw new InvalidOperationException("contents can be added only to tables");
    }

    return new AccessDBContentWriter(path, this);
}

GetContentWriter の実装に関する注意

System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter*の実装には、次の条件が適用される場合があります。

動的パラメーターを Add-Content および Set-Content コマンドレットにアタッチする

コマンドレット Add-ContentSet-Content コマンドレットでは、ランタイムを追加する動的パラメーターを追加する必要がある場合があります。 これらの動的パラメーターを指定するには、Windows PowerShell コンテンツ プロバイダーがSystem.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriterdynamicparameters*メソッドを実装して、これらのパラメーターを処理する必要があります。 このメソッドは、指定されたパスにある項目の動的パラメーターを取得し、コマンドレット クラスまたは System.Management.Automation.Runtimedefinedparameterdictionary オブジェクトに似た属性を解析するプロパティとフィールドを持つオブジェクトを返します。 ランタイムWindows PowerShell返された オブジェクトを使用して、コマンドレットにパラメーターを追加します。

このWindows PowerShellプロバイダーは、このメソッドを実装していない場合があります。 ただし、次のコードは、このメソッドの既定の実装です。

public object GetContentWriterDynamicParameters(string path)
{
    return null;
}

コンテンツのクリア

コンテンツ プロバイダーは、 コマンドレットをサポート する System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* メソッドを実装 Clear-Content します。 このメソッドは、指定されたパスにある項目の内容を削除しますが、項目はそのまま残ります。

このプロバイダーの System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* メソッドの実装を次に示します。

public void ClearContent(string path)
{
    string tableName;
    int rowNumber;

    PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

    if (type != PathType.Table)
    {
        WriteError(new ErrorRecord(
            new InvalidOperationException("Operation not supported. Content can be cleared only for table"),
                "NotValidRow", ErrorCategory.InvalidArgument,
                    path));
        return;
    }

    OdbcDataAdapter da = GetAdapterForTable(tableName);

    if (da == null)
    {
        return;
    }

    DataSet ds = GetDataSetForTable(da, tableName);
    DataTable table = GetDataTable(ds, tableName);

    // Clear contents at the specified location
    for (int i = 0; i < table.Rows.Count; i++)
    {
        table.Rows[i].Delete();
    }

    if (ShouldProcess(path, "ClearContent"))
    {
        da.Update(ds, tableName);
    }

} // ClearContent

ClearContent の実装に関する注意

System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*の実装には、次の条件が適用される場合があります。

動的パラメーターを Clear-Content コマンドレットにアタッチする

コマンドレット Clear-Content では、実行時に追加される追加の動的パラメーターが必要になる場合があります。 これらの動的パラメーターを指定するには、Windows PowerShell コンテンツ プロバイダーがSystem.Management.Automation.Provider.Icontentcmdletprovider.Clearcontentdynamicparameters*メソッドを実装して、これらのパラメーターを処理する必要があります。 このメソッドは、指定されたパスにある項目のパラメーターを取得します。 このメソッドは、指定されたパスにある項目の動的パラメーターを取得し、コマンドレット クラスまたは System.Management.Automation.Runtimedefinedparameterdictionary オブジェクトに似た属性を解析するプロパティとフィールドを持つオブジェクトを返します。 このWindows PowerShell返されたオブジェクトを使用して、コマンドレットにパラメーターを追加します。

このWindows PowerShellプロバイダーは、このメソッドを実装していない場合があります。 ただし、次のコードは、このメソッドの既定の実装です。

public object ClearContentDynamicParameters(string path)
{
    return null;
}
public object ClearContentDynamicParameters(string path)
{
    return null;
}

コード サンプル

完全なサンプルコードについては、「 AccessDbProviderSample06 のコードサンプル」を参照してください。

オブジェクトの種類と書式設定の定義

プロバイダーを作成する場合は、既存のオブジェクトにメンバーを追加したり、新しいオブジェクトを定義したりすることが必要になる場合があります。 これを行うには、オブジェクトのメンバーを識別するために使用できる型ファイルと、オブジェクトの表示方法を定義するフォーマットファイルを作成する必要があり Windows PowerShell ます。 詳細については、「 オブジェクトの種類と書式設定の拡張」を参照してください。

Windows PowerShell プロバイダーの構築

コマンドレット、プロバイダー、およびホストアプリケーションを登録する方法」を参照してください。

Windows PowerShell プロバイダーのテスト

Windows PowerShell プロバイダーが Windows PowerShell に登録されている場合は、コマンドラインでサポートされているコマンドレットを実行してテストできます。 たとえば、サンプルコンテンツプロバイダーをテストします。

コマンドレットを使用し Get-Content て、パラメーターで指定されたパスにあるデータベーステーブル内の指定された項目の内容を取得し Path ます。 パラメーターは、 ReadCount 定義されたコンテンツリーダーが読み取る項目の数を指定します (既定値は 1)。 次のコマンドを入力すると、コマンドレットはテーブルから2つの行 (項目) を取得し、その内容を表示します。 次の出力例では、架空の Access データベースが使用されていることに注意してください。

Get-Content -Path mydb:\Customers -ReadCount 2
ID        : 1
FirstName : Eric
LastName  : Gruber
Email     : ericgruber@fabrikam.com
Title     : President
Company   : Fabrikam
WorkPhone : (425) 555-0100
Address   : 4567 Main Street
City      : Buffalo
State     : NY
Zip       : 98052
Country   : USA
ID        : 2
FirstName : Eva
LastName  : Corets
Email     : evacorets@cohowinery.com
Title     : Sales Representative
Company   : Coho Winery
WorkPhone : (360) 555-0100
Address   : 8910 Main Street
City      : Cabmerlot
State     : WA
Zip       : 98089
Country   : USA

参照

Windows PowerShell プロバイダーの作成

Windows PowerShell プロバイダーを設計する

オブジェクトの種類と書式設定の拡張

ナビゲーション Windows PowerShell プロバイダーの実装

コマンドレット、プロバイダー、およびホストアプリケーションを登録する方法

Windows PowerShell SDK

Windows PowerShell プログラマー ガイド