USBドライバをインストールせよ!

UBSのドライバなんぞ、簡単にインストールできんじゃんよ!と思われることでしょう。

しかし、とある顧客の設置展開にて問題が発生する・・・
そして、その白刃の矢がワシ(多少暇&元々MS製品の技術部門にいたため?)のほうへ・・・・・・

まず、最初に断っておきますが、本内容にて至った解決方法は正しいとは限りません。かなり、無理やりに実現しています。また、他にいい方法もあると思います。もっといい方法があれば、ぜひお教え願います。

[ミッション]


あるUSBのデバイスを全国に展開するということで、通常であればそんなものデバイスを接続してもらってドライバをインストールすれば済む話ではあるが。。。しかし、今回のデバイスのドライバはMicrosoftによる署名がないため、Administrator権限にてインストールする必要がある。追い討ちをかけるように、全国に散らばる端末を利用するユーザにはローカルのAdministrator権限がないため、ドライバのインストールができない。ユーザにAdministratorのパスワードは教えたくない(まぁ、当然)。
尚、顧客環境はWindowsのActiveDirectory(以下、AD)で管理されており、ファイルを配布しインストールさせる仕掛けも存在する。


[調査開始]


確かに、ADで管理していない通常のWindows XPにシステム管理者でなく、制限ユーザでログインしてドライバをインストールしようとすると以下のメッセージと共に認証ダイアログが表示される。

「このハードウェアをインストールするには、このコンピュータの Administrators グループのメンバである必要があります。」

どうしたらよいのか?

まずは、ドライバがインストールされている状態、つまりはプレインストール状態であればUSBのデバイスを接続すれば、問題なくいくのでないか?ということで、じゃぁどうやってインストールすんじゃい?という話である。このデバイスのドライバにはインストーラーは付属してなく、「*.inf」および「*.sys」ファイルが存在するのみである。

まず、詳しい先輩にお伺いを立てたところ。ドライバを予めインストールするには「Platform SDKのSetup APIのSetupCopyOEMInfなるメソッドを使えばいいらしい」という回答を得た。正直、この辺りはてんで弱いので・・・どうしていいかよくわからんヽ(;´Д`)ノ

途方に暮れていたところに見つけたドキュメントが以下のもの。

このドキュメントに「The Driver Package Installer (DPInst)」なるものが記載されていた。これはなんじゃい?ということで、色々とググってみた。

まず、「DPInst」を使用するには下記のサイトよりWindows Driver Kit(WDK)をダウンロードしてインストールしてください。

尚、ダウンロードするにはMSDN サブスクリプション ダウンロード経由か、Microsoft Connect Webにユーザ登録することでダウンロード可能です。

んでもって、その他、情報色々。

[DPInstによるドライバのインストール]


この「DPInst」を使えばドライバをインストールすることができることがわかった(正確には後に違うことが判明するが・・・)。尚、今回のドライバにはデジタル署名がなされていないため、「/LM」オプションを使用して実行する必要がある。インストールが完了すると「C:WINDOWSsystem32DRVSTORE」以下にインストールしたドライバのフォルダが作成され、INFやSYSファイルがコピーされる。

これでいけたんじゃねーの!?!
ってことで、この状態にて制限ユーザでログインし、デバイスを接続!!

しかーし、やはり認証ダイアログが出る・・・。
ちなみに、Administrator権限のあるユーザでデバイスを接続すると「新しいハードウェアの検出ウィザード」が表示される。そのまま進むと通常はドライバの「*.inf」ファイルを指定しなくてはいけないが、「ソフトウェアを自動的にインストールする」を選択して「次へ」をクリックすることで、ドライバはインストールされます。しかし、この後によく見る以下の文言のダイアログが表示されることになる。

このハードウェア「○△□」を使用するためにインストールしようとしているソフトウェアは、Windows XPの互換性を検証する Windows ロゴ テストに合格していません。

インストールを続行した場合、システムの動作が損なわれたり、システムが不安定になるなど、重大な障害を引き起こす要因となる可能性があります。今すぐインストールを中断し、Windows ロゴ テストに合格したソフトウェアが入手可能かどうか、ハードウェア ベンダーに確認されることを、Microsoft は強く勧めます。

通常はココで「続行」ボタンをクリックするんだろうが・・・
さらにググること暫く。。。以下の情報を発見。

Dpinst – Virtual COM

ん?署名されてないとダメって書いてある (゚Д゚;)ウソ?
つーかよー、そもそも署名しろよなーっと憤慨。

もう、無理なのか?でも、まだ抵抗してみる。
署名されていなくてもインストールさせるような設定があったような?ADだし、Group Policyで設定を反映することは容易に可能なはず。ということで、さらに調査。

ドライバの署名に関する動作の変更は以下の手順で出来る。

  1. 「コントロール パネル」を開いて、「システム」をダブル・クリックします。
    ※上記のアイコンがない場合は、「パフォーマンスとメンテナンス」をクリックし、「システム」をクリックします。
  2. 「ハードウェア」タブをクリックして、「ドライバの署名」ボタンをクリックします。「ドライバ署名オプション」ダイアログ・ボックスが表示されます。
  3. 「ドライバ署名オプション」の設定が「無視」になっているか確認します。
    「無視」であれば「OK」ボタンをクリックし、そうでなければ現在の設定をメモした後、「無視」に変更して「OK」ボタンをクリックします。

尚、Group Policy(ファイル名を指定して実行で「gpedit.msc」でグループ ポリシー エディタは起動できる)では[コンピュータの構成]-[Windows の設定]-[セキュリティの設定]-[ローカル ポリシー]-[セキュリティ オプション]-[デバイス: 署名されていないドライバの新ストール時の動作]が該当すると思われる。

この状態でいざ!!

しかーーーし、やはりダメ。。。
色々調べてわかったのだが、上記の設定でもWindows ロゴ テストうんたらのダイアログは非表示にすることは出来ない。また、Windows VistaとWindows Server 2008の64ビット版だと、Microsoftの署名ではなく商用のCAを代用することができるらしい。つーか、何度も言うが、ちゃんとテストをパスして署名してもらっとけということだ。

問題を切り分けるために、試しにDPInstのオプションで「/Q:サイレントインストール」と「/C:デバッグログ出力」をつけて実行してみた(DPInst.exe /LM /Q /C)。すると・・・以下のエラーコードが返ってきているではないですか!(゚Д゚;)

INFO: RETURN: DriverPackagePreinstallW (0xE000022F)

この「0xE000022F」でググると。

どうも、DPInstの仕様で署名のないドライバの場合、「/LM」オプションと一緒にサイレントインストールのオプションである「/Q」を一緒に使用してインストールすることはできないらしいことが判明。

うーむ、サイレントインストールできないのは困った。

では、DIFxAPPとかいうのを利用してVisualStudioでインストーラを作成する方向で検討を開始!!
しかし、どうやって作っていいものか?さっぱりわからんわけです。
作成するためにはどうも「DIFxApp.msm」および「Ocra」なるツールが必要であるということは分かった。

とにかく、ググりまくること数時間・・・
以下のリンクを見ながらようやくインストーラー完成!!

Driver Install FrameworkのDIFxApp.msmのマージモジュールを使用してインストーラーを作成する手順をいかにまとめておく。
(これでほんとに正しいかは不明だが、しっかりと「C:WindowsSystem32DRVSTORE」にドライバがインストールされたので問題ないと思われる)
尚、VisualStudio 2008を使用している。

余談だけど、Interfaceという雑誌の1月号にこの手順についてはまとまっています。これを調べているときは土曜日で会社の図書室が閉まっていたので、自力で調べた。。。

[DIFxAPPによるドライバインストーラー作成手順]


  1. VisualStudioを起動し、「新しいプロジェクト」ダイアログで[その他のプロジェクトの種類]-[セットアップと配置]の「セットアップ プロジェクト」を選択し、「OK」をクリック。
    DIFxAPP_02
  2. プロジェクトを右クリックし、[追加]-[マージ モジュール]をクリック。「モジュールの追加」ダイアログで「\B3C8260ED36F41Cc$WINDDK6001.18002redistDIFxDIFxAppMultiLinMergeModx86DIFxApp.msm」を指定し、「開く」をクリック。
    DIFxAPP_03
  3. 後は、プロジェクトを右クリックし、[追加]-[ファイル]をクリックし、必要な「*.inf、*.sys」等を追加。
  4. ビルド。
  5. ビルドされた「*.msi」ファイルをOrcaで開く。
    DIFxAPP_04
  6. 「DIFxApp」モジュールを追加すると、Orca上のTablesペインに「MsiDriverPackages」が追加されているので、メニューの[Tables]-[Add Row]でレコード追加する。
    DIFxAPP_05
  7. 続いて、「Add Row」ダイアログで然るべき値を入れるんだが。ここで何を入れて良いのかわからなくて、ハマッタ(マニュアルはちゃんと読みましょう♪)。ずっと、「*.inf」のファイル名を入れていたんですけど・・・当然ながらダメ。じゃ、何?ということなんだけど、Tablesペインの「Component」のレコードの「Component」の値を入れてあげないといけなかった(これは、雑誌Interfaceで公開されていたサンプルを見てわかった)。。残りのFlagsには今回はレガシーモードでインストールするので「16」、Sequenceにはとりあえず「0」を入力。FlagsについてはMsiDriverPackages Custom Table Schemaを確認してください。
    DIFxAPP_06

以上でインストーラは完成!実行する際にMSIのオプションである「/quiet」を付与することで、デジタル署名がないドライバでもサイレントモードでインストールすることができた。

まだまだ根本的にわかっていないワシは「これで出来ただろう」と思い、再度デバイスを接続。
しかし・・・DPInstでインストールした場合と何も変わらない。

そして、根本的な問題に気がつく。。。

DPInstやDIFxAppを使用したインストールはストア(文字通り「DRVSTORE」だったのだが)にコピーされるだけで、実際にはインストールされていないということに。。。(゚Д゚;)要は、「Driver Install Frameworks Library (DIFxLIB、昔はDIFxAPIという名前だったとか?)」を利用してインストーラを作成しないといけないらしい。ほんと、何も知らないって大変です(ココに書いてることも何が正しいのかわかったもんじゃない)。

[DIFxAPIによるドライバインストーラー]


そこでDIFxAPIを使用したWindows Dirver Kitに含まれる「DIFxCmd」なるサンプルをとりあえず動かしてみることに。尚、サンプルはWDKのインストール先の「C:WINDDK6001.18002srcsetupDIFxAPIDIFxCmd」に入っています(バージョンにより差異はあるかもしれませんが)。
実行時のコマンドは「DIFxCmd.exe /i wceusbsh.inf 16」です。すると、、「0xE000020B」がリターンコードで返ってきた。。。エラーには下記の記述がある。

Installation did not occur because the hardware isn’t currently present.
LOG Event: 1, No drivers installed. No devices found that match driver(s) contained in ‘C:WINDOWSsystem32DRVSTOREwceusbsh_4CB9273877DE2C6BC6A117EF
B10503885C346732wceusbsh.inf’.

デバイスが接続されていないからインストールできませんでしたと。試しに接続した状態でコマンドを実行してみると・・・やはり、WHQLの警告ダイアログが表示される。。デバイスを接続しなくてもインストールを実行したいところだが、その方法がわからんので前提として「デバイスが接続されていること」として話を進めます。

「DIFxCmd」では「DIFxAPI」で提供される「DriverPackageInstall」メソッドにてドライバ パッケージのインストールを実行していることがわかる。

やっとのことで、インストールまではうまくいったのだが、やはりデバイスを接続すると認証ダイアログが表示されてしまう。「ドライバの署名」の設定は変更しているはずなのに。。。効いてない?あまり関係ないが、ドライバへのデジタル署名については他のメーカもしてないことは判明。

先にも書いたが、WHQLの警告ダイアログを非表示にすることはWindows XPでは出来ないらしい。じゃぁ、この設定は何?ということについては、現状不明です。

[そもそも論]


ここで一旦整理しようと思います。WHQLのドライバ署名がなされていれば、ローカルのAdministrator権限を持っていなくてもデバイスのインストールは可能です。しかし、今回のドライバにはWHQLによりドライバ署名がなされていません。

つまり、ドライバ署名がなされていればDPInstやDIFxAPPを使用して予めインストールしておけば、デバイスを接続した時点でインストールが自動的に行われるし、DIFxAPIを使用すれば事前にインストールすることもできる。

[最後の壁]


とりあえず、デバイスが接続状態にあること、WHQLのダイアログが表示されてしまうという制限があるが、DIFxAPIを使用したDIFxCmdにてドライバをインストールできるところまでは辿りついた。。。

しかしである。

このインストーラーを実行できるのは配布ツールかエンドユーザです。配布するといっても、警告ダイアログが表示されてしまうためアウト。だとすると、エンドユーザが実行することになります。しかし、ミッションにもあるようにエンドユーザにはローカルのAdministrator権限がありません。

つまり、インストーラーを起動するのはエンドユーザだが、インストーラー自体がAdministrator権限で動作させることができれば問題は解決する。

そこで、色々と先輩に教えて頂きWin32 APIのCreateProcessWithLogonWを使って解決することに(いやもーここまでくると無理くりです・・・)。

↓以下が、Administratorでインストーラーを起動するだけのプログラム。

#define _WIN32_WINNT 0x0500

#include <windows.h>
#include <winbase.h>
#include <atlbase.h>

void main(void)
{
STARTUPINFOW sInfo;
PROCESS_INFORMATION pInfo;
BOOL result;
memset(&sInfo, 0, sizeof(sInfo));
sInfo.cb = sizeof(sInfo);
USES_CONVERSION;

result = CreateProcessWithLogonW(A2W("ユーザ名"),
A2W("マシン名"),
A2W("パスワード"),
0,
A2W("cmd.exe"),
A2W("/C DIFxCmd.exe /i wceusbsh.inf 16"),
0,
NULL,
A2W("C:\TEMP\"), //作業フォルダ
&sInfo,
&pInfo);
}

こいつを起動することでローカルAdministratorの権限のないユーザでも署名のないドライバーをインストールすることが何とか可能になりました。

[まとめ]


Windows Driver Kitで提供されているDriver Install Frameworkを使用し、無理やりミッションをこなせそうな解決策は見出せた。けれども、もっといい方法があるんじゃないの?と思っています。何か他にいい方法があれば、追記なりしようとは思います(書いてることも参考程度でよろしくです)。

何度も書いてはいるんだけど、そもそもドライバがWindows ロゴ テストをパスしていて、インストーラーも提供されていればこんなことする必要はないのです。

USBドライバをインストールせよ!

コメントを残す