当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 创建 Windows PowerShell 内容提供程序

作者:精品下载站 日期:2024-12-14 02:29:54 浏览:13 分类:玩电脑

创建 Windows PowerShell 内容提供程序


本主题介绍如何创建 Windows PowerShell 提供程序,使用户能够操作数据存储中的项目内容。因此,可以操作项目内容的提供程序称为 Windows PowerShell 内容提供程序。

笔记

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

定义 Windows PowerShell 内容提供程序类

Windows PowerShell 内容提供程序必须创建支持 System.Management.Automation.Provider.Icontentcmdletprovider 接口的 .NET 类。以下是本节中描述的项目提供程序的类定义。

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

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

定义基类的功能

如设计您的 Windows PowerShell 提供程序中所述,System.Management.Automation.Provider.Navigationcmdletprovider 类派生自提供不同提供程序功能的其他几个类。因此,Windows PowerShell 内容提供程序通常定义这些类提供的所有功能。

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

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

要操作数据存储的项目(例如获取、设置和清除项目),提供程序必须实现 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 基类,因此必须实现该类提供的方法。有关详细信息,请参阅实现这些方法,请参阅实现导航 Windows PowerShell 提供程序。

实施内容阅读器

要从项目中读取内容,提供程序必须实现派生自 System.Management.Automation.Provider.Icontentreader 的内容读取器类。该提供程序的内容读取器允许访问数据表中的行的内容。内容读取器类定义了一个 Read 方法,用于从指定行检索数据并返回表示该数据的列表,一个 Seek 方法用于移动内容读取器,一个 Seek 方法用于移动内容读取器, >Close 方法(关闭内容阅读器)和 Dispose 方法。

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 cmdlet。此方法返回位于指定路径的项目的内容读取器。然后可以打开阅读器对象来读取内容。

以下是此提供程序的此方法的 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* 的实现:

  • 定义提供程序类时,Windows PowerShell 内容提供程序可能会从 System.Management.Automation.Provider.Providercapability 枚举中声明 ExpandWildcards、Filter、Inclusion 或 Exclude 提供程序功能。在这些情况下,System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader* 方法的实现必须确保传递给该方法的路径满足指定功能的要求。为此,该方法应访问适当的属性,例如 System.Management.Automation.Provider.Cmdletprovider.Exclude* 和 System.Management.Automation.Provider.Cmdletprovider.Include* 属性。

  • 默认情况下,除非 System.Management.Automation.Provider.Cmdletprovider.Force* 属性设置为 true,否则此方法的重写不应检索对用户隐藏的对象的读取器。如果路径表示对用户隐藏的项目并且 System.Management.Automation.Provider.Cmdletprovider.Force* 设置为 false,则应写入错误。

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

Get-Content cmdlet 可能需要在运行时动态指定的其他参数。要提供这些动态参数,Windows PowerShell 内容提供程序必须实现 System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreaderdynamicparameters* 方法。此方法检索指定路径处项目的动态参数,并返回一个对象,该对象具有类似于 cmdlet 类或 System.Management.Automation.Runtimedefineparameterdictionary 对象的解析属性的属性和字段。 Windows PowerShell 运行时使用返回的对象将参数添加到 cmdlet。

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

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

检索内容编写器

要将内容写入项目,提供程序必须实现 System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter* 以支持 Set-ContentAdd-Content cmdlet。此方法返回位于指定路径的项目的内容编写器。

以下是此方法的 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* 的实现:

  • 定义提供程序类时,Windows PowerShell 内容提供程序可能会从 System.Management.Automation.Provider.Providercapability 枚举中声明 ExpandWildcards、Filter、Inclusion 或 Exclude 提供程序功能。在这些情况下,System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter* 方法的实现必须确保传递给该方法的路径满足指定功能的要求。为此,该方法应访问适当的属性,例如 System.Management.Automation.Provider.Cmdletprovider.Exclude* 和 System.Management.Automation.Provider.Cmdletprovider.Include* 属性。

  • 默认情况下,除非 System.Management.Automation.Provider.Cmdletprovider.Force* 属性设置为 true,否则此方法的重写不应检索对用户隐藏的对象的编写器。如果路径表示对用户隐藏的项目并且 System.Management.Automation.Provider.Cmdletprovider.Force* 设置为 false,则应写入错误。

