嗨,脚本专家 ! 使用 Windows PowerShell 中的 Access 数据库

The Microsoft Scripting Guys

数据库是 特殊的部分软件。 在最简单的表单中使用它们是只不过归档 CAB 压缩包用于存储信息。 实际 Magic 开头此存储的信息的应用程序。 当然,最 beautifully 设计的数据库没有任何记录是只不过 Academic 练习。 它为使该数据库的数据。 每当我们听到关于具有极大的数据库的人员,人员作出反应与 awe。 由于不必在的数据库而数据包含。

如何所有这些数据获取到数据库? 手动输入到数据库的数据用于在的 birds,出使用密钥的打孔卡了。 若要生成数据库大小足以 Impress 您的朋友,并提供可能解锁您的网络神秘感,您必须自动化。 目前,意味着 Windows PowerShell,和本文,这是我们将使用来收集有关本地计算机的某些数据并将其写入到名为 ComputerData.mdb Office Access 数据库内容。 可以手动,创建此数据库,或使用文章中找到该脚本" 我如何可以创建具有多个表的数据库?." 我们将调用脚本 WriteToAccessDatabase.ps1,因此我们将知道它的作用。

我们首先创建签入路径函数将用来确保数据库存在。 要创建该函数,我们使用函数关键字,为该函数命名,然后定义任何输入的变量,就需要接收。 第一次操作检查的路径是否是使用 Test-路径 cmdlet 数据库路径中的目录是否存在。 要这样做,它要使用拆分路径 cmdlet 分成一父部分以及子部分的路径。 我们只需要验证目录的存在路径的父部分。 下面是如何我们使用拆分路径检索父路径:

PS C:\> Split-Path C:\fso\ComputerData.mdb -Parent
C:\fso

我们使用 Not 而不是检查是否存在该路径的以查找缺少运算符 (!)。 如果不在不存在文件夹 throw 关键字使用引发错误:

Function Check-Path($Db)
{
 If(!(Test-Path -path (Split-Path -path $Db -parent)))
   { 
     Throw "$(Split-Path -path $Db -parent) Does not Exist" 
   }

即使该文件夹存在,数据库文件可能已丢失。 我们使用 ELSE 关键字来引入该替换条件。 再一次,我们使用 IF 语句查找存在该数据库文件和 throw 关键字引发错误,如果该项不存在:

  ELSE
  { 
   If(!(Test-Path -Path $Db))
     {
      Throw "$db does not exist"
     }
  }
} #End Check-Path

我们不真正需要使用 IF…ELSE 构造来验证数据库存在。 工作对 cmdlet 测试的路径使用 –path 参数简单的调用。 但是,如果使用 IF…ELSE 中,则提供更高级别的反馈。 我们想知道是否该目录存在并且,如果是这样,执行该文件存在时? 数据库可能从文件夹丢失,但也可能文件夹本身可能是缺少是当然可能是。 这提供了更精确的反馈,并可以帮助进行疑难解答。

我们已确保数据库存在时, 我们将创建在获取 BIOS 函数,来从 Win32_Bios WMI 类中获取 BIOS 信息。 下面是获取 BIOS 函数:

Function Get-Bios
{
 Get-WmiObject -Class Win32_Bios
} #End Get-Bios

通过封装函数在 WMI 调用,我们可以能够方便地更改诸如添加远程功能,或接受的凭据的该函数。 修改能此处建立而不影响脚本的其余部分。 实际上,从测试的角度如果还不行您只是注释掉函数代码,其余的脚本会继续运行。 对于帮助以查找与 WMI 类的信息,您可以使用在 Windows PowerShell Scriptomatic 图 1 所示。 此工具可以轻松地浏览 WMI 命名空间和类,并甚至创建 Windows PowerShell 脚本,以检索信息。

fig01.gif

图 1 的 Scriptomatic 实用工具的 Windows PowerShell 版

接下来,我们将创建获取视频函数,以检索 Win 32 _ VideoController WMI 类的视频的信息。 正如您所看到的则此函数是类似于获取 BIOS 功能:

Function Get-Video
{
 Get-WmiObject -Class Win32_VideoController
} #End Get-Video

现在我们需要连接到数据库。 为此,我们使用连接数据库函数。 我们创建两个连接数据库函数的输入的参数: –DB 和其值存储在 $ 数据库和 $ –tables 表在函数的变量。 首先我们在连接数据库的函数是为几个用于控制在打开该记录集方式的变量中。 记录集对象的打开的方法可以如下所示接受达五个不同的参数:

RecordSet.Open Source, ActiveConnection, CursorType, LockType, Options 

第一个是源参数计算结果为有效 Command 对象、 SQL 语句、 表名称、 存储的过程调用、 一个的 URL 或文件或 Stream 对象包含永久存储的 Recordset 的名称。 第二个参数是将 ActiveConnection、 计算结果为有效的 Connection 对象的字符串或包含 connectionstring 参数的字符串。 CursorType 参数用于确定将在打开该记录集时使用的游标的类型。 游标类型的允许值 图 2 所示。

图 2 ADO 游标类型枚举常量和值
常量 说明
adOpenDynamic 2 使用动态游标。 所添加、 更改和删除由其他用户均可见,且记录集的移动所有类型都允许,除外的书签,如果提供程序不支持它们。
adOpenForwardOnly 0 默认值。 使用仅向前型游标。 与静态的游标在于您可以仅记录中向前滚动。 这样可以在您需要通过一个记录集仅一次时提高性能。
adOpenKeyset 1 使用键集游标。 像动态的游标在于您无法看到其他用户添加的记录和其他用户删除的记录是从您的 Recordset 不可访问。 由其他用户的数据更改是仍然可见的。
adOpenStatic 3 使用是一组用于查找数据或生成报表的记录的静态副本一个静态游标。 添加、 更改或由其他用户的删除不可见。
adOpenUnspecified -1 不指定游标的类型。

LockType 参数用于控制更新记录时, 要使用的锁定的类型,该选项参数用于通知提供程序如何计算源参数。 LockType 参数,允许值 图 3 所示。

图 3 ADO 锁定类型枚举常量和值
常量 说明
AdLockBatchOptimistic 4 指示开放式批更新。 需要的批更新模式。
AdLockOptimistic 3 指示开放式锁定,记录的记录。 提供程序使用开放式锁定仅在调用 Update 方法时,它锁定记录。
AdLockPessimistic 2 指示保守式锁定,记录的记录。 提供程序执行必要的以确保成功编辑该的记录通常通过编辑后立即锁定数据源的记录。
adLockReadOnly 1 指示只读记录。 您无法更改数据。
为 adLockUnspecified -1 不指定锁定类型。 对于克隆,克隆创建具有相同的锁定类型,与原始。

所有 5 个记录集对象的 Open 方法的参数是可选的 ; 通常,使用只有第一个四。 我们已分配用于光标枚举和锁类型的值后,我们使用新对象的 cmdlet 创建新的 ADODB.Connection 对象我们 $ 连接变量中存储的。 我们种方式可以然后使用 Open 方法从连接对象需要提供程序名称和数据源。 我们然后调用更新记录功能,并将 $ 表变量。 下面是连接数据库函数:

Function Connect-Database($Db, $Tables)
{
  $OpenStatic = 3
  $LockOptimistic = 3
  $connection = New-Object -ComObject ADODB.Connection
  $connection.Open("Provider = Microsoft.Jet.OLEDB.4.0;Data Source=$Db" )
  Update-Records($Tables)
} #End Connect-DataBase

在更新记录函数中的首先我们要做的是创建 ADODB.Recordset 对象的实例。 我们使用 New-对象的 cmdlet 执行此操作,并将新创建的记录集对象存储在 $ 记录集变量中。 接下来,我们使用在 For Each 语句以遍历表的数组。 表名称 $ 表变量中存储,并且分配在脚本的开头。 在 ForEach 循环内我们首先创建我们是而不是泛型的选择查询 * $ 表中。 为表名中使用一个变量的优点我们只需一次编写代码 ; 表名称,在查询中的获取更改每次我们遍历表名称的数组。

我们现在是给记录集对象的 Open 方法。 我们指定 $ 查询变量 $ 连接变量、 将 $ OpenStatic 值及 $ LockOptimistic 值来控制在打开该记录集方式中的 Connection 对象中存储的查询。 然后,我们使用调用表达式 cmdlet 执行一个字符串的值。 我们这样做的原因我们已经创建了两个函数,用于更新不同的数据库表。 我们在更新的表命名函数。 我们不允许时它的一半是一个的变量,因此我们需要解析变量,然后调用函数,调用某个函数名称。

但是,不无法工作至少不直接。 我们要做是视为一个字符串和不命令处理函数名称。 但我们希望执行该命令类似。 为此,我们使用调用表达式。 此 cmdlet 调用每个不同的更新功能。 在经过表名称的数组的循环我们关闭每个记录集对象,然后返回到下一个项目数组中的表的名称,创建一个新查询,打开新的记录集对象并调用一个新的函数。 这将继续为表的数组中每个表类似名称这样:

