本主题描述如何创建一个 Windows PowerShell 导航工具,用于导航数据存储。 这种类型的提供者支持递归命令、嵌套容器和相对路径。
注释
您可以使用 Windows Vista 和 .NET Framework 3.0 运行时组件的 Microsoft Windows 软件开发工具包下载该提供者的 C# 源文件(AccessDBSampleProvider05.cs)。 有关下载说明,请参见 《如何安装Windows PowerShell》和《Windows PowerShell SDK》。 下载的源文件可在 <PowerShell Samples> 目录中获取。 有关其他 Windows PowerShell 提供者实现的更多信息,请参见 “设计你的 Windows PowerShell 提供者”。
这里描述的提供者允许用户将 Access 数据库作为驱动器管理,从而能够导航到数据库中的数据表。 在创建自己的导航提供者时,你可以实现一些方法,比如要求导航必须有驱动器合格的路径,规范化相对路径,移动数据存储中的项目,以及获取子名称、获取项目的父路径,并测试项目是否是容器的方法。
注意
请注意,这种设计假设数据库有一个带有名称 ID 的字段,且字段类型为 LongInteger。
定义 Windows PowerShell 提供者
Windows PowerShell 导航提供者必须创建一个从 System.Management.Automation.Provider.NavigationCmdletProvider 基类衍生的 .NET 类。 以下是本节中描述的导航提供者的类定义。
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider
注意,在此提供者中, System.Management.Automation.Provider.CmdletProviderAttribute 属性包含两个参数。 第一个参数指定了 Windows PowerShell 所用提供者的用户友好名称。 第二个参数指定了 Windows PowerShell 在命令处理过程中向 Windows PowerShell 运行时暴露的具体功能。 对于该提供者,没有添加任何 Windows PowerShell 特定的功能。
定义基础功能
如《 设计你的 PS 提供者》中所述, System.Management.Automation.Provider.NavigationCmdletProvider 基类源自其他提供不同提供者功能的类。 因此,Windows PowerShell 导航提供者必须定义这些类提供的所有功能。
要实现添加会话特定初始化信息和释放提供者使用的资源的功能,请参见 创建基础 PS 提供者。 然而,大多数提供者(包括此处描述的提供者)可以使用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 容器提供者”。
创建 Windows PowerShell 路径
Windows PowerShell 导航提供者使用提供者内部 Windows PowerShell 路径来导航数据存储中的项。 要创建提供者-内部路径,提供者必须实现 System.Management.Automation.Provider.NavigationCmdletProvider.MakePath* 方法,以支持 Combine-Path cmdlet 调用。 该方法将父路径和子路径合并为提供者-内部路径,使用提供者专用的路径分隔符区分父子路径。
默认实现采用带有“/”或“\”的路径分隔符,将路径分隔符归一化为“\”,将父路径和子路径部分与分隔符合并,然后返回包含合并路径的字符串。
该导航提供者不实现该方法。 然而,以下代码是 System.Management.Automation.Provider.NavigationCmdletProvider.MakePath* 方法的默认实现。
实现MakePath需要注意的事项
以下条件可能适用于您对 System.Management.Automation.Provider.NavigationCmdletProvider.MakePath*的实现:
你实现的 System.Management.Automation.Provider.NavigationCmdletProvider.MakePath* 方法不应在提供者命名空间中验证该路径是否合法且完全限定。 请注意,每个参数只能代表路径的一部分,合并后的部分可能不生成完全限定的路径。 例如, System.Management.Automation.Provider.NavigationCmdletProvider.MakePath* 方法中,文件系统提供者可能在参数中接收到“windows\system32”
parent,参数中child为“abc.dll”。 该方法用“\”分隔符连接这些值,返回“windows\system32\abc.dll”,这并不是一个完全限定的文件系统路径。重要
调用 System.Management.Automation.Provider.NavigationCmdletProvider.MakePath* 时提供的路径部分可能包含提供者命名空间中不允许的字符。 这些字符很可能用于万能牌扩展,采用这种方法不应移除它们。
检索父路径
Windows PowerShell 导航提供者实现了 System.Management.Automation.Provider.NavigationCmdletProvider.GetParentPath* 方法,以获取指定完整或部分提供者特定路径的父部分。 该方法移除路径的子部分,返回父路径部分。 该 root 参数指定了驱动根节点的完全限定路径。 如果未使用已挂载驱动器进行检索作,该参数可以为空或空。 如果指定了根节点,方法必须返回与根节点同一树中的容器路径。
示例导航提供者不会覆盖该方法,而是使用默认实现。 它接受同时使用“/”和“\”作为路径分隔符的路径。 它首先将路径规范化为仅有“\”分隔符,然后在最后一个“\”处将父路径分开,返回父路径。
记住实现GetParentPath的相关内容
你实现的 System.Management.Automation.Provider.NavigationCmdletProvider.GetParentPath* 方法应在提供者命名空间的路径分隔符上按词法方式分割路径。 例如,FileSystem提供者使用这种方法查找最后一个“\”,并返回分隔符左侧的所有信息。
检索子路径名称
您的导航提供者实现了 System.Management.Automation.Provider.NavigationCmdletProvider.GetChildName* 方法,以获取位于指定完整或部分提供者特定路径的项目子节点的名称(叶节点)。
样本导航提供者不会覆盖该方法。 默认实现如下所示。 它接受同时使用“/”和“\”作为路径分隔符的路径。 它首先将路径规范化为仅有“\”分隔符,然后在最后一个“\”处将父路径分离出来,返回子路径部分的名称。
实现GetChildName时需要记住的事项
你实现的 System.Management.Automation.Provider.NavigationCmdletProvider.GetChildName* 方法应该在路径分隔符上按词汇方式分割路径。 如果提供的路径不包含路径分隔符,方法应返回未修改的路径。
重要
调用该方法时提供的路径可能包含在提供者命名空间中非法的字符。 这些字符很可能用于万用符展开或正则表达式匹配,实现该方法不应去除它们。
判断物品是否为容器
导航提供者可以实现 System.Management.Automation.Provider.NavigationCmdletProvider.IsItemContainer* 方法,以判断指定路径是否指向容器。 如果路径代表容器,则返回为真;否则返回为假。 用户需要这种方法才能使用 Test-Path 该命令小说来获得所提供的路径。
以下代码展示了我们示例导航提供者中的 System.Management.Automation.Provider.NavigationCmdletProvider.IsItemContainer* 的实现。 该方法验证指定路径是否正确,以及表是否存在,若路径指示容器,则返回为真。
protected override bool IsItemContainer(string path)
{
if (PathIsDrive(path))
{
return true;
}
string[] pathChunks = ChunkPath(path);
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out rowNumber);
if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName, StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
} // IsItemContainer
实现IsItemContainer时需要注意的事项
你的导航提供商 .NET 类可能会声明从 System.Management.Automation.Provider.ProviderCapabilities 枚举中声明 ExpandWildcard、Filter、Include 或 Exclude 的提供者能力。 在这种情况下, System.Management.Automation.Provider.NavigationCmdletProvider.IsItemContainer* 的实现需要确保通过的路径符合要求。 为此,方法应访问相应属性,例如 System.Management.Automation.Provider.CmdletProvider.Exclude* 属性。
移动物品
为支持该 Move-Item 命令,导航提供者实现了 System.Management.Automation.Provider.NavigationCmdletProvider.MoveItem* 方法。 该方法将参数指定的 path 物品移动到参数中路径 destination 的容器。
示例导航提供者不会覆盖 System.Management.Automation.Provider.NavigationCmdletProvider.MoveItem* 方法。 以下是默认实现。
实现MoveItem需要记住的事项
你的导航提供商 .NET 类可能会声明从 System.Management.Automation.Provider.ProviderCapabilities 枚举中声明 ExpandWildcard、Filter、Include 或 Exclude 的提供者能力。 在这种情况下, System.Management.Automation.Provider.NavigationCmdletProvider.MoveItem* 的实现必须确保通过的路径满足要求。 为此,方法应访问相应属性,例如 CmdletProvider.Exclude 属性。
默认情况下,除非将 System.Management.Automation.Provider.CmdletProvider.Force* 属性设置为 true。 例如,FileSystem提供者不会在已有 C:\bar.txt 文件上复制 C:\temp\abc.txt,除非 System.Management.Automation.Provider.CmdletProvider.Force* 属性设置为 true。 如果参数中指定的 destination 路径存在且是容器,则不需要 System.Management.Automation.Provider.CmdletProvider.Force* 属性。 在这种情况下, System.Management.Automation.Provider.NavigationCmdletProvider.MoveItem* 应将参数 path 指示的项作为子节点移动到参数指示 destination 的容器。
你实现 System.Management.Automation.Provider.NavigationCmdletProvider.MoveItem* 方法时,应调用 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.NavigationCmdletProvider.MoveItem* 方法应调用 System.Management.Automation.Provider.CmdletProvider.ShouldContinue 方法。 该方法向用户发送消息,允许反馈以判断是否应继续作。 您的服务提供者应致电 System.Management.Automation.Provider.CmdletProvider.WithContinue ,作为潜在危险系统修改的额外检查。
将动态参数附加到 Move-Item cmdlet
有时 Move-Item cmdlet 需要在运行时动态提供额外参数。 为了提供这些动态参数,导航提供者必须实现 System.Management.Automation.Provider.NavigationCmdletProvider.MoveItemDynamicParameters* 方法,从指定路径的项目获取所需参数值,并返回具有类似cmdlet类或 System.Management.Automation.RuntimeDefinedParameterDictionary 对象的属性和字段的对象。
该导航提供者不实现该方法。 然而,以下代码是 System.Management.Automation.Provider.NavigationCmdletProvider.MoveItemDynamicParameters*的默认实现。
相对路径归一化
你的导航提供者实现了 System.Management.Automation.Provider.NavigationCmdletProvider.NormalizeRelativePath* 方法,将参数中标注 path 的完全限定路径与参数指定的 basePath 路径进行规范化。 该方法返回归一化路径的字符串表示。 如果 path 参数指定了不存在的路径,则写入错误。
样本导航提供者不会覆盖该方法。 以下是默认实现。
关于实现 NormalizeRelativePath 需要记住的事项
你实现的 System.Management.Automation.Provider.NavigationCmdletProvider.NormalizeRelativePath* 应该会解析该 path 参数,但不必完全使用语法解析。 建议你设计这种方法,利用路径查找数据存储中的路径信息,并创建与套管和标准化路径语法相匹配的路径。
代码示例
完整示例代码请参见 AccessDbProviderSample05 代码示例。
定义对象类型与格式化
提供者可以向现有对象添加成员或定义新对象。 更多信息请参见“扩展对象类型与格式”。
构建 Windows PowerShell 提供者
欲了解更多信息,请参见 如何注册指令链、提供者和主机应用。
测试Windows PowerShell提供者
当你的 Windows PowerShell 提供者已注册 Windows PowerShell 后,可以通过命令行运行支持的 cmdlet(包括通过派生提供)来测试。 本示例将测试示例导航提供者。
运行你的新shell,用
Set-Locationcmdlet设置路径以指示Access数据库。Set-Location mydb:现在运行
Get-ChildItemcmdlet 以获取数据库项目列表,也就是可用的数据库表。 对于每个表,该 cmdlet 还检索表行数。Get-ChildItem | Format-Table RowCount, Name -AutoSizeRowCount Name -------- ---- 180 MSysAccessObjects 0 MSysACEs 1 MSysCmdbars 0 MSysIMEXColumns 0 MSysIMEXSpecs 0 MSysObjects 0 MSysQueries 7 MSysRelationships 8 Categories 91 Customers 9 Employees 2155 Order Details 830 Orders 77 Products 3 Shippers 29 Suppliers再次使用
Set-Location命令子设置员工数据表的位置。Set-Location Employees现在我们用
Get-Locationcmdlet获取Employees表的路径。Get-LocationPath ---- mydb:\Employees现在用
Get-ChildItem管道传输到Format-Table指令的指令令。 这组 cmdlet 用于获取 Employees 数据表的项,即表行。 它们的格式按照指令符(cmdlet)Format-Table指定。Get-ChildItem | Format-Table RowNumber, PSIsContainer, Data -AutoSizeRowNumber PSIsContainer Data --------- -------------- ---- 0 False System.Data.DataRow 1 False System.Data.DataRow 2 False System.Data.DataRow 3 False System.Data.DataRow 4 False System.Data.DataRow 5 False System.Data.DataRow 6 False System.Data.DataRow 7 False System.Data.DataRow 8 False System.Data.DataRow你现在可以运行
Get-Itemcmdlet 来获取 Employees 数据表第 0 行的项目。Get-Item 0PSPath : AccessDB::C:\PS\Northwind.mdb\Employees\0 PSParentPath : AccessDB::C:\PS\Northwind.mdb\Employees PSChildName : 0 PSDrive : mydb PSProvider : System.Management.Automation.ProviderInfo PSIsContainer : False Data : System.Data.DataRow RowNumber : 0再次使用
Get-Item命令小工具检索第0行项目的员工数据。(Get-Item 0).DataEmployeeID : 1 LastName : Davis FirstName : Sara Title : Sales Representative TitleOfCourtesy : Ms. BirthDate : 12/8/1968 12:00:00 AM HireDate : 5/1/1992 12:00:00 AM Address : 4567 Main Street Apt. 2A City : Buffalo Region : NY PostalCode : 98052 Country : USA HomePhone : (206) 555-9857 Extension : 5467 Photo : EmpID1.bmp Notes : Education includes a BA in psychology from Colorado State University. She also completed "The Art of the Cold Call." Nancy is a member of Toastmasters International. ReportsTo : 2