将动态参数附加到 Add-Content 和 Set-Content Cmdlet

Add-ContentSet-Content cmdlet 可能需要在运行时添加的其他动态参数。要提供这些动态参数,Windows PowerShell 内容提供程序必须实现 System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriterdynamicparameters* 方法来处理这些参数。此方法检索指定路径处项目的动态参数,并返回一个对象,该对象具有类似于 cmdlet 类或 System.Management.Automation.Runtimedefineparameterdictionary 对象的解析属性的属性和字段。 Windows PowerShell 运行时使用返回的对象将参数添加到 cmdlet。

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

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

清除内容

您的内容提供程序实现 System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* 方法以支持 Clear-Content cmdlet。此方法删除指定路径中项目的内容,但保持项目完好无损。

以下是此提供程序的 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* 的实现:

  • 定义提供程序类时,Windows PowerShell 内容提供程序可能会从 System.Management.Automation.Provider.Providercapability 枚举中声明 ExpandWildcards、Filter、Inclusion 或 Exclude 提供程序功能。在这些情况下,System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* 方法的实现必须确保传递给该方法的路径满足指定功能的要求。为此,该方法应访问适当的属性,例如 System.Management.Automation.Provider.Cmdletprovider.Exclude* 和 System.Management.Automation.Provider.Cmdletprovider.Include* 属性。

  • 默认情况下,除非 System.Management.Automation.Provider.Cmdletprovider.Force* 属性设置为 true,否则此方法的重写不应清除对用户隐藏的对象的内容。如果路径表示对用户隐藏的项目并且 System.Management.Automation.Provider.Cmdletprovider.Force* 设置为 false,则应写入错误。

  • System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* 方法的实现应调用 System.Management.Automation.Provider.Cmdletprovider.ShouldProcess 并在对数据存储进行任何更改之前验证其返回值。此方法用于在数据存储发生更改(例如清除内容)时确认操作的执行。 System.Management.Automation.Provider.Cmdletprovider.ShouldProcess 方法将要更改的资源名称发送给用户,Windows PowerShell 运行时处理任何命令行设置或首选项变量以确定应显示的内容。

    在调用 System.Management.Automation.Provider.Cmdletprovider.ShouldProcess 返回 true 后,System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* 方法应调用 System.Management.Automation.Provider。 Cmdletprovider.ShouldContinue 方法。此方法向用户发送一条消息以允许反馈以验证是否应继续操作。对 System.Management.Automation.Provider.Cmdletprovider.ShouldContinue 的调用允许对潜在危险的系统修改进行额外检查。

将动态参数附加到 Clear-Content Cmdlet

Clear-Content cmdlet 可能需要在运行时添加的其他动态参数。要提供这些动态参数,Windows PowerShell 内容提供程序必须实现 System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontentdynamicparameters* 方法来处理这些参数。此方法检索指定路径处的项目的参数。此方法检索指定路径处项目的动态参数,并返回一个对象,该对象具有类似于 cmdlet 类或 System.Management.Automation.Runtimedefineparameterdictionary 对象的解析属性的属性和字段。 Windows PowerShell 运行时使用返回的对象将参数添加到 cmdlet。

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

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

代码示例

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

定义对象类型和格式

编写提供程序时,可能需要向现有对象添加成员或定义新对象。完成此操作后,您必须创建 Windows PowerShell 可用于标识对象成员的类型文件和定义对象显示方式的格式文件。有关详细信息,请参阅扩展对象类型和格式。

构建 Windows PowerShell 提供程序

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

测试 Windows PowerShell 提供程序

当您的 Windows PowerShell 提供程序已向 Windows PowerShell 注册后,您可以通过在命令行上运行支持的 cmdlet 来测试它。例如,测试示例内容提供程序。

使用 Get-Content cmdlet 可在 Path 参数指定的路径处检索数据库表中指定项目的内容。 ReadCount 参数指定定义的内容读取器要读取的项目数(默认为 1)。使用以下命令条目,cmdlet 从表中检索两行(项目)并显示其内容。请注意,以下示例输出使用虚构的 Access 数据库。

Get-Content -Path mydb:\Customers -ReadCount 2
ID        : 1
FirstName : Eric
LastName  : Gruber
Email     : [email protected]
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     : [email protected]
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 提供程序

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

Windows PowerShell SDK

Windows PowerShell 程序员指南

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