资讯动态

编写 Windows PowerShell 提供程序:基于 AccessDBProviderSample03 实现数据库驱动器与项目操作

发布时间:2026/10/15 3:08:45 来源:尧图企业网站定制
示例工程【免费下载链接】Windows-classic-samplesThis repo contains samples that demonstrate the API used in Windows classic desktop applications.项目地址https://gitcode.com/gh_mirrors/wi/Windows-classic-samples点击查看免费下载本指南以 Windows-classic-samples 仓库中的 AccessDBProviderSample03 为骨架系统讲解如何用 C# 实现一个把 Access 数据库.mdb暴露为 PowerShell 驱动器Drive的提供程序Provider。读完本文你将掌握ItemCmdletProvider基类的核心方法NewDrive、GetItem、SetItem、ItemExists、IsValidPath的编写方式理解如何通过 ODBC 把数据库表与行映射为类似文件系统的路径结构并能在本机用Import-Module加载 DLL 后用Get-PSProvider、Get-PSDrive、Get-Item、Set-Item等内建 cmdlet 直接操作数据库内容。一、样本定位提供程序系列中的“Item 操作”范例PowerShell 提供程序的核心理念是让用户以“文件系统驱动器”这一统一、一致的格式来访问异构数据源。文件系统之外的数据数据库表、注册表项、环境变量等只要实现了 Provider用户就可以用同一套Get-Item、Set-Item、New-Item等 cmdlet 来读写。在仓库中PowerShell Provider 样本是一个连续编号的系列共包含六个目录AccessDBProvider01AccessDBProvider02AccessDBProvider03AccessDBProvider04AccessDBProvider05AccessDBProvider06本样本是系列中的第三份Sample 03。正如其 README 所述它演示了三项核心目标创建基本的 Windows PowerShell 提供程序创建 PowerShell 驱动器PowerShell drives通过提供程序操作项目items即数据库中的表与行。后续样本0406则在此基础上继续演示额外的 Provider 功能因此本样本最适合作为理解“ItemCmdletProvider 驱动器状态管理”这一组合的入门范本。二、样本目标与实现概览从源码结构看本样本把“数据库”抽象成了三级路径空间驱动器根数据库→ 表名Table→ 行号Row驱动器根即整个 .mdb 数据库文件一级路径段是表名二级路径段是行号从 0 开始的整数索引。这一设计直接体现在源码中的PathType枚举与路径解析方法上见下文第四部分。样本由一个主源文件实现全部逻辑AccessDBProviderSample03.cs其代码组织为三个区域AccessDBProvider类继承自System.Management.Automation.Provider.ItemCmdletProvider含驱动器操作Drive Manipulation、Item 方法Item Methods与辅助方法Helper Methods三个辅助类AccessDBPSDriveInfo保存驱动器状态、DatabaseTableInfo表信息类比DirectoryInfo、DatabaseRowInfo行信息类比FileInfo。从这一对应关系可以推断出作者的抽象思路表 ≈ 目录行 ≈ 文件而DatabaseTableInfo、DatabaseRowInfo的注释也正是这样说明的——前者“Similar to the DirectoryInfo class”后者“Analogous to the FileInfo class”。三、驱动器管理NewDrive 与 RemoveDrivePowerShell 驱动器由用户通过New-PSDrive -PSProvider AccessDB -Root 数据库文件路径创建。当 PowerShell 引擎要求提供程序“接管”一个新驱动器时会调用NewDrive方法。3.1 NewDrive建立 ODBC 连接并保存状态在 NewDrive 实现 中核心逻辑分四步protected override PSDriveInfo NewDrive(PSDriveInfo drive) { // 1. drive 对象不能为 null否则写入 NullDrive 错误 if (drive null) { ... return null; } // 2. drive.Root 不能为空且必须指向一个真实存在的文件 if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root) false)) { ... return null; } // 3. 构造 ODBC 连接字符串并打开连接 AccessDBPSDriveInfo accessDBPSDriveInfo new AccessDBPSDriveInfo(drive); OdbcConnectionStringBuilder builder new OdbcConnectionStringBuilder(); builder.Driver Microsoft Access Driver (*.mdb); builder.Add(DBQ, drive.Root); OdbcConnection conn new OdbcConnection(builder.ConnectionString); conn.Open(); // 4. 把连接保存在驱动器对象里返回 accessDBPSDriveInfo.Connection conn; return accessDBPSDriveInfo; }要点Root 校验drive.Root直接来自New-PSDrive -Root参数必须非空且File.Exists为真否则通过WriteError写入NoRoot/NullDrive错误记录并返回null表示创建失败连接字符串使用OdbcConnectionStringBuilder生成指定驱动为Microsoft Access Driver (*.mdb)、数据库文件为DBQRoot状态保存连接对象被存入自定义的AccessDBPSDriveInfo继承自PSDriveInfo并返回给 PowerShell 引擎。此后该驱动器存续期间所有 Item 操作都能通过this.PSDriveInfo拿到这条连接——这正是“把与驱动器关联的状态放在这里”的典型做法。3.2 RemoveDrive关闭连接当驱动器被移除如Remove-PSDrive时引擎调用RemoveDrive。实现将传入的PSDriveInfo转回AccessDBPSDriveInfo若成功则调用Connection.Close()释放 ODBC 连接防止资源泄漏。从源码结构看AccessDBPSDriveInfo.Connection是普通属性get/set因此连接的生命周期完全由 Provider 自身管理创建时打开移除时关闭。四、Item 操作GetItem、SetItem、ItemExists、IsValidPath本样本的类声明为[CmdletProvider(AccessDB, ProviderCapabilities.None)] public class AccessDBProvider : ItemCmdletProviderCmdletProvider特性注册了提供程序名称AccessDB对应Get-PSProvider中显示的名字继承ItemCmdletProvider意味着实现了“单项”操作能力需要重写以下方法。4.1 GetItem按路径取表或行GetItem 先判断路径是否就是驱动器本身PathIsDrive若是则输出驱动器对象否则用GetNamesFromPath把路径解析为“表名 行号”并按类型分发路径代表表PathType.Table→ 调用GetTable(tableName)用WriteItemObject(table, path, true)输出第三个参数isContainer为true因为表可包含行路径代表行PathType.Row→ 调用GetRow(tableName, rowNumber)用WriteItemObject(row, path, false)输出否则抛出终止性异常ThrowTerminatingInvalidPathException。4.2 SetItem更新一行数据SetItem 演示了“通过 Provider 写数据”的完整链路PathType type GetNamesFromPath(path, out tableName, out rowNumber); if (type ! PathType.Row) { /* 仅支持更新行否则写 SetNotSupported 错误 */ } OdbcDataAdapter da GetAdapterForTable(tableName); DataSet ds GetDataSetForTable(da, tableName); DataTable table GetDataTable(ds, tableName); string[] colValues (values as string).Split(,); DataRow row table.Rows[rowNumber]; for (int i 0; i colValues.Length; i) { row[i] colValues[i]; } if (ShouldProcess(path, SetItem)) { da.Update(ds, tableName); }关键设计values 约定Set-Item传入的values被当作逗号分隔字符串按列顺序逐列写入DataRow越界保护rowNumber table.Rows.Count时抛出ArgumentException提示新增行应使用NewItem该能力在后续样本中实现写入确认使用ShouldProcess(path, SetItem)包裹da.Update(...)使-Confirm等确认机制生效——这是 PowerShell Provider 实现写操作时的标准做法无手工 SQL 更新语句更新通过OdbcDataAdapterOdbcCommandBuilder自动生成SetItem本身不需要编写任何 UPDATE SQL。4.3 ItemExists 与 IsValidPathItemExists对驱动器路径恒返回true对表路径要求GetTable结果非空对行路径还要求行号小于table.RowCount。IsValidPath先做空值检查再通过NormalizePath把/统一替换为反斜杠然后用pathSeparator拆分路径段任何一段为空即视为非法。这两个方法分别支撑Test-Path与路径合法性校验等内建 cmdlet 语义。五、路径解析机制PathType、表名校验与防注入5.1 路径分段与类型判定GetNamesFromPath是整套路径语义的核心其解析规则为路径段数语义结果仅驱动器根整个数据库PathType.Database1 段表名须通过TableNameIsValidPathType.Table2 段表名 行号须能转换为非负整数PathType.Row超过 2 段非法写入PathNotValid错误行号转换使用SafeConvertRowNumber捕获FormatException写入RowStringFormatNotValid与OverflowException写入RowStringConversionToNumberFailed失败时返回-1表示无效。5.2 表名正则防御 SQL 注入源码中定义的表名校验正则private static string pattern ^[a-z][0-9]*_*$;TableNameIsValid用该正则RegexOptions.Compiled | RegexOptions.IgnoreCase匹配表名不匹配即写入TableNameNotValid错误。由于表名随后会被拼进Select count(*) from \ tableName \之类的 SQL 语句中这一白名单式校验是防御 SQL 注入的关键一环——只允许“字母开头、可跟数字和下划线”的标识符。5.3 其他辅助方法GetTables/GetRows枚举数据库全部表通过connection.GetSchema(Tables)或指定表的全部行通过 DataAdapter 填充 DataSet分别生成DatabaseTableInfo/DatabaseRowInfo集合枚举行数时执行SELECT count(*)失败则按 0 处理GetAdapterForTable校验表名合法且表存在后创建OdbcDataAdapter并关联OdbcCommandBuilder使后续 UPDATE 无需手写 SQL连接未打开时自动Open()GetDataSetForTable/GetDataTable以DataSet作为数据源的内存表示并把Locale设为InvariantCulturePathIsDrive用path.Replace(this.PSDriveInfo.Root, )判断路径是否仅剩驱动器根。六、辅助类驱动器状态与“表/行”信息对象三个辅助类都在源码 AccessDBProviderSample03.cs 中定义AccessDBPSDriveInfo : PSDriveInfo唯一新增成员是OdbcConnection Connection属性承载驱动器生命周期内的数据库连接DatabaseTableInfo包含Data来自 Tables schema 的 DataRow、Name表名、RowCount行数、Columns列定义集合。语义上对应“目录”DatabaseRowInfo包含Data行的 DataRow与RowNumber行索引字符串。语义上对应“文件”。这些对象由 Provider 在GetItem等方法的WriteItemObject中输出用户可以在管道中对它们进行后续处理或格式化显示。七、构建样本7.1 工程配置解决方案 AccessDBProviderSample03.sln 为 Visual Studio 2012 格式工程文件 AccessDBProviderSample03.csproj 的关键配置如下OutputType为Library——本样本编译结果是DLL模块而非可执行文件AssemblyName为AccessDBProviderSample03对应运行步骤中的Import-Module .\AccessDBProviderSample03.dllTargetFrameworkVersion为v4.0引用了System.Management.AutomationVersion 3.0.0.0通过 GAC 路径引入、System.DataODBC/DataSet 所需、System.Xml等程序集Debug 配置输出到.\bin\Debug\Release 配置输出到.\bin\Release\与 README 中“库将构建在默认 \bin 或 \bin\Debug 目录”的描述一致。7.2 构建步骤Visual Studio启动 Visual Studio选择File→Open→Project/Solution进入样本目录 Samples/PowerShell/Provider/AccessDBProvider03/cs双击解决方案文件AccessDBProviderSample03.sln按F7或通过Build→Build Solution构建产物出现在bin\Debug\AccessDBProviderSample03.dll或 Release 目录。八、运行样本按 README 给出的步骤在 Windows PowerShell 中操作启动 Windows PowerShell切换到包含样本 DLL 的目录如bin\Debug加载模块Import-Module .\AccessDBProviderSample03.dll查看新出现的提供程序Get-PSProvider应能看到名为AccessDB的提供程序条目。创建并查看驱动器。结合源码中NewDrive的校验规则-Root必须是指向真实存在的 .mdb 文件的路径New-PSDrive -Name mydb -PSProvider AccessDB -Root C:\samples\test.mdb Get-PSDrive mydbNew-PSDrive会触发NewDrive进而打开 ODBC 连接并把AccessDBPSDriveInfo挂到该驱动器上。用Get-Item/Set-Item操作数据。路径语义为驱动器:表名与驱动器:表名\行号# 取整张表 Get-Item mydb:\Employees # 取第 2 行行号从 0 开始 Get-Item mydb:\Employees\1 # 更新第 2 行的各列值逗号分隔字符串 Set-Item mydb:\Employees\1 -Value 张三,IT,10000 # 验证是否存在 Test-Path mydb:\Employees需要说明的前提与限制README 声明的操作系统要求为客户端Windows 8.1、服务器Windows Server 2012 R2并面向 .NET Framework 4.0 / System.Management.Automation 3.0数据库访问依赖本机安装的Microsoft Access Driver (*.mdb)ODBC 驱动因此需要相应 Access/ODBC 组件可用表名必须满足源码正则^[a-z][0-9]*_*$Set-Item仅支持更新已存在的行新增行需使用NewItem本样本未实现属后续样本范畴。九、与系列样本的关系及延伸学习本样本只实现了 Item 层面的操作ItemCmdletProvider。同一仓库中还有 AccessDBProvider01、AccessDBProvider02、AccessDBProvider04、AccessDBProvider05、AccessDBProvider06 等后续样本用于演示更多 Provider 功能如导航、内容、子项目等能力。想系统学习 PowerShell Provider 的完整体系可以按编号顺序通读该系列想快速把握“驱动器 Item 操作”这一最小闭环本样本Sample 03是首选的精读对象。赞分享示例工程【免费下载链接】Windows-classic-samplesThis repo contains samples that demonstrate the API used in Windows classic desktop applications.项目地址https://gitcode.com/gh_mirrors/wi/Windows-classic-samples点击查看免费下载相关推荐Windows 驱动示例解析基于 KMDF 的 WMI 数据提供程序WmiSamp完整实现指南Windows 驱动示例解析基于 KMDF 的 WMI 数据提供程序WmiSamp完整实现指南 本文以 Windows driver samples 仓库示例工程YARP动作转换提供程序ActionTransformProvider实现YARP动作转换提供程序ActionTransformProvider实现 概述 在YARPYet Another Reverse Proxy反向代理框架后端API网关网络基于证据驱动为 AI Agent 编写 Trellis Spec以 EcoPaste 仓库为范例的实操指南基于证据驱动为 AI Agent 编写 Trellis Spec以 EcoPaste 仓库为范例的实操指南 本文以 EcoPaste 仓库中的 spec wr桌面应用开发工具上一篇Sysboost核心组件解析elfmerge、sysboostd与加载器的协同工作原理下一篇OpenEuler Sw Committee邮件列表使用指南高效沟通的4个秘诀创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