Ei, Scripting Guy! Trabalhando com bancos de dados do Access no Windows PowerShell

The Microsoft Scripting Guys

bancos de dados são partes misteriosas de software. Em sua forma mais simples são nada mais do que gabinetes de arquivamento para armazenar informações. A mágica real começa com a aplicação dessas informações armazenadas. É claro, o máximo beautifully criado banco de dados sem os registros não é mais do que um exercício acadêmico nada. Ele é os dados que faz o banco de dados. Sempre que ouvimos sobre alguém que tenha um banco de dados grande, as pessoas reagem com awe. Não devido ao banco de dados, mas para os dados, ele contém.

Como faz tudo o que dados obtém em um banco de dados? Entrada manual dos dados em um banco de dados é para os pássaros, e ele deu com cartões de ponto chaves. Para criar um banco de dados grande o suficiente para impressionar os seus amigos e fornecer o potencial para desbloquear o mistério de sua rede, você precisa automatizar. Hoje em dia, isso significa que o Windows PowerShell, e neste artigo, é o que usaremos para coletar alguns dados sobre o computador local e gravá-los para um banco de dados do Office Access chamado ComputerData.mdb. Este banco de dados pode ser criado à mão, ou você pode usar o script encontrado no artigo" Como criar um banco de dados com mais de uma tabela?." Será chamamos nosso script WriteToAccessDatabase.ps1 para será sabemos o que ele faz.

Vamos começar criando a função de check-Path, que será usada para Certifique-se de que o banco de dados existe. Para criar a função, é usar a palavra-chave de função, dar a função um nome e definir qualquer entradas variáveis que talvez precise receber. A coisa de que primeiro faz de check-caminho é usar o cmdlet Test-Path para ver se o diretório no caminho do banco de dados existe. Para fazer isso, ele usa o cmdlet de caminho de Dividir para dividir o caminho em uma parte pai e uma parte filho. Precisamos apenas parte do caminho para verificar a existência do diretório pai. Eis como usamos caminho dividido para recuperar o caminho pai:

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

Em vez de verificar a presença do caminho, usamos o operador Not (!) para procurar a sua ausência. Se a pasta não existir, a palavra-chave de Throw é usada para gerar um erro:

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

Mesmo se a pasta existir, o arquivo de banco de dados poderão estar ausente. Usamos a palavra-chave ELSE para apresentar essa condição alternativa. Uma vez, usamos a instrução IF para procurar a presença do arquivo de banco de dados e a palavra-chave throw para gerar um erro se ele não existir:

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

Na verdade não precisamos usar a construção IF…ELSE para verificar a existência do banco de dados. Uma chamada simples para o cmdlet Test-caminho usando o parâmetro –path funcionaria. No entanto, usar IF…ELSE fornece um nível mais alto de comentários. Queremos saber se o diretório existe e, em caso afirmativo, o arquivo existe? É certamente possível o banco de dados pode ser faltando da pasta, mas também é possível que a pasta propriamente dito pode estar falta. Isso fornece comentários mais granular e pode ajudar na solução de problemas.

Quando é ter garantida que o banco de dados existe, criamos a função de Get-BIOS para obter as informações de BIOS da classe WMI Win32_Bios. Aqui está a função de Get-BIOS:

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

Ao encapsular a chamada WMI em uma função, obtemos a capacidade de alterar facilmente a função, como adicionar recurso remoto ou aceitar as credenciais. A modificação pôde ser feita aqui sem afetar o restante do script. Na verdade, de uma perspectiva de teste, se não funcionar, você simplesmente comentar o código da função e o script restante continua a trabalhar. Para obter ajuda na localização de informações relacionadas às classes WMI, você pode usar o Windows PowerShell Scriptomaticmostra a Figura 1 . Essa ferramenta permite que você facilmente explorar namespaces do WMI e classes e até mesmo cria o script do Windows PowerShell para recuperar as informações.

fig01.gif

Figura 1 versão do Windows PowerShell do utilitário Scriptomatic

Em seguida, vamos criar a função de Get-vídeo para recuperar informações de vídeo da classe WMI Win32_VideoController. Como você pode ver, essa função é semelhante à função de Get-BIOS:

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

Agora precisamos fazer uma conexão com o banco de dados. Para fazer isso, usamos a função de conectar-se-banco de dados. Nós criamos dois parâmetros de entrada para a função de conectar-se-banco de dados: –DB e –Tables cujos valores são armazenados no DB $ e $ tabelas variáveis dentro a função. A primeira coisa que em conectar-se-banco de dados funcionam é atribuir valores para algumas variáveis que são usadas para controlar o maneira como o RecordSet é aberto. O método Open do objeto RecordSet pode aceitar até cinco diferentes parâmetros, da seguinte maneira:

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

A primeira é o parâmetro de origem, que é avaliada como um objeto de comando válido, uma instrução SQL, um nome de tabela, uma chamada de procedimento armazenado, um URL ou o nome de um objeto de arquivo ou fluxo que contém um conjunto de registros armazenado de maneira persistente. O segundo parâmetro é o ActiveConnection, uma seqüência de caracteres avaliada como um objeto de conexão válida ou uma seqüência de caracteres que contém parâmetros connectionstring. O parâmetro de propriedades CursorType é usado para determinar o tipo de cursor que será usado ao abrir o RecordSet. Valores permitidos para o tipo de cursor são mostrados na Figura 2 .

A Figura 2 ADO cursor tipo enumeração constantes e valores
Constante Valor Descrição
adOpenDynamic 2 Usa um cursor dinâmico. Adições, alterações e exclusões por outros usuários estão visíveis, e todos os tipos de movimento através do conjunto de registros são permitidos, exceto para indicadores, se o provedor não suportá-los.
adOpenForwardOnly 0 O padrão. Usa um cursor forward-only. Idêntico a um cursor estático, exceto que seja possível apenas rolar frente através de registros. Isso melhora o desempenho quando você precisa fazer somente uma passagem por meio de um conjunto de registros.
adOpenKeyset 1 Usa um cursor de conjunto de chaves. Como um cursor dinâmico, exceto que você não pode ver registros que outros usuários adicionam e registros que outros usuários excluírem são inacessíveis do seu conjunto de registros. Alterações de dados por outros usuários estão ainda visíveis.
adOpenStatic 3 Usa um cursor estático, que é uma cópia estática de um conjunto de registros que você pode usar para localizar dados ou gerar relatórios. Adições, alterações ou exclusões por outros usuários não estão visíveis.
adOpenUnspecified -1 Não especifica o tipo de cursor.

O parâmetro LockType é usado para determinam o tipo de bloqueio a ser usado ao atualizar registros, e o parâmetro de opções é usado para informar o provedor como avaliar o parâmetro de origem. Os valores permitidos para o parâmetro LockType são mostrados na Figura 3 .

A Figura 3 ADO bloquear tipo enumeração constantes e valores
Constante Valor Descrição
AdLockBatchOptimistic 4 Indica as atualizações em lotes otimista. Necessário para o modo de atualização em lotes.
AdLockOptimistic 3 Indica a proteção otimista, registro por registro. O provedor usa bloqueio otimista, que bloqueia registros somente quando você chamar o método Update.
AdLockPessimistic 2 Indica a proteção pessimista, registro por registro. O provedor faz o que é necessário para garantir bem-sucedida edição dos registros, geralmente por bloquear registros na fonte de dados imediatamente após a edição.
adLockReadOnly 1 Indica os registros de somente leitura. Você não pode alterar os dados.
adLockUnspecified -1 Não especifica um tipo de bloqueio. Para clones, o clone é criado com o mesmo tipo de bloqueio que o original.

Todos os cinco dos parâmetros para o método Open do objeto RecordSet são opcionais; em geral, usamos apenas quatro primeiro. Depois que tiver atribuído valores a serem usados para a enumeração de cursor e o tipo de bloqueio, usamos o cmdlet New-Object para criar um novo objeto de ADODB.Connection que armazenamos na variável de conexão $. Em seguida, usamos o método Open do objeto Connection, que precisa, o nome do provedor e a fonte de dados. Em seguida, chamamos a função de registros de atualização e passar a variável de tabelas $. Aqui está a função de banco de dados-conectar-se:

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

Na função registros de atualização, a primeira coisa que fazemos é criar uma instância do objeto ADODB.Recordset. Use o cmdlet New-Object para fazer isso e armazenar o objeto RecordSet recém-criado na variável $ RecordSet. Em seguida, usamos o para cada instrução para percorrer a nossa matriz das tabelas. Os nomes de tabela são armazenados na variável $ tabelas e são atribuídos no início do script. Dentro do loop ForEach, primeiro criamos nossa consulta, que é uma seleção genérica em vez disso, * da tabela $. A vantagem de usar uma variável para o nome de tabela é que só precisamos escrever o código de uma vez; o nome da tabela na consulta é alterado toda vez que percorra a matriz de nomes de tabela.

Agora, chegamos ao método aberto do objeto RecordSet. Especificamos a consulta que é armazenada na variável $ consulta, o objeto de conexão na variável $ conexão, o valor de OpenStatic $ e o valor de LockOptimistic $ para controlar o maneira como o RecordSet é aberto. Então, usamos o cmdlet Invoke-expressão para executar o valor de uma seqüência de caracteres. Nós fazer isso porque nós criamos duas funções que foram criadas para atualizar as tabelas de banco de dados diferente. Chamamos as funções após as tabelas que eles atualizar. Nós não são permitidas para chamar um nome de função quando metade dele é uma variável, portanto, é necessário resolver a variável e, em seguida, chamar a função.

Mas que não funciona um — pelo menos não diretamente. O deseja fazer é tratar o nome da função como se fosse uma seqüência de caracteres e não um comando. Mas queremos executá-lo como um comando. Para fazer isso, é usar expressões de Invoke. Esse cmdlet chama cada uma das funções de atualização diferente. Dentro do loop passa a matriz de nomes de tabela, fechar cada um dos objetos RecordSet, e retornar para o próximo item na matriz de nomes de tabela, crie uma nova consulta, abrir um novo objeto RecordSet e chamar uma nova função. Esse processo continua para cada tabela de nomes na matriz de tabelas, como para:

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()
     }

Depois dos registros são atualizados, poderá fechar a conexão. Para fazer isso, usamos o método Close do objeto Connection:

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

A função de registros de atualização chama duas funções de suporte, Update-BIOS e Update-vídeo, que são projetados para atualizar os campos apropriados na tabela de banco de dados respectivos. Se você adicionar tabelas adicionais ao seu banco de dados, você precisará adicionar uma função de atualização * adicional para atualizar as novas tabelas. Como prática recomendada, é recomendável manter os nomes de campo do banco de dados para o mesmo que os nomes de propriedade WMI. Ele torna as coisas muito mais fácil controlar. Ao escrever um script para atualizar um banco de dados existente, convém examinar o esquema de banco de dados para as tabelas, colunas e tipos de dados contidos nos campos. O esquema de banco de dados para o banco de dados ComputerData é mostrado na Figura 4 . Este modo de exibição foi gerado pelo script do artigo" Como posso saber quais tabelas e colunas estão em um banco de dados sem abrir-?"

fig04.gif

A Figura 4 A esquema de banco de dados para o banco de dados ComputerData

Na função Update-BIOS, nós primeiro postar uma mensagem informando que está atualizando as informações de BIOS. Nós, em seguida, chamar a função de Get-BIOS e armazenamos o objeto WMI Win32_Bios retornado na variável BiosInfo $. Agora precisamos adicionar um registro à tabela de banco de dados. Para fazer isso, chamamos o método AddNew do objeto RecordSet. Após obtermos um novo registro, adicionamos informações ao cada um dos campos na tabela. Quando todos os campos tiverem sido atualizados, chamamos o método Update para confirmar o registro à tabela. A função de BIOS de atualização completa é mostrada aqui:

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

Quando a tabela de BIOS tiver sido atualizada, é necessário atualizar a tabela de vídeo. Para fazer isso, podemos chamar a função de vídeo de atualização, que é exatamente o mesmo que a função de BIOS de atualização. É apresentar uma mensagem informando que está atualizando o vídeo, chame a função de vídeo de Get para recuperar as informações de vídeo, chame o método AddNew para adicionar um novo registro à tabela de vídeo e escreva todas as informações aos campos adequados. Quando nós tiver terminados, chamamos o método de atualização.

Um possível problema na coleta as informações de vídeo é o número de controladores de vídeo no computador. Meu computador pessoal tem um cartão filha e relatórios de vários controladores de vídeo. Para lidar com esse eventualidade, usamos a instrução ForEach para iterar através de um conjunto de Win32_VideoControllers. Se você não estiver interessado nas informações de configuração do cartão de filha ou se a placa de vídeo é canal duplo e relata as informações de mesmas duas vezes, você pode remover o loop ForEach e selecione $ VideoInfo [0] ao índice diretamente para o primeiro gravar que é relatado. O problema com essa abordagem é que se a consulta retornar um singleton, você gerará um erro porque você não pode indexar em um único registro:

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

O ponto de entrada para o script aponta para o banco de dados, lista as tabelas e, em seguida, chama a função de banco de dados de conexão, conforme mostrado aqui:

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

Após a execução do script, novos registros são gravados o banco de dados ComputerData.mdb como mostrado na Figura 5 . O script WriteToAccessDatabase.ps1 completo pode ser visto na Figura 6 .

fig05.gif

A Figura 5 novos registros adicionados ao banco de dados ComputerData.mdb

A Figura 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

Se você deseja saber mais sobre como trabalhar com bancos de dados Office Access no Windows PowerShell, faça check-out "Ei, Equipe de Scripts!" arquivo para a semana de, 20 de fevereiro de 2009. Além disso, a 2009 jogos de script de verão estiver em breve! Visite scriptingguys.com Para obter mais informações.

Ed Wilson , uma especialista em scripts conhecida, é autor do oito livros, incluindo Windows PowerShell Scripting Guide (2008) e Microsoft Windows PowerShell Step by Step (2007). Ed contém mais de 20 certificações do setor, incluindo Microsoft Certified Systems Engineer (MCSE) e o Professional de Security Systems (CISSP) de informações do certificado. Em seu tempo livre, ele goza woodworking, fotografia submarinas e scuba diving. E Chá.

Craig Liebendorfer é um wordsmith e longtime editor da Microsoft. Craig ainda não acredito há um trabalho que paga-lo para trabalhar com palavras todos os dias. Uma das suas coisas favoritas é irreverent humor, para que ele deve ajustar direita em aqui. Ele considera seu accomplishment maior na vida seja sua filha magnificent.