PowerShellからMS Accessへの接続は何種類も方法がある
タイトルのとおりなのですが、先日のADOXの件以来、納得がいかなくて調べてました。
ADOXの件は結論からすると直接使用ではなくてCOMを.Netのラッパー経由で呼び出すようになるようです。よく考えたらRCWというやつをtlbimp.exeなどで作らないとダメでした。 ということは、ADOXはdllというかCOMの登録が正常であれば結局はCOMとして呼び出すか.NetでもRCW経由で呼び出す必要があるので興味を失ってしまいました。
また、tlbimp.exeはVisualStudioインストール時に導入されるのでダウンロードする時間を待てませんでした。 そのうちやります。
今回はせっかくAccessランタイムを導入したのでテーブルを作ってデータを追加したり参照したりしてみます。
COM経由でADODB.Connectionを使う
2015年にもなって、VBAやVBS以外からこれを使うとは思ってもみませんでしたが、使うことができます。
$db = Join-Path (pwd).Path "test.accdb" try { $con = New-Object -ComObject "ADODB.Connection" $con.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$db;") ## SQLでデータ登録する $con.Execute("create table PSUser (id number not null, name text not null)") $con.Execute("insert into PSUser values (1, 'm0t0k1')") | Out-Null $con.Execute("insert into PSUser values (2, 'm0t0k1x2')") | Out-Null $con.Execute("insert into PSUser values (3, 'm0t0k1w')") | Out-Null ## 削除するときにつかう ## $con.Execute("delete from PSUser") | Out-Null ## データを参照する $rs = New-Object -ComObject "ADODB.Recordset" $rs.Open("select * from PSUser", $con, 3, 3) if($rs.EOF -eq $false){ $rs.MoveFirst() while($rs.EOF -ne $true){ Write-Host ("データ -> {0}`t{1}" -f $rs.Fields.Item("id").Value, $rs.Fields.Item("name").Value) $rs.MoveNext() } } else { "データが1件もありません。" } $rs.Close() $con.Close() } catch { $Error } finally { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($rs) | Out-Null [System.Runtime.InteropServices.Marshal]::ReleaseComObject($con) | Out-Null }
たぶん、サラリーマン時代はこれを使っていたような気がします。もう忘れてしまいましたが。 すでにPowerShellには名前空間で読み込まれているので、特にきにすることなくNew-Objectすることができます。 なお、更新系のSQLはExecuteNonQueryメソッドを使いましょう。また、今回はトランザクションをまったく考慮していませんが、MS Accessでも一括で更新するときはトランザクションを使ったほうが処理速度が早いので使ったほうがいいでしょう。
$db = Join-Path (pwd).Path "test.accdb" try{ $db = New-Object System.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=$db;") $cmd = New-Object System.Data.OleDb.OleDbCommand("select * from PSUser", $db) $db.Open() $reader = $cmd.ExecuteReader() while($reader.Read()){ Write-Host ("{0}`t{1}" -f $reader[0], $reader[1]) } }catch{ $Error }finally{ $reader.Close() }
COMを使わないので、あまりオブジェクトの解放に気をつかっていません。PowerShellでもusingって使えたりするのかな…
こちらもほぼOleDBと同じです。使い方もほぼ同じです。 唯一違うのが、接続文字列がプロバイダではなくドライバーになっているところですかね。
$db = Join-Path (pwd).Path "test.accdb" try{ $db = New-Object System.Data.Odbc.OdbcConnection("Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=$db;") $cmd = New-Object System.Data.Odbc.OdbcCommand("select * from PSUser", $db) $db.Open() $reader = $cmd.ExecuteReader() while($reader.Read()){ Write-Host ("{0}`t{1}" -f $reader[0], $reader[1]) } }catch{ $Error }finally{ $reader.Close() }
PowerShellでは.Netなので無理にCOMを使う必要はありません。Excelなどの操作でどうしても、とかあるいは過去に使っていたので、などがあるかもしれませんのでそういうときに限定したほうがいいかもしれません。面倒ですからね。
先日投稿したアンマネージドdllについても、どうしてもということがなければ.Netを使ったほうが精神衛生上、いいかもしれません。
はじめよう Windows PowerShell
著者:柏原 基規
価格:500円
楽天ブックスで詳細を見る