Function Update-Records($Tables)
{
  $RecordSet = new-object -ComObject ADODB.Recordset
   ForEach($Table in $Tables)
     {
      $Query = "Select * from $Table"
      $RecordSet.Open($Query, $Connection, $OpenStatic, $LockOptimistic)
      Invoke-Expression "Update-$Table"
      $RecordSet.Close()
     }

更新记录后,我们可以关闭连接。 为此,我们使用 Close 方法从连接对象:

   $connection.Close()
} #End Update-Records

更新记录功能调用两个支持功能、 更新 BIOS 和更新视频这为了更新各自的数据库表中相应的字段。 如果您要向数据库中添加其他表,您需要添加用于更新新表的其他更新 * 函数。 作为最佳做法是,我们建议保持数据库字段名称与 WMI 属性名称相同。 使内容更易于跟踪。 编写一个脚本来更新现有数据库时, 可能要查看表、 列和在字段中包含的数据类型的数据库架构。 ComputerData 数据库的数据库架构如 图 4 所示。 此视图是由从文章脚本生成的" 怎样知道哪些表和数据库中的列被不打开它?"

fig04.gif

图 4 ComputerData 数据库的数据库架构

在更新 BIOS 函数中,我们首次发布一条消息说明我们正在更新 BIOS 信息。 我们然后调用获取 BIOS 函数,并将返回的 WMI Win32_Bios 对象存储在变量 $ BiosInfo。 现在我们需要向数据库表中添加记录。 为此,我们将从记录集对象调用 AddNew 方法。 我们有一条新记录之后,我们将信息添加到每个表中字段。 更新所有字段,我们调用 Update 方法将记录提交到表。 完成更新的 BIOS 功能如下:

Function Update-Bios
{
 "Updating Bios"
 $BiosInfo = Get-Bios
 $RecordSet.AddNew()
 $RecordSet.Fields.Item("DateRun") = Get-Date
 $RecordSet.Fields.Item("Manufacturer") = $BiosInfo.Manufacturer
 $RecordSet.Fields.Item("SerialNumber") = $BiosInfo.SerialNumber
 $RecordSet.Fields.Item("SMBIOSBIOSVersion") = $BiosInfo.SMBIOSBIOSVersion
 $RecordSet.Fields.Item("Version") = $BiosInfo.Version
 $RecordSet.Update()
} #End Update-Bios

在更新 BIOS 表需要更新视频的表。 为此中,,我们可以调用该更新视频为函数这正是与更新 BIOS 函数相同。 我们将显示一条消息说明我们正在更新视频,调用 get-视频函数来检索视频信息、 调用 AddNew 方法在视频的表中添加一个新的记录并将所有信息写入相应字段。 当我们做我们将调用 Update 方法。

在收集视频信息的潜在问题是在计算机上的视频控制器的数。 我的个人计算机有女儿卡,并报告多个视频控制器。 若要处理此 eventuality,我们使用 ForEach 语句循环访问 Win32_VideoControllers 的集合。 如果您不感兴趣的女儿卡配置信息,或者如果您的视频卡是双通道,并且向索引报告相同的信息可以在两次,删除 ForEach 循环并选择 $ VideoInfo [0],直接在第一个记录的报告。 使用此方法问题是如果查询返回单一实例,您将生成一个错误,因为无法索引成一个记录:

Function Update-Video
{ "Updating video" $VideoInformation = Get-Video 
Foreach($VideoInfo in $VideoInformation)  
  {
   $RecordSet.AddNew()   $RecordSet.Fields.Item("DateRun") = Get-Date
   $RecordSet.Fields.Item("AdapterCompatibility") = $VideoInfo.AdapterCompatibility
   $RecordSet.Fields.Item("AdapterDACType") = $VideoInfo.AdapterDACType
   $RecordSet.Fields.Item("AdapterRAM") = $VideoInfo.AdapterRAM
   $RecordSet.Fields.Item("Description") = $VideoInfo.Description
   $RecordSet.Fields.Item("DriverDate") = $VideoInfo.DriverDate
   $RecordSet.Fields.Item("DriverVersion") = $VideoInfo.DriverVersion
   $RecordSet.Update()
  }
} 
#End Update-Video

入口点脚本指向在的数据库列出在的表,然后调用此连接数据库函数 (如下所示:

$Db = "C:\FSO\ComputerData.mdb"+
$Tables = "Bios","Video"
Check-Path -db $Db
Connect-DataBase -db $Db -tables $Tables

在运行该脚本后,新记录将写入到 ComputerData.mdb 数据库中,如 图 5 所示。 图 6 中,可以看到完整的 WriteToAccessDatabase.ps1 脚本。

fig05.gif

图 5 添加到 ComputerData.mdb 数据库的新记录

图 6 WriteToAccessDataBase.ps1

Function Check-Path($Db)
{
 If(!(Test-Path -path (Split-Path -path $Db -parent)))
   { 
     Throw "$(Split-Path -path $Db -parent) Does not Exist" 
   }
  ELSE
  { 
   If(!(Test-Path -Path $Db))
     {
      Throw "$db does not exist"
     }
  }
} #End Check-Path

Function Get-Bios
{
 Get-WmiObject -Class Win32_Bios
} #End Get-Bios

Function Get-Video
{
 Get-WmiObject -Class Win32_VideoController
} #End Get-Video

Function Connect-Database($Db, $Tables)
{
  $OpenStatic = 3
  $LockOptimistic = 3
  $connection = New-Object -ComObject ADODB.Connection
  $connection.Open("Provider = Microsoft.Jet.OLEDB.4.0;Data Source=$Db" )
  Update-Records($Tables)
} #End Connect-DataBase

Function Update-Records($Tables)
{
  $RecordSet = new-object -ComObject ADODB.Recordset
   ForEach($Table in $Tables)
     {
      $Query = "Select * from $Table"
      $RecordSet.Open($Query, $Connection, $OpenStatic, $LockOptimistic)
      Invoke-Expression "Update-$Table"
      $RecordSet.Close()
     }
   $connection.Close()
} #End Update-Records

Function Update-Bios
{
 "Updating Bios"
 $BiosInfo = Get-Bios

 $RecordSet.AddNew()
 $RecordSet.Fields.Item("DateRun") = Get-Date
 $RecordSet.Fields.Item("Manufacturer") = $BiosInfo.Manufacturer
 $RecordSet.Fields.Item("SerialNumber") = $BiosInfo.SerialNumber
 $RecordSet.Fields.Item("SMBIOSBIOSVersion") = $BiosInfo.SMBIOSBIOSVersion
 $RecordSet.Fields.Item("Version") = $BiosInfo.Version
 $RecordSet.Update()
} #End Update-Bios

Function Update-Video
{
 "Updating video"
 $VideoInformation = Get-Video
 Foreach($VideoInfo in $VideoInformation)
  { 
   $RecordSet.AddNew()
   $RecordSet.Fields.Item("DateRun") = Get-Date
   $RecordSet.Fields.Item("AdapterCompatibility") = $VideoInfo.AdapterCompatibility
   $RecordSet.Fields.Item("AdapterDACType") = $VideoInfo.AdapterDACType
   $RecordSet.Fields.Item("AdapterRAM") = $VideoInfo.AdapterRAM
   $RecordSet.Fields.Item("Description") = $VideoInfo.Description
   $RecordSet.Fields.Item("DriverDate") = $VideoInfo.DriverDate
   $RecordSet.Fields.Item("DriverVersion") = $VideoInfo.DriverVersion
   $RecordSet.Update()
  }
} #End Update-Video

# *** Entry Point to Script ***

$Db = "C:\FSO\ComputerData.mdb"
$Tables = "Bios","Video"
Check-Path -db $Db
Connect-DataBase -db $Db -tables $Tables

如果您希望了解有关使用 Windows PowerShell 中 Office Access 数据库,签出的 2009 2 月 20 个周您"好,脚本专家 !"存档。 此外,2009 夏天脚本竞赛即将推出 ! 请访问 scriptingguys.com 有关详细信息。

Ed Wilson ,一个已知的脚本专家是八个书籍,包括 Windows PowerShell Scripting Guide (2008) 和 Microsoft Windows PowerShell Step by Step 的作者 (2007)。 Ed 包含超过 20 个包括 Microsoft 认证系统工程 (MCSE) 和认证信息系统安全专业人员 (CISSP) 行业认证。 在他空闲的时间他受 woodworking、 underwater 摄影和 scuba 所在。 和工作。

Craig Liebendorfer 是 wordsmith 和 longtime 的 Microsoft Web 编辑器。 Craig 仍不能相信还有支付他使用单词每天的作业。 他最喜欢的事情之一是 irreverent 幽默,因此他应适合在此处的右侧。 他认为他的最大 accomplishment 为他你的女儿生命周期中。