Hey, Scripting Guy!

Scripting Guys が皆さんの質問にお答えします

Hey, Scripting Guy!

TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。

詳細情報

Hey, Scripting Guy! カテゴリ別アーカイブ

Hey, Scripting Guy! 日付別アーカイブ

Hey, Scripting Guy! ダウンロード

Spacer

*

Windows PowerShell を使用してデータベースにレコードを追加する方法はありますか

Hey, Scripting Guy! Question

Scripting Guy さん、よろしくお願いします。しばらく前のコラムで、Windows PowerShell を使用して Microsoft Access データベースからデータを取得する方法が紹介されていました。現在、PowerShell を使用してデータベースにデータを追加しようとしていますが、スクリプトがうまく機能しません。Windows PowerShell を使用してデータベースにレコードを追加する方法を教えていただけますか。

-- AB

SpacerHey, Scripting Guy! AnswerScript Center

AB さん、こんにちは。まず最初に、先週の金曜日 (1 月 11 日) に Joel Thoreson さんからいただいた素敵なメッセージを皆さんにご紹介したいと思います。

"Scripting Guy の皆さんにとって、この 1 月 11 日がすばらしい Scripting Guy の日になることを心から祈っています。"

Joel さん、ありがとうございます。言うまでもありませんが、1 月 11 日が Scripting Guys の日であることを覚えていてくれる方がいたことに心から感謝しています。Scripting Guys の母親たちでさえ、Scripting Guys の日にお祝いの電話をくれなかったのですから。傷ついたか、ですって。当然です。今でもまだ傷ついています。

皆さんの中には、「何の話をしているんだろう。Scripting Guys の日だって。まさか、そんなわけないよ。Scripting Guys の日は 1 月 11 日ではないだろう」と考ている方がいらっしゃることはわかっています。でも実は、1 月 11 日は Scripting Guys の日です。2005 年 12 月 20 日のコラムに記載されている注釈を見てください。

興味深い歴史上の事実 : 米国の祖父母の日は毎年、労働記念日の後の最初の日曜日です。この祝日は、40 人の孫を持つある夫婦によって始められました。Scripting Guys は、祖父母の日というアイデアを全面的に支持しています。なんといっても、この祝日は彼らのためのようなものです。それにしても、祖父母の日によって、毎年 40 個の追加のギフトを受け取ることになる夫婦がこの日を提唱したということは興味深いことです。

ところで、1 月 11 日が Scripting Guys の日であるということは申し上げましたでしょうか。

Hey, Scripting Guy! のコラムに記載されているなら、事実に違いありません。一件落着です。

改めて、Joel さん、ありがとうございました。あなたにとっても Scripting Guys の日がすばらしい 1 日になりますように。他の皆さんは、後ろめたさを感じないでくださいね。何しろ、お気に入りの Scripting Guy にプレゼント送る時間はまだ十分あるのですから。プレゼントは次の住所にお送りください。

The Scripting Guy Who Writes That Column
Microsoft Corporation
One Microsoft Way
Building 42/4039
Redmond, WA 99352

遅くても何もしないよりはまし、ということわざがあることをお忘れなく。

: 何ですって。このコラムを執筆している Scripting Guy のほかに Scripting Guys はいないのか、ですって。もちろんいます。"お気に入りの" Scripting Guy にプレゼント送る時間はまだ十分ある、と言いましたよね。こう言うと、他のすべての Scripting Guys はほとんど除外されることになりますが。

お祝いの気持ちを込めて、Scripting Guys の日のパーティの合間を縫って、Windows PowerShell を使用して Access データベースに新しいレコードを追加する方法 (つまり、ADO [ActiveX Data Objects] を使用する他のデータベースにレコードを追加できる方法) を紹介することにしました。ADO を使用する VBScript スクリプトを入手して、同じタスクを実行する Windows PowerShell スクリプトに変換しようした方は大勢いらっしゃることでしょう。これは実現可能です。これから、その作業を行います。ただし、注意が必要なポイントがいくつかあります。

実際に、それらのポイントについて説明します。

1 月 11 日が Scripting Guys の日であることを忘れていた人にも説明しますよ。

スクリプトは次のとおりです。

$adOpenStatic = 3 
$adLockOptimistic = 3 
 
$objConnection = New-Object -com "ADODB.Connection" 
$objRecordSet = New-Object -com "ADODB.Recordset" 
 
$objConnection.Open("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = C:\Scripts\Test.mdb") 
 
$objRecordset.Open("Select * From Computers", $objConnection,$adOpenStatic,$adLockOptimistic) 
 
$objRecordSet.AddNew() 
$objRecordSet.Fields.Item("ComputerName").Value = "atl-ws-001" 
$objRecordSet.Fields.Item("SerialNumber").Value = "192ATG43R" 
$objRecordSet.Update() 
 
$objRecordSet.Close() 
$objConnection.Close()

このスクリプトのしくみはどうなっているのか、ですって。では、コードを見てみましょう。まず、次のように、$adOpenStatic と $adLockOptimistic という 2 つの変数に値を代入します。

$adOpenStatic = 3 
$adLockOptimistic = 3

今日のコラムでは、これらの変数の詳細は説明しません。これらの変数は、データベース テーブルを開いたときに、カーソルの種類と、使用されるレコード ロックの種類を特定するのに役立つとお伝えしておけば十分でしょう (もう少し情報が必要な場合は、Scripting Guys Webcast の「Database Scripting For System Administrators」(英語) を参照してください)。この 2 つの変数を初期化したら、次のように、ADODB.Connection オブジェクトと ADODB.Recordset オブジェクトのインスタンスを作成します。

$objConnection = New-Object -com "ADODB.Connection" 
$objRecordSet = New-Object -com "ADODB.Recordset"

ご参考までに、Connection オブジェクトは、実際のデータベース ファイル (この場合は、C:\Scripts\Test.mdb) への接続を管理するのに使用します。接続を確立したら、Recordset オブジェクトを使用して、データベース内の指定されたレコードセットを操作できます。今日のスクリプトの場合は、Computers という名前のテーブル内にあるすべてのレコードを操作します。

これらの 2 つのオブジェクトを作成したら、次のコード行を使用して Test.mdb に接続できます。

$objConnection.Open("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = C:\Scripts\Test.mdb")

このコードについて少し説明する必要がありますね。Test.mdb が Access 2003 (または Access XP) データベースである場合、上記のコマンドを実行すると Test.mdb に接続されます。Test.mdb が Access 2007 データベースの場合、このコマンドはあまり役立ちません。というのも、Access 2007 では、使用される Provider 文字列とファイル拡張子が異なるからです。Access 2007 データベースを使用して作業している場合は、代わりに次のコード行を使用します。

$objConnection.Open("Provider = Microsoft.ACE.OLEDB.12.0; Data Source = C:\Scripts\Test.accdb")

なぜ Provider 文字列とファイル拡張子が変更されたかはわかりません。どういうわけか、Office チームは、このような大幅な変更を加える際に、Scripting Guys に意見を求めたことは今まで一度もありません。

不思議なことです。

: お気付きかもしれませんが、Open メソッドに渡すすべての情報をかっこで囲みました。これは、皆さんが VBScript スクリプトを Windows PowerShell に変換しようとするときに混乱する箇所です。Windows PowerShell では、すべてのメソッド (Open メソッドを含む) の後に 1 組のかっこを続けて指定する必要があり、そのかっこでメソッドのすべてのパラメータを囲む必要があります。VBScript では、Provider 情報をかっこで囲むとスクリプトでエラーが発生しますが、Windows PowerShell では、Provider 情報をかっこで囲まないとスクリプトでエラーが発生します。

不思議なことです。

データベースに接続したら、次のコード行を使用して、Computers テーブル内にあるすべてのデータで構成されるレコードセットを返します。

$objRecordset.Open("Select * From Computers", $objConnection,$adOpenStatic,$adLockOptimistic)

信じられないかもしれませんが、これでデータベースにレコードを追加する準備ができました。これを行うのが次のコード ブロックです。

$objRecordSet.AddNew() 
$objRecordSet.Fields.Item("ComputerName").Value = "atl-ws-001" 
$objRecordSet.Fields.Item("SerialNumber").Value = "192ATG43R" 
$objRecordSet.Update()

上記のコードではどのような処理が行われているのか、ですって。まず、AddNew メソッドを使用して新しい空のレコードを作成します (ここでも、メソッド名の後にかっこが必要なことに注意してください)。では、次の行に移りましょう。

$objRecordSet.Fields.Item("ComputerName").Value = "atl-ws-001"

AB さん、最も問題となっていたのはこの行でしょう。このコード行では、ComputerName フィールドに値 (atl-ws-001) を代入しています。VBScript スクリプトを移植しているのでなければ、このコード行は特に厄介ではありません。というのも、VBScript では、この同じコード行が次のようになるからです。

objRecordSet("ComputerName") = "atl-ws-001"

VBScript では、必要な作業は、オブジェクト参照 (objRecordset) の後に、フィールド名 (ComputerName) を含む 1 組のかっこを続けて指定するだけです。でも、いいですか、これは VBScript の場合です。Windows PowerShell では、このような簡略化されたコマンドは機能しません。同じようなコマンドを使用すると、次のようなエラー メッセージが表示されるだけです。

式またはステートメントのトークン '(' を使用できません。 
使用場所 C:\scripts\test.ps1:11 文字:15 
+ $objRecordSet(" <<<< ComputerName") = "atl-ws-001"

正直なところ、この問題が発生するはっきりとした理由はわかりません。私たちが知っているのは、VBScript では、何も指定しないと、どのオブジェクトの場合も既定のプロパティが自動的に指定されるということです。しかし、(Windows PowerShell を含む) 他のほとんどの言語では、オブジェクトの既定のプロパティや他のプロパティなど、使用するプロパティを明示的に指定する必要があります。Fields.Item.(フィールド名).Value は、今回のレコードセットの既定のプロパティであると推測されます。そう考えると、PowerShell では完全なプロパティ名を指定する必要がありますが、VBScript ではフィールド名だけを指定する必要がある理由を理解できると思います。

もちろん、先ほど述べたとおり、これは推測にすぎないので、完全に見当違いだという可能性は十分にあります。でも、別にかまいません。何しろ、ここで問題なのは、完全なプロパティ名を指定しなければならない理由ではないからです。重要なのは、ここで説明している方法に従って作業することだけです。では、SerialNumber フィールドに値を代入するにはどのようにすればよいでしょうか。そうです、そのとおりです。

$objRecordSet.Fields.Item("SerialNumber").Value = "192ATG43R"

もちろん、この後は引き続き、Computers テーブルに含まれているのと同じ数のフィールドにプロパティを代入できます。プロパティの代入が完了したら、Update メソッドを呼び出して、実際にデータベースに新しいレコードを書き込みます。

$objRecordSet.Update()

後は、Connection オブジェクトと Recordset オブジェクトを閉じて、Scripting Guys の日を祝うパーティに戻るだけです。

AB さん、これでうまくいくはずです。このスクリプトがお役に立てばと思います。そして、残された Scripting Guys の日の休暇シーズンをお楽しみください。さて、Joel さん以外の皆さんが今年の Scripting Guys の日を忘れていたことに腹を立てたり、落胆したりはしていないこともお知らせしておきます。たいしたことではありませんし、恨んでもいません。

: わかりました。それはうそです。やはり、非常に恨んでいます。でも、本当のことを言ったら、編集者にその部分をカットされるだけだと思ったので、何もかもすばらしいようなふりをした方が良さそうだと判断しました。たとえ、うそでもです。

しかし、公平に見て、Scripting Guys の日が 1 年の中で良くない時期に定められていることは認めざるを得ません。何しろ、クリスマス休暇のような長期休暇の直後に、Scripting Guys の日のような重要な休暇を取るのは難しいですから。さらに、1 月 11 日はシンガーソングライターのメアリー J. ブライジ、以前メジャーリーグでショートを守っていたレイ オルドネス、そしてカナダのジャン クレティエン元首相の誕生日でもあることを考えると、皆さんが混乱するのも無理はありません。いい考えがあります。(少し遅いですが) 今すぐプレゼントを送っていただければ、2009 年の Scripting Guys の日を別の日に制定することを検討してみます。


ページのトップへページのトップへ