Datenzugriffe über ADO.Net - Access Spezial

Access - Spezial

Details

0 Einleitung
0.1 fehlende Provider / Installation und Registrierung von Providern
      Beispiel 1: "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$DatabaseName;"
      Beispiel 2: "Provider = Microsoft.Jet.OLEDB.4.0;Data Source = $DatabaseName"
0.2 Einführungsbeispiele
      Beispiel 1: Daten aus einer AccessDatebank auslesen (DataSet)
      Beispiel2: Daten in eine AccessTabelle schreiben

1 Connectionstrings für x32 und x64 Architekturen
Beispiel 1: "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$DatabaseName;"
Beispiel 2: "Provider = Microsoft.Jet.OLEDB.4.0;..."

2 ADOX
   Beispiel 1: Anlegen einer (leeren) Tabelle und anschließendes Auslesen aller Tabellen der Nordwind.mdb
   Beispiel 2: DesignAnalyse einer bestimmten Tabelle in einer Accessdatenbank
   Beispiel 3: Erstellen einer Tabelle mit zwei Spalten

3 Hilfreiche Links


0 Einleitung

Microsoft Access finde ich ein ziemlich geniales Programm, um einfach strukturierte Daten übersichtlich aufbereiten zu können. 

In der Systemadministration fallen häufig größere Mengen an Daten an, für deren Aufbereitung Excel schon überfordert, aber ein SQLServer noch nicht notwendig ist.
Beispiele sind die Analyse von Eventlogdateien, oder laufende Performancemessungen.
Sollen beispielsweise die Einträge der Securitylogs aus mehreren Domaincontrollern analysiert werden, so kommen schnell einige hundertausend Events in einer Tabelle zusammen. 

0.1 fehlende Provider / Installation und Registrierung von Providern

Bei der Verwendung von ADO.NET Skripten kommt es immer wieder zu Fehlermeldungen, dass der "...Provider ist nicht auf dem lokalen Computer registriert" sei. 

Ausnahme beim Aufrufen von "Open" mit 0 Argument(en):  "Der 'Microsoft.ACE.OLEDB.12.0'-Provider ist nicht auf dem lokalen Computer registriert."
Bei Zeile:19 Zeichen:19
+ $XLConnection.Open <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

.....

Dies hat entweder damit zu tun, dass man einen Provider verwenden möchte, der für das verwendete Betriebssystem bzw. für die Betriebssystemarchitektur (32-bit/ 64-bit) nicht verfügbar ist, oder der im Skript verwendete Provider tatsächlich noch nicht registriert ist. 


Lösungsmöglichkeiten:

  1. Installation des Providers “Microsoft.ACE.OLEDB.12.0”  Microsoft Access Database Engine 2010 Redistributable (empfehlenswert, wenn kein Office 2010 installiert ist!). Damit könnt ihr dann auch auf Access oder Excel zugreifen, selbst wenn kein Office auf dem Client installiert ist. 
     
  2. Angleichung der Architektur von Betriebssystem und Office (32-bit/32-bit oder 64-bit/64-bit)
     
  3. Unter 64-bit Betriebssystem mit 64-bit Office bevorzugt den Connectionstring "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$DatabaseName;"
     
  4. Habt ihr unter einem 64-bit Betriebssystem eine 32-bit Office installiert, verwendet bevorzugt den Connectionstring "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$DatabaseName;", nachdem ihr den ACE-Provider installiert habt (Siehe Punkt 1.). Ohne den ACE-Provider könnt ihr nur den $ConnectionString = "Provider = Microsoft.Jet.OLEDB.4.0;Data Source = $DatabaseName". Ihr müsst in beiden Fällen aber die 32-bit Version der Powershell nutzen:

Hier noch zwei einfache Beispiele, an denen ihr Erkennen könnt, ob der passenden Provider vorhanden ist.
 
Beispiel 1: "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$DatabaseName;"

$DatabaseName = "c:\temp\Nordwind.mdb"
$Query = "SELECT Firma FROM Kunden"

$ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$DatabaseName;"

# Connection Object erstellen
$Connection = New-Object System.Data.OleDb.OleDbConnection $ConnectionString
$Command  = New-Object System.Data.OleDb.OleDbCommand $Query,$Connection
$Connection.Open()

#Daten zuerst in den Adapter laden, danach ins Dataset schreiben 
$Adapter = New-Object System.Data.OleDb.OleDbDataAdapter $Command
$Dataset = New-Object System.Data.DataSet
[void] $Adapter.Fill($DataSet)
$Connection.Close()

#Daten schreiben
$DataSet.Tables | Select-Object -Expand Rows
#mögliche Ausgabe, wenn der 12.0-Provider nicht installiert ist

Ausnahme beim Aufrufen von "Open" mit 0 Argument(en):  "Der 'Microsoft.ACE.OLEDB.12.0'-Provider ist nicht auf dem lokalen Computer registriert."
Bei Zeile:6 Zeichen:17
+ $Connection.Open <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

Viele Beispiele im Internet benutzen als Connectionstring "Provider = Microsoft.Jet.OLEDB.4.0;..." 

wie auch  Hey, Scripting Guy! Can I Query a Microsoft Access Database with a Windows PowerShell Script?

Beispiel 2: "Provider = Microsoft.Jet.OLEDB.4.0;Data Source = $DatabaseName"

$DatabaseName = "c:\temp\Nordwind.mdb"
$Query = "SELECT Firma FROM Kunden"

$ConnectionString = "Provider = Microsoft.Jet.OLEDB.4.0;Data Source = $DatabaseName"

# Connection Object erstellen
$Connection = New-Object System.Data.OleDb.OleDbConnection $ConnectionString
$Command  = New-Object System.Data.OleDb.OleDbCommand $Query,$Connection
$Connection.Open()

#Daten zuerst in den Adapter laden, danach ins Dataset schreiben 
$Adapter = New-Object System.Data.OleDb.OleDbDataAdapter $Command
$Dataset = New-Object System.Data.DataSet
[void] $Adapter.Fill($DataSet)
$Connection.Close()

#Daten schreiben
$DataSet.Tables | Select-Object -Expand Rows
#Ausgabe, wenn der 4.0-Provider nicht installiert ist

Ausnahme beim Aufrufen von "Open" mit 0 Argument(en):  "Der 'Microsoft.Jet.OLEDB.4.0'-Provider ist nicht auf dem lokalen Computer registriert."
Bei Zeile:9 Zeichen:17
+ $Connection.Open <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

 
0.2 Einführungsbeispiele

Beispiel 1: Daten aus einer AccessDatebank auslesen (DataSet)

$DatabaseName = "c:\temp\Northwind.mdb"
$Query = "SELECT Top 4 Firma FROM Kunden"

$ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Temp\nordwind.mdb;"

#Connection Object erstellen
$Connection = New-Object System.Data.OleDb.OleDbConnection $ConnectionString
$Command  = New-Object System.Data.OleDb.OleDbCommand $Query,$Connection
$Connection.Open()

#Daten zuerst in den Adapter laden, danach ins Dataset schreiben
$Adapter = New-Object System.Data.OleDb.OleDbDataAdapter $Command
$Dataset = New-Object System.Data.DataSet
[void] $Adapter.Fill($DataSet)
$Connection.Close()

#Daten schreiben
$DataSet.Tables | Select-Object -Expand Rows
#Ausgabe gekürzt

Firma
-----
Alfreds Futterkiste   
Ana Trujillo Emparedados y helados
Antonio Moreno Taquería
Around the Horn

Dieses Beispiel funktioniert so nur mit einem Office unter 64-bit. Wenn ihr 32-Bit Office verwendet, muss die Zeile 

$dsn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Temp\nordwind.mdb;"

angepasst werden. 

Sollten Meldungen erscheinen, dass der Provider auf dem System nicht installiert ist, so kontrolliert eure OfficeVersion, ob diese tatsächlich unter 64-bit läuft 

Beispiel 2: Daten in eine AccessTabelle schreiben

$adOpenStatic = 3
$adLockOptimistic = 3

$Connection = New-Object -com "ADODB.Connection"
$RecordSet = New-Object -com "ADODB.Recordset"

$Connection.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Temp\Database1.accdb;")

$RecordSet.Open("Select * From Table1", $Connection,$adOpenStatic,$adLockOptimistic)

$RecordSet.AddNew()
$RecordSet.Fields.Item("ComputerName").Value = "Dom1Cli01"
$RecordSet.Fields.Item("IPAddress").Value = "192.168.178.10"
$RecordSet.Update()

$RecordSet.Close()
$Connection.Close(
)

 
1 Connectionstrings für x32 und x64 Architekturen

Liefern die folgende Beispiele Fehlermeldungen zurück, so liegt dies an der unterschiedlichen Verfügbarkeit der von den verschieden 32 und 64-bit Officeversionen benötigten Provider auf 32 und 64-Bit Betriebssystemen

Beispiel 1: "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$DatabaseName;"

$DatabaseName = "c:\temp\Nordwind.mdb"
$Query = "SELECT Firma FROM Kunden"

$ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$DatabaseName;"

#Connection Object erstellen
$Connection = New-Object System.Data.OleDb.OleDbConnection $ConnectionString
$Command  = New-Object System.Data.OleDb.OleDbCommand $Query,$Connection
$Connection.Open()

#Daten zuerst in den Adapter laden, danach ins Dataset schreiben 
$Adapter = New-Object System.Data.OleDb.OleDbDataAdapter $Command
$Dataset = New-Object System.Data.DataSet
[void] $Adapter.Fill($DataSet)
$Connection.Close()

#Daten schreiben
$DataSet.Tables | Select-Object -Expand Rows
#mögliche Ausgabe

Ausnahme beim Aufrufen von "Open" mit 0 Argument(en):  "Der 'Microsoft.ACE.OLEDB.12.0'-Provider ist nicht auf dem lokalen Computer registriert."
Bei Zeile:6 Zeichen:17
+ $Connection.Open <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

Viele Beispiele im Internet benutzen als Connectionstring "Provider = Microsoft.Jet.OLEDB.4.0;..." 

wie auch  Hey, Scripting Guy! Can I Query a Microsoft Access Database with a Windows PowerShell Script?

Beispiel 2: "Provider = Microsoft.Jet.OLEDB.4.0;..."

$DatabaseName = "c:\temp\Nordwind.mdb"
$Query = "SELECT Firma FROM Kunden"

$ConnectionString = "Provider = Microsoft.Jet.OLEDB.4.0;Data Source = $DatabaseName"

#Connection Object erstellen
$Connection = New-Object System.Data.OleDb.OleDbConnection $ConnectionString
$Command  = New-Object System.Data.OleDb.OleDbCommand $Query,$Connection
$Connection.Open()

#Daten zuerst in den Adapter laden, danach ins Dataset schreiben 
$Adapter = New-Object System.Data.OleDb.OleDbDataAdapter $Command
$Dataset = New-Object System.Data.DataSet
[void] $Adapter.Fill($DataSet)
$Connection.Close()

#Daten schreiben
$DataSet.Tables | Select-Object -Expand Rows
#Ausgabe

Ausnahme beim Aufrufen von "Open" mit 0 Argument(en):  "Der 'Microsoft.Jet.OLEDB.4.0'-Provider ist nicht auf dem lokalen Computer registriert."
Bei Zeile:9 Zeichen:17
+ $Connection.Open <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

Diese Meldungen treten wiegesagt auf, wenn ihr auf einem 64-bit Betriebssystem eine 32-bit Version von Access installiert habt.

 
2 ADOX

Mit ADO.Net lassen sich die meisten Aufgaben mit prinzipiell baugleichen Skripten für verschiedene Datenquellen (Excel, SqlServer, Access und weitere) erledigen -> Datenzugriffe über ADO.Net - Connected Classes. Allerdings gibt es für Access ein paar Ausnahmen bei der Administration von Accessdatenbanken. Zumindest habe ich für folgende Aufgaben an AccessDbs keine Lösungen gefunden.

  • Create Database
  • Create/ Alter Table

Im Netz findet man Aussagen, dass dies nicht möglich sei, oder dass selbst anerkannte Spezialisten noch keine Lösung mit ADO.Net gefunden haben 

Richard Siddaway's Blog "One thing that is obvious is that I am not checking the SQL to ensure that it is a CREATE TABLE command that is being passed in.  This is a job for another time"

Den Ausweg bietet die ADOX-Bibliothek MSDN: ADOX Fundamentals (=Microsoft® ActiveX® Data Objects Extensions for Data Definition Language and Security (ADOX)). Nach dieser MSDN-Seite ist ADOX eine Erweiterung der ADO-Bibiliothek (nicht ADO.Net) und beinhaltet Funktionen zur Administration des Schemas (=Tabellen, Abfragen, Makros) einer Datenbank, sowie zur Verwaltung von Sicherheitsfunktionen.

Beispiel 1: Anlegen einer (leeren) Tabelle und anschließendes Auslesen aller Tabellen der Nordwind.mdb

Set-StrictMode -Version "2.0"
Remove-Variable * force
Clear-Host

#$DatabaseName = "C:\Temp\Nordwind.accdb"
$DatabaseName = "C:\Temp\Nordwind.mdb"
$Provider="Provider=Microsoft.ACE.OLEDB.12.0"

#Zusammenbau des ConnectionStrings
$DataSource="Data Source=$DataBaseName"
$ConnectionString = "$Provider;$DataSource;"

#ConnectionObject erstellen und Öffnen
$Conn = New-Object -ComObject 'ADODB.Connection'
$Conn.ConnectionString = "$Provider;$DataSource;"
$Conn.Open($null,$null,$null,0)

#CatalogObject erstellen und öffnen
$Catalog = New-Object -ComObject 'ADOX.Catalog'
$Catalog.ActiveConnection = $Conn

#TabellenObject erstellen und benennen
$Table = New-Object -ComObject 'ADOX.Table'
$Table.Name = "Neue Tabelle"

#Tabelle an Datenbank (=Catalog) anfügen
$Catalog.Tables.Append($Table)

#Ausgabe aller Tabellen
$Catalog.Tables | Sort Type,Name | Format-Table Name,Type -AutoSize

#Schließen der Verbindung
$Conn.Close()

#getestet mit Office2010 und Win7 64bit/64bit

#Ausgabe gekürzt

Name                            Type        
----                            ----        
MSysAccessObjects               ACCESS TABLE
MSysAccessXML                   ACCESS TABLE
MSysCmdbars                     ACCESS TABLE
MSysIMEXColumns                 ACCESS TABLE
MSysIMEXSpecs                   ACCESS TABLE
MSysNameMap                     ACCESS TABLE
MSysNavPaneGroupCategories      ACCESS TABLE
MSysNavPaneGroups               ACCESS TABLE
MSysNavPaneGroupToObjects       ACCESS TABLE
MSysNavPaneObjectIDs            ACCESS TABLE
MSysACEs                        SYSTEM TABLE
MSysObjects                     SYSTEM TABLE
MSysQueries                     SYSTEM TABLE
MSysRelationships               SYSTEM TABLE
Artikel                         TABLE       
Bestelldetails                  TABLE       
Bestellungen                    TABLE       
Kategorien                      TABLE       
Kunden                          TABLE       
Lieferanten                     TABLE       
Neue Tabelle                    TABLE       
Personal                        TABLE       
Versandfirmen                   TABLE       
Alphabetische Artikelliste      VIEW        
Artikel nach Kategorie          VIEW        
Artikel über Durchschnittspreis VIEW        
Bestelldetails erweitert        VIEW        
Bestellungen Abfrage            VIEW        
Bestellzwischensummen           VIEW        
Die zehn teuersten Artikel      VIEW        
Liste der aktuellen Artikel     VIEW        
Quartalsbestellungen            VIEW        
Rechnungen                      VIEW        
Umsätze nach Artikeln für 1997  VIEW        
Umsätze nach Kategorie          VIEW        
Umsätze nach Kategorie für 1997 VIEW

Es gibt in Access offenbar mehrere Typen von Tabellen

  • AccessTable
  • SystemTable
  • Table
  • View

Access- und System Table sind offenbar interne Systemtabellen von Access. er Typ Table gehört zu den auch in der GUI verwaltbaren Tabellen und der Typ View entspricht dort einer Abfrage/ Query.

Beispiel 2: DesignAnalyse einer bestimmten Tabelle in einer Accessdatenbank

Bei einer Datenbanktabelle ist neben den Daten vor allem das Design einer Tabelle entscheidend. Im DesignView von Access werden die Spalten definiert (Datentyp, Länge). 

Per Skript kann man sich diese Informationen natürlich ebenso beschaffen

Set-StrictMode -Version "2.0"
Remove-Variable * force
Clear-Host

#$DatabaseName = "C:\Temp\Nordwind.accdb"
$DatabaseName = "C:\Temp\Nordwind.mdb"
$Provider = "Provider=Microsoft.ACE.OLEDB.12.0"
$TableName = "Artikel"

#Zusammenbau des ConnectionStrings
$DataSource="Data Source=$DataBaseName"
$ConnectionString = "$Provider;$DataSource;"

#ConnectionObject erstellen und Öffnen
$Conn = New-Object -ComObject 'ADODB.Connection'
$Conn.ConnectionString = "$Provider;$DataSource;"
$Conn.Open($null,$null,$null,0)

#CatalogObject erstellen und öffnen
$Catalog = New-Object -ComObject 'ADOX.Catalog'
$Catalog.ActiveConnection = $Conn

#bestimmte Tabelle auswählen und analysieren
$ArtikelTable = $Catalog.Tables | Where {$_.Name -eq $TableName}
$ArtikelTable.Columns | Format-Table  Name, DefinedSize, Type –AutoSize
#$ArtikelTable.Columns | Format-Table  * –AutoSize

#Schließen der Verbindung
$Conn.Close()

#getestet mit Office2010 und Win7 64bit/64bit
#Ausgabe

Name               DefinedSize Type
----               ----------- ----
Artikelname                 40  202
Artikel-Nr                   0    3
Auslaufartikel               2   11
BestellteEinheiten           0    2
Einzelpreis                  0    6
Kategorie-Nr                 0    3
Lagerbestand                 0    2
Lieferanten-Nr               0    3
Liefereinheit               25  202
Mindestbestand               0    2

Die Spalte "Artikelname" besitzt den Type 202, was dem DataType "Text" entspricht. Die FieldSize (=DefinedSize) ist mit 40 festgelegt.

Alle möglichen Typewerte findet ihr selbstverständlich in der MSDN: ADO API Reference -> DataTypeEnum

Auszug aus der genannten MSDN-Tabelle:

adSmallInt 2 Indicates a two-byte signed integer (DBTYPE_I2).
adInteger 3 Indicates a four-byte signed integer (DBTYPE_I4).
adCurrency 6 Indicates a currency value (DBTYPE_CY). Currency is a fixed-point number with four digits to the right of the decimal point. It is stored in an eight-byte signed integer scaled by 10,000.
adBoolean 11 Indicates a Boolean value (DBTYPE_BOOL).
adVarWChar 202 Indicates a null-terminated Unicode character string.

 

Beispiel 3: Erstellen einer Tabelle mit zwei Spalten

Set-StrictMode -Version "2.0"
Remove-Variable * force
Clear-Host

#$DatabaseName = "C:\Temp\Nordwind.accdb"
$DatabaseName = "C:\Temp\Nordwind.mdb"
$Provider="Provider=Microsoft.ACE.OLEDB.12.0"

$TableName = "Neue Tabelle"
 
#Zusammenbau des ConnectionStrings
$DataSource="Data Source=$DataBaseName"
$ConnectionString = "$Provider;$DataSource;"

#ConnectionObject erstellen und öffnen
$Conn = New-Object -ComObject 'ADODB.Connection'
$Conn.ConnectionString = "$Provider;$DataSource;"
$Conn.Open($null,$null,$null,0)

#CatalogObject erstellen und öffnen
$Catalog = New-Object -ComObject 'ADOX.Catalog'
$Catalog.ActiveConnection = $Conn

#TabellenObject erstellen, designen und benennen
$Table = New-Object -ComObject 'ADOX.Table'
$Table.Columns.Append("Marke",202,42)
$Table.Columns.Append("Wert",6,4)
$Table.Name = $TableName

#Tabelle an Datenbank (=Catalog) anfügen
$Catalog.Tables.Append($Table)

#Ausgabe aller DesignInfos
$Table.Columns | Format-List  *

#Schließen der Verbindung
$Conn.Close()

#getestet mit Office2010 und Win7 64bit/64bit

#Ausgabe

Name          : Marke
Attributes    : 0
DefinedSize   : 42
NumericScale  : 0
Precision     : 0
RelatedColumn :
SortOrder     :
Type          : 202
Properties    : System.__ComObject
ParentCatalog :

Name          : Wert
Attributes    : 0
DefinedSize   : 4
NumericScale  : 0
Precision     : 0
RelatedColumn :
SortOrder     :
Type          : 6
Properties    : System.__ComObject
ParentCatalog :

Dieses Skript legt eine neue Tabelle in der AccessDatenbank "nordwind.mdb" an und fügt dieser Tabelle zwei Datenfelder hinzu. Die Definition der Typen findet ihr in dem Link aus Beispiel 2.

Um Daten in die Tabellen einzutragen oder daraus auszulesen, seht euch das Kapitel Datenzugriffe über ADO.Net - ADO.Net an

 
3 Hilfreiche Links