创建 Windows PowerShell 容器提供程序

本主题介绍如何创建可用于多层数据存储的 Windows PowerShell 提供程序。 对于这种类型的数据存储,存储的顶层包含根项,每个后续级别称为子项的节点。 通过允许用户在这些子节点上工作,用户可以通过数据存储以分层方式交互。

可在多级数据存储上运行的提供程序称为 Windows PowerShell 容器提供程序。 但是,请注意,仅当有一个容器(无嵌套容器)包含其中的项时,才能使用 Windows PowerShell 容器提供程序。 如果存在嵌套容器,则必须实现 Windows PowerShell 导航提供程序。 有关实现 Windows PowerShell 导航提供程序的详细信息,请参阅 创建 Windows PowerShell 导航提供程序

注释

可以使用适用于 Windows Vista 和 .NET Framework 3.0 运行时组件的 Microsoft Windows 软件开发工具包下载此提供程序的 C# 源文件(AccessDBSampleProvider04.cs)。 有关下载说明,请参阅 如何安装 Windows PowerShell 并下载 Windows PowerShell SDK <PowerShell 示例> 目录中提供了下载的源文件。 有关其他 Windows PowerShell 提供程序实现的详细信息,请参阅 设计 Windows PowerShell 提供程序

此处所述的 Windows PowerShell 容器提供程序将数据库定义为其单个容器,数据库表和行定义为容器的项。

谨慎

请注意,此设计假定数据库具有具有名称 ID 的字段,并且该字段的类型为 LongInteger。

定义 Windows PowerShell 容器提供程序类

Windows PowerShell 容器提供程序必须定义派生自 System.Management.Automation.Provider.ContainerCmdletProvider 基类的 .NET 类。 下面是本节中所述的 Windows PowerShell 容器提供程序的类定义。

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

请注意,在此类定义中,System.Management.Automation.Provider.CmdletProviderAttribute 属性包含两个参数。 第一个参数指定 Windows PowerShell 使用的提供程序的用户友好名称。 第二个参数指定提供程序在命令处理期间向 Windows PowerShell 运行时公开的 Windows PowerShell 特定功能。 对于此提供程序,没有添加 Windows PowerShell 特定功能。

定义基本功能

设计 Windows PowerShell 提供程序中所述,System.Management.Automation.Provider.ContainerCmdletProvider 类派生自提供不同提供程序功能的几个其他类。 因此,Windows PowerShell 容器提供程序需要定义这些类提供的所有功能。

若要实现用于添加特定于会话的初始化信息和释放提供程序使用的资源的功能,请参阅 创建基本 Windows PowerShell 提供程序。 但是,大多数提供程序(包括此处所述的提供程序)都可以使用 Windows PowerShell 提供的此功能的默认实现。

若要访问数据存储,提供程序必须实现 System.Management.Automation.Provider.DriveCmdletProvider 基类的方法。 有关实现这些方法的详细信息,请参阅 创建 Windows PowerShell 驱动器提供程序

若要作数据存储的项(如获取、设置和清除项),提供程序必须实现由 System.Management.Automation.Provider.ItemCmdletProvider 基类提供的方法。 有关实现这些方法的详细信息,请参阅 创建 Windows PowerShell 项提供程序

检索子项

若要检索子项,Windows PowerShell 容器提供程序必须重写 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildItems* 方法以支持来自 Get-ChildItem cmdlet 的调用。 此方法从数据存储中检索子项,并将其作为对象写入管道。 如果指定了 cmdlet 的 recurse 参数,该方法将检索所有子级,而不管其级别如何。 如果未指定 recurse 参数,该方法只检索单个级别的子级。

下面是此提供程序的 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildItems* 方法的实现。 请注意,此方法在路径指示 Access 数据库时检索所有数据库表中的子项,如果路径指示数据表,则从该表的行中检索子项。

protected override void GetChildItems(string path, bool recurse)
{
    // If path represented is a drive then the children in the path are 
    // tables. Hence all tables in the drive represented will have to be
    // returned
    if (PathIsDrive(path))
    {
        foreach (DatabaseTableInfo table in GetTables())
        {
            WriteItemObject(table, path, true);

            // if the specified item exists and recurse has been set then 
            // all child items within it have to be obtained as well
            if (ItemExists(path) && recurse)
            {
                GetChildItems(path + pathSeparator + table.Name, recurse);
            }
        } // foreach (DatabaseTableInfo...
    } // if (PathIsDrive...
    else
    {
        // Get the table name, row number and type of path from the
        // path specified
        string tableName;
        int rowNumber;

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

        if (type == PathType.Table)
        {
            // Obtain all the rows within the table
            foreach (DatabaseRowInfo row in GetRows(tableName))
            {
                WriteItemObject(row, path + pathSeparator + row.RowNumber,
                        false);
            } // foreach (DatabaseRowInfo...
        }
        else if (type == PathType.Row)
        {
            // In this case the user has directly specified a row, hence
            // just give that particular row
            DatabaseRowInfo row = GetRow(tableName, rowNumber);
            WriteItemObject(row, path + pathSeparator + row.RowNumber,
                        false);
        }
        else
        {
            // In this case, the path specified is not valid
            ThrowTerminatingInvalidPathException(path);
        }
    } // else
} // GetChildItems

有关实现 GetChildItems 的注意事项

以下条件适用于 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildItems*的实现:

将动态参数附加到 Get-ChildItem Cmdlet

有时调用 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildItems*Get-ChildItem cmdlet 需要运行时动态指定的其他参数。 若要提供这些动态参数,Windows PowerShell 容器提供程序必须实现 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildItemsDynamicParameters* 方法。 此方法检索指示路径处的项的动态参数,并返回具有属性和字段的对象,其属性和字段与 cmdlet 类或 System.Management.Automation.RuntimeDefinedParameterDictionary 对象类似。 Windows PowerShell 运行时使用返回的对象将参数添加到 Get-ChildItem cmdlet。

此 Windows PowerShell 容器提供程序不实现此方法。 但是,以下代码是此方法的默认实现。

检索子项名称

若要检索子项的名称,Windows PowerShell 容器提供程序必须重写 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildNames* 方法,以支持在指定 Name 参数时从 Get-ChildItem cmdlet 调用。 如果指定了 cmdlet 的 returnAllContainers 参数,此方法将检索所有容器的指定路径或子项名称的子项的名称。 子名称是路径的叶部分。 例如,路径 C:\windows\system32\abc.dll 的子名称为“abc.dll”。 目录 C:\windows\system32 的子名称为“system32”。

下面是此提供程序的 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildNames* 方法的实现。 请注意,如果指定的路径指示 Access 数据库(驱动器)和行号(如果路径指示表),该方法将检索表名。

protected override void GetChildNames(string path,
                              ReturnContainers returnContainers)
{
    // If the path represented is a drive, then the child items are
    // tables. get the names of all the tables in the drive.
    if (PathIsDrive(path))
    {
        foreach (DatabaseTableInfo table in GetTables())
        {
            WriteItemObject(table.Name, path, true);
        } // foreach (DatabaseTableInfo...
    } // if (PathIsDrive...
    else
    {
        // Get type, table name and row number from path specified
        string tableName;
        int rowNumber;

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

        if (type == PathType.Table)
        {
            // Get all the rows in the table and then write out the 
            // row numbers.
            foreach (DatabaseRowInfo row in GetRows(tableName))
            {
                WriteItemObject(row.RowNumber, path, false);
            } // foreach (DatabaseRowInfo...
        }
        else if (type == PathType.Row)
        {
            // In this case the user has directly specified a row, hence
            // just give that particular row
            DatabaseRowInfo row = GetRow(tableName, rowNumber);

            WriteItemObject(row.RowNumber, path, false);
        }
        else
        {
            ThrowTerminatingInvalidPathException(path);
        }
    } // else
} // GetChildNames

有关实现 GetChildNames 的注意事项

以下条件适用于 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildItems*的实现:

将动态参数附加到 Get-ChildItem Cmdlet (名称)

有时,Get-ChildItem cmdlet(使用 Name 参数)需要在运行时动态指定的其他参数。 若要提供这些动态参数,Windows PowerShell 容器提供程序必须实现 System.Management.Automation.Provider.ContainerCmdletProvider.GetChildNamesDynamicParameters* 方法。 此方法检索指示路径处的项的动态参数,并返回一个对象,该对象具有与 cmdlet 类或 System.Management.Automation.RuntimeDefinedParameterDictionary 对象类似的属性和字段。 Windows PowerShell 运行时使用返回的对象将参数添加到 Get-ChildItem cmdlet。

此提供程序不实现此方法。 但是,以下代码是此方法的默认实现。

重命名项

若要重命名项,Windows PowerShell 容器提供程序必须重写 System.Management.Automation.Provider.ContainerCmdletProvider.RenameItem* 方法,以支持来自 Rename-Item cmdlet 的调用。 此方法将指定路径处的项的名称更改为提供的新名称。 新名称必须始终相对于父项(容器)。

此提供程序不会替代 System.Management.Automation.Provider.ContainerCmdletProvider.RenameItem* 方法。 但是,下面是默认实现。

有关实现 RenameItem 的注意事项

以下条件适用于 System.Management.Automation.Provider.ContainerCmdletProvider.RenameItem*的实现:

将动态参数附加到 Rename-Item Cmdlet

有时,Rename-Item cmdlet 需要在运行时动态指定的其他参数。 若要提供这些动态参数,Windows PowerShell 容器提供程序必须实现 System.Management.Automation.Provider.ContainerCmdletProvider.RenameItemDynamicParameters* 方法。 此方法检索指示路径处的项的参数,并返回具有属性和字段的对象,其属性和字段与 cmdlet 类或 System.Management.Automation.RuntimeDefinedParameterDictionary 对象类似。 Windows PowerShell 运行时使用返回的对象将参数添加到 Rename-Item cmdlet。

此容器提供程序不实现此方法。 但是,以下代码是此方法的默认实现。

创建新项

若要创建新项,容器提供程序必须实现 System.Management.Automation.Provider.ContainerCmdletProvider.NewItem* 方法,以支持来自 New-Item cmdlet 的调用。 此方法创建位于指定路径的数据项。 cmdlet 的 type 参数包含新项的提供程序定义类型。 例如,FileSystem 提供程序使用值为“file”或“directory”的 type 参数。 cmdlet 的 newItemValue 参数为新项指定提供程序特定的值。

下面是此提供程序的 System.Management.Automation.Provider.ContainerCmdletProvider.NewItem* 方法的实现。

protected override void NewItem( string path, string type, object newItemValue )
{
    // Create the new item here after
    // performing necessary validations
    //
    // WriteItemObject(newItemValue, path, false);

    // Example
    //
    // if (ShouldProcess(path, "new item"))
    // {
    //      // Create a new item and then call WriteObject
    //      WriteObject(newItemValue, path, false);
    // }

} // NewItem
{
    case 1:
        {
            string name = pathChunks[0];

            if (TableNameIsValid(name))
            {
                tableName = name;
                retVal = PathType.Table;
            }
        }
        break;

    case 2:
        {
            string name = pathChunks[0];

关于实现 NewItem 的注意事项

以下条件适用于 System.Management.Automation.Provider.ContainerCmdletProvider.NewItem*的实现:

将动态参数附加到 New-Item Cmdlet

有时,New-Item cmdlet 需要在运行时动态指定的其他参数。 若要提供这些动态参数,容器提供程序必须实现 System.Management.Automation.Provider.ContainerCmdletProvider.NewItemDynamicParameters* 方法。 此方法检索指示路径处的项的参数,并返回具有属性和字段的对象,其属性和字段与 cmdlet 类或 System.Management.Automation.RuntimeDefinedParameterDictionary 对象类似。 Windows PowerShell 运行时使用返回的对象将参数添加到 New-Item cmdlet。

此提供程序不实现此方法。 但是,以下代码是此方法的默认实现。

删除项目

若要删除项,Windows PowerShell 提供程序必须重写 System.Management.Automation.Provider.ContainerCmdletProvider.RemoveItem* 方法,以支持从 Remove-Item cmdlet 调用。 此方法从指定路径处的数据存储中删除项。 如果 Remove-Item cmdlet 的 recurse 参数设置为 true,则无论其级别如何,该方法都会删除所有子项。 如果参数设置为 false,该方法仅删除指定路径上的单个项。

此提供程序不支持删除项。 但是,以下代码是 System.Management.Automation.Provider.ContainerCmdletProvider.RemoveItem*的默认实现。

有关实现 RemoveItem 的注意事项

以下条件适用于 System.Management.Automation.Provider.ContainerCmdletProvider.NewItem*的实现:

将动态参数附加到 Remove-Item Cmdlet

有时,Remove-Item cmdlet 需要在运行时动态指定的其他参数。 若要提供这些动态参数,容器提供程序必须实现 System.Management.Automation.Provider.ContainerCmdletProvider.RemoveItemDynamicParameters* 方法来处理这些参数。 此方法检索指示路径处的项的动态参数,并返回一个对象,该对象具有与 cmdlet 类或 System.Management.Automation.RuntimeDefinedParameterDictionary 对象类似的属性和字段。 Windows PowerShell 运行时使用返回的对象将参数添加到 Remove-Item cmdlet。

此容器提供程序不实现此方法。 但是,以下代码是 System.Management.Automation.Provider.ContainerCmdletProvider.RemoveItemDynamicParameters*的默认实现。

查询子项

若要查看指定路径中是否存在子项,Windows PowerShell 容器提供程序必须重写 System.Management.Automation.Provider.ContainerCmdletProvider.HasChildItems* 方法。 如果项具有子项,则此方法返回 true;否则返回 false。 对于 null 或空路径,该方法将数据存储中的任何项视为子级,并返回 true

下面是 System.Management.Automation.Provider.ContainerCmdletProvider.HasChildItems* 方法的替代。 如果 ChunkPath 帮助程序方法创建了两个以上的路径部分,该方法将返回 false,因为只定义了数据库容器和表容器。 有关此帮助程序方法的详细信息,请参阅 创建 Windows PowerShell 项提供程序中讨论 ChunkPath 方法。

protected override bool HasChildItems( string path )
{
    return false;
} // HasChildItems
        ErrorCategory.InvalidOperation, tableName));
}

return results;

有关实现 HasChildItems 的注意事项

以下条件适用于 System.Management.Automation.Provider.ContainerCmdletProvider.HasChildItems*的实现:

复制项

若要复制项,容器提供程序必须实现 System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem 方法,以支持来自 Copy-Item cmdlet 的调用。 此方法将数据项从 cmdlet 的 path 参数指示的位置复制到由 copyPath 参数指示的位置。 如果指定了 recurse 参数,该方法将复制所有子容器。 如果未指定参数,该方法仅复制单个级别的项。

此提供程序不实现此方法。 但是,以下代码是 System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem的默认实现。

有关实现 CopyItem 的注意事项

以下条件适用于 System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem的实现:

将动态参数附加到 Copy-Item Cmdlet

有时,Copy-Item cmdlet 需要在运行时动态指定的其他参数。 若要提供这些动态参数,Windows PowerShell 容器提供程序必须实现 System.Management.Automation.Provider.ContainerCmdletProvider.CopyItemDynamicParameters* 方法来处理这些参数。 此方法检索指示路径处的项的参数,并返回具有属性和字段的对象,其属性和字段与 cmdlet 类或 System.Management.Automation.RuntimeDefinedParameterDictionary 对象类似。 Windows PowerShell 运行时使用返回的对象将参数添加到 Copy-Item cmdlet。

此提供程序不实现此方法。 但是,以下代码是 System.Management.Automation.Provider.ContainerCmdletProvider.CopyItemDynamicParameters*的默认实现。

代码示例

有关完整的示例代码,请参阅 AccessDbProviderSample04 代码示例

生成 Windows PowerShell 提供程序

请参阅 如何注册 Cmdlet、提供程序和主机应用程序

测试 Windows PowerShell 提供程序

将 Windows PowerShell 提供程序注册到 Windows PowerShell 后,可以通过在命令行上运行支持的 cmdlet 来测试它。 请注意,以下示例输出使用虚构的 Access 数据库。

  1. 运行 Get-ChildItem cmdlet,从 Access 数据库中的 Customers 表中检索子项的列表。

    Get-ChildItem mydb:customers
    

    将显示以下输出。

    PSPath        : AccessDB::customers
    PSDrive       : mydb
    PSProvider    : System.Management.Automation.ProviderInfo
    PSIsContainer : True
    Data          : System.Data.DataRow
    Name          : Customers
    RowCount      : 91
    Columns       :
    
  2. 再次运行 Get-ChildItem cmdlet 以检索表的数据。

    (Get-ChildItem mydb:customers).Data
    

    将显示以下输出。

    TABLE_CAT   : C:\PS\northwind
    TABLE_SCHEM :
    TABLE_NAME  : Customers
    TABLE_TYPE  : TABLE
    REMARKS     :
    
  3. 现在,使用 Get-Item cmdlet 检索数据表中第 0 行的项。

    Get-Item mydb:\customers\0
    

    将显示以下输出。

    PSPath        : AccessDB::customers\0
    PSDrive       : mydb
    PSProvider    : System.Management.Automation.ProviderInfo
    PSIsContainer : False
    Data          : System.Data.DataRow
    RowNumber     : 0
    
  4. 重复使用 Get-Item 检索第 0 行中项的数据。

    (Get-Item mydb:\customers\0).Data
    

    将显示以下输出。

    CustomerID   : 1234
    CompanyName  : Fabrikam
    ContactName  : Eric Gruber
    ContactTitle : President
    Address      : 4567 Main Street
    City         : Buffalo
    Region       : NY
    PostalCode   : 98052
    Country      : USA
    Phone        : (425) 555-0100
    Fax          : (425) 555-0101
    
  5. 现在,使用 New-Item cmdlet 向现有表添加行。 Path 参数指定行的完整路径,并且必须指示大于表中现有行数的行数的行号。 Type 参数指示 Row 指定要添加的项类型。 最后,Value 参数指定行的列值的逗号分隔列表。

    New-Item -Path mydb:\Customers\3 -ItemType "Row" -Value "3,CustomerFirstName,CustomerLastName,CustomerEmailAddress,CustomerTitle,CustomerCompany,CustomerPhone, CustomerAddress,CustomerCity,CustomerState,CustomerZip,CustomerCountry"
    
  6. 验证新项作的正确性,如下所示。

    PS mydb:\> cd Customers
    PS mydb:\Customers> (Get-Item 3).Data
    

    将显示以下输出。

    ID        : 3
    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
    

另请参阅

创建 Windows PowerShell 提供程序

设计 Windows PowerShell 提供程序

实现项 Windows PowerShell 提供程序

实现导航 Windows PowerShell 提供程序

如何注册 Cmdlet、提供程序和主机应用程序

Windows PowerShell SDK

Windows PowerShell 程序员指南