LinuxのPXEを使ってWindows PEをネットワークブート
Windows PEをPXEサーバを使ってネットワークブートしてみた。他のWindows系OSと異なり、ネットワークブートすることも念頭に置かれて作られているためか、それほど手間はかからなかった。BartPEやLinux系でネットワークブートをやったことがあれば、簡単に設定できるだろう。
まずはちょっとおさらい。Windows PEはWindows系OSを大量のPCに配布したり、Windows系OSがシステムトラブルを起こした時にメモリだけで起動し修復作業をするために開発された特殊なOSである。*1 そのためWinPEのユーザはOEMメーカは千台ものPCを管理しなければならない大手の情報システム部門がほとんどだと思うが、Windows製品の正規ユーザであれば個人でも利用できる。(「Windows PE」を参照)
WinPEの基本的な利用方法はWinPEの起動CDを作成して、そのCDからブートして使う。しかし、企業などでWindowsの保守で使う場合は、PCにCD/DVDドライブがなければならず、コストもかかり、また外部ドライブを使うにしても手間がかかる。今時のPCであればネットワークインタフェースはほぼ標準であり、今時のBIOSであればPXEによるネットブートもサポートしているので、大量のPCを保守するのであればCDブートではなく、ネットワークブートの方が便利だ。
そこで、WinPEをネットワークブートできるか確認してみた。(なお、ここではPXEサーバとしてLinuxマシンを使っているが、PXEの動作はWindowsでもLinuxでも同じなので基本的にはどちらでも構わない。PXEとTFTPについては設定済みという前提で話を進めるので、LinuxによるPXEの一般的な設定については「PXEによるディスクレス・クライアント(総集編)」を参照のこと。)
■ PXEサーバに必要なファイルをコピーする
まず必要なファイルをPXEサーバに置いておく必要がある。必要なファイルはWinPEのブートCDを作成する開発環境から持ってくる(もしくは、作成したWinPEのCDからと、WinPEを起動してその中のファイルをネットワーク経由でコピーしても可能)。「Windows PE」にあるようにAIKをインストールすると、Windows PEの環境は
C:\Program Files\Windows AIK\Tools\PETools
に置かれる。まずは、そこから次のファイル・フォルダをコピーする。(ここでは、WinPEでブートするPCのアーキテクチャがx86である前提で話を進める。もし64ビット系のPCなどでは適宜、適当なフォルダを使う。)
C:\Program Files\Windows AIK\Tools\PETools\x86\winpe.wim C:\Program Files\Windows AIK\Tools\PETools\x86\boot\
これらのフォルダをPXEサーバのTFTPのディレクトリへコピーする。TFTPサーバをWinPEのブートのためだけに使うのであればTFTPのルートの下に、直接、"boot"や"winpe.wim"を置けば設定の手間が軽減できる(ちょっとだけファイル名の変更やファイルの移動は必要だが。)しかし、TFTPをWinPEのブートだけに使うのはもったいないので私は次のようにした。まず、TFTPのルートディレクトリに"winpe"というディレクトリを作り、その下に"x86"のフォルダをコピーした。TFTP上でのディレクトリの構成は以下の通り。(なお、"boot\fonts\"の下の中国語フォント(ch*.ttf)、韓国語フォント(ko*.ttf)、またそれ以外にも通常のPXEブートには必要ないファイルやディレクトリは削除してある。以下が(日本語表示オプションを除けば)ほぼ必要最小限である。
[root@pxeserver ~]# ls -R /tftpboot/winpe/ /tftpboot/winpe/: x86 /tftpboot/winpe/x86: boot winpe.wim /tftpboot/winpe/x86/boot: bcd boot.sdi fonts /tftpboot/winpe/x86/boot/fonts: jpn_boot.ttf wgl4_boot.ttf
以上で半分以上のファイルはPXEサーバにコピーできたが、実は肝心のNBP(Network Bootstrap Program、PXEブートで一番最初にダウンロードされるブートローダ)と次に呼び出される2次ローダなどが無い。これはRAMイメージ上のWinPEのディレクトリの中に入っているので、これを取り出す必要ある。まず、Linux上で/tftpboot/winpe/x86/pxeというディレクトリを作り、次にWinPEを立ち上げてネットワーク経由などで次のファイルやフォルダをそこへ持ってくる。
X:\Windows\Boot\PXE\pxeboot.n12 X:\Windows\Boot\PXE\bootmgr.exe X:\Windows\Boot\PXE\en-US\ X:\Windows\Boot\PXE\ja-JP\
("en-US"、"ja-JP"は日本でメッセージを出すなどで使うのでなくても構わない。)
もしくは、WinPEの起動ディスク開発環境(AIK)をつかって次の方法で持ってくることも可能だ。
C:\winpe_x86>dir ドライブ C のボリューム ラベルがありません。 ボリューム シリアル番号は A190-DEB9 です C:\winpe_x86 のディレクトリ 2008/06/17 09:27. 2008/06/17 09:27 .. 2008/01/05 03:23 2,048 etfsboot.com 2008/06/17 09:27 ISO 2008/06/17 09:27 mount 2008/01/23 17:45 183,819,403 winpe.wim 2 個のファイル 183,821,451 バイト 4 個のディレクトリ 649,486,336 バイトの空き領域 C:\winpe_x86>imagex /mount winpe.wim 1 mount ImageX Tool for Windows Copyright (C) Microsoft Corp. All rights reserved. Mounting: [C:\winpe_x86\winpe.wim, 1] -> [C:\winpe_x86\mount] Successfully mounted image. C:\winpe_x86>xcopy /s mount\Windows\Boot\PXE N:\tftpboot\winpe\x86\pxe mount\Windows\Boot\PXE\abortpxe.com mount\Windows\Boot\PXE\bootmgr.exe : mount\Windows\Boot\PXE\zh-HK\bootmgr.exe.mui mount\Windows\Boot\PXE\zh-TW\bootmgr.exe.mui 33 個のファイルをコピーしました C:\winpe_x86>imagex /unmount mount ImageX Tool for Windows Copyright (C) Microsoft Corp. All rights reserved. Unmounting: [C:\winpe_x86\mount]... Successfully unmounted image. C:\winpe_x86>
(この例ではNドライブはネットワークドライブであり、Linuxマシンのディレクトリを共有している。そこへファイルをコピーしている。PXEの下をすべてコピーしているので、後で不必要なファイルは削除しておく。)
全てのファイルをコピーしたPXEサーバ上のTFTPのディレクトリは次のようになる。
[root@pxeserver ~]# ls -RF /tftpboot/winpe/ /tftpboot/winpe/: x86/ /tftpboot/winpe/x86: boot/ pxe/ winpe.wim /tftpboot/winpe/x86/boot: bcd boot.sdi fonts/ /tftpboot/winpe/x86/boot/fonts: jpn_boot.ttf wgl4_boot.ttf /tftpboot/winpe/x86/pxe: bootmgr.exe en-US/ ja-JP/ pxeboot.n12 /tftpboot/winpe/x86/pxe/en-US: bootmgr.exe.mui /tftpboot/winpe/x86/pxe/ja-JP: bootmgr.exe.mui
なお、ファイルのパーミッションは、これらのファイルはLinux上では単に置いてあるだけで実行できないし、TFTPサーバが読みだすだけなのでrootの所有で644のパーミッションにしておいた(ディレクトリは755)。
■ TFTPで配布できるようにシンボリックリンクを張る
すべてのファイルはPXEサーバ上へ展開できたが、このままでは、PXEクライアント(=WinPEを起動するPC)からTFTPでリクエストされるパス名やファイル名と異なるので、ファイル名・ディレクトリ名の変更やディレクトリの移動が必要になる。しかし、Linuxではシンボリックリンクという大変便利な方法があるので、それを利用してクライアントからのリクエストに対応できるようにする。なお、クライアントからは「\」記号を使ってフォルダを指定してくるが、Linuxでは「\」はディレクトリの区切り記号でないので、これもシンボリックリンクを使って解決できる。一石二鳥の方法だ。例えば、クライアントからは"\boot\boot.sdi"というファイルを要求してくるが、Windows系PXEサーバであればTFTPのルートフォルダの下に"BOOT"というフォルダを作り、その下に"BOOT.SDI"というファイルを置いておけばいい。(フォルダ名やファイル名は"BOOT"でも"Boot"でも"boot"でも構わない。その辺、Windows系はいい加減というか。実はローダーが要求する名前も大小文字が実体のファイル名と異なったり、"\boot"だったり"\Boot"だったり、一貫性がない....。) 一方、Linux系PXEサーバを使う場合は"\boot\boot.sdi"という「名前」のファイルにしなければならない。そう、「\」は区切記号ではなく、ファイル名の中の単なる文字として扱えばいい。あとは、大文字、小文字の区別も含めて正確にクライアントから要求された通りの「ファイル名」として、実体ファイルへシンボリックリンクをかける。
/tftpbootディレクトリから、必要なファイルへ、クライアントから呼び出されるパス名・ファイル名で、シンボリックリンクをかける。全てのファイルにシンボリックリンクをかけると以下のような内容になる。
[root@pxeserver ~]# ls -l /tftpboot/ total 100 lrwxrwxrwx 1 root root 18 2008-06-17 11:17 \Boot\BCD -> winpe/x86/boot/bcd lrwxrwxrwx 1 root root 23 2008-06-17 11:17 \boot\boot.sdi -> winpe/x86/boot/boot.sdi lrwxrwxrwx 1 root root 35 2008-06-17 11:21 \Boot\en-US\bootmgr.EXE.MUI -> winpe/x86/pxe/en-US/bootmgr.exe.mui lrwxrwxrwx 1 root root 33 2008-06-17 11:18 \Boot\Fonts\jpn_boot.ttf -> winpe/x86/boot/fonts/jpn_boot.ttf lrwxrwxrwx 1 root root 34 2008-06-17 11:18 \Boot\Fonts\wgl4_boot.ttf -> winpe/x86/boot/fonts/wgl4_boot.ttf lrwxrwxrwx 1 root root 35 2008-06-17 11:20 \Boot\ja-JP\bootmgr.EXE.MUI -> winpe/x86/pxe/ja-JP/bootmgr.exe.mui lrwxrwxrwx 1 root root 25 2008-06-17 11:21 bootmgr.exe -> winpe/x86/pxe/bootmgr.exe lrwxrwxrwx 1 root root 19 2008-06-17 11:22 \sources\boot.wim -> winpe/x86/winpe.wim drwxr-xr-x 3 root root 4096 2008-06-17 11:15 winpe
ここで大文字、小文字の区別は意味があるので、この通りにリンクを張る必要がある。WinPEのバージョン等によって、ローダがtftpサーバへ要求するファイル名(の特に大文字小文字)が異なる可能性もあり、その場合tftpサーバは要求に応えられない。上手くtftpサーバからファイルをダウンロードできない場合は、ログを見ながら適宜修正する。
■ /etc/dhcpd.confの設定
PXEクライアントが最初にダウンロードするNBPが"pxeboot.n12"であることを知らせるために /etc/dhcpd.conf に次のようなクライアントの設定を追加する。(ここでは、PXEクライアントのホスト名を"disklesswin"という名前として/etc/hostsに登録してあるものとする。)
host disklesswin { hardware ethernet 01:23:45:67:89:AB; # PCのMACアドレス fixed-address disklesswin; # /etc/hostsで定義されているホスト名 next-server 192.168.100.97; # PXEサーバのIPアドレス filename "/winpe/x86/pxe/pxeboot.n12"; default-lease-time 1296000; # 2 weeks max-lease-time 2592000; # 4 weeks }
/etc/dhcpd.conf を変更したらdhcpdサービスを再起動していおく。
[root@pxeserver ~]# service dhcpd restart
以上で設定は終了。Windows PEを動かしたいPCの電源を入れれば、ネットワークブートするはずである。(PCのBIOS設定で優先的にPXEでブートすることを忘れないように。)
■ bootmgerのメッセージを日本語にしてみる
ブートのメッセージは英語のままである。これは、ブートの方法を指定するBCD(Boot Configuration Data)ファイルに言語として英語を使うように設定されているからだ。日本語でメッセージを出したければBCDを変更して、日本語をデフォルト言語にする。
BCDを変更するにはWinPEを一旦CDから立ち上げ、CDに入っているオリジナルのBCDを次の手順で変更する:
X:\windows\system32>copy D:\BOOT\BCD X:\Windows\Temp\bcd.ja-JP 1 個のファイルをコピーしました。 X:\windows\system32>cd X:\Windows\Temp X:\Windows\Temp>dir ドライブ X のボリューム ラベルは Boot です ボリューム シリアル番号は 0AD6-C20D です X:\Windows\Temp のディレクトリ 2008/01/19 17:45. 2008/01/19 17:45 .. 2008/01/05 03:22 262,144 bcd.ja-JP 1 個のファイル 262,144 バイト 2 個のディレクトリ 31,764,480 バイトの空き領域 X:\Windows\Temp>bcdedit /store bcd.ja-JP /set {bootmgr} locale ja-JP この操作を正しく終了しました。 X:\Windows\Temp>bcdedit /store bcd.ja-JP /set {default} locale ja-JP この操作を正しく終了しました。 X:\Windows\Temp>bcdedit /store bcd.ja-JP /set {memdiag} locale ja-JP この操作を正しく終了しました。 X:\Windows\Temp>dir ドライブ X のボリューム ラベルは Boot です ボリューム シリアル番号は 0AD6-C20D2 です X:\Windows\Temp のディレクトリ 2008/01/19 17:45 . 2008/01/19 17:45 .. 2008/06/17 12:27 262,144 bcd.ja-JP 1 個のファイル 262,144 バイト 2 個のディレクトリ 31,752,192 バイトの空き領域 X:\Windows\Temp>
新しく作った"bcd.ja-JP"を使ってPXEブートするように設定すれば日本語のメッセージになる。
無事にブートが終われば、わざわざ日本語で表示する必要性もない。が、
エラーが起きた時は少しは役に立つか。もっとも元のメッセージが意味不明なので、余り役に立たないかも。
■ 参考にしたページと感想
- Windows XP と Windows PE 2.0 によるデュアル ブート:Windows PEのブート方式について書いているが、PXEには触れていない。今回はむしろBCDの設定の仕方の参考となった。
- Configuring the Deployment Agent Builder service:Microsoftのネットブートなどに書いているがLinuxのPXE設定には役に立たなかった。PXEブートの過程でboot.iniというファイルをダウンロードしようとしていて、その書き方が分からなくて参照したが、結局、WinPEのPXEブートではboot.iniは使っていないようだ。これはPXEではなく、MicrosoftのADSを使う時に参照されるファイルのようだ。
- ImageX と WIM イメージ形式:ImageXの使い方が書いてある。
今回はほとんど参考にするページはなかった。LinuxやBartPEのネットワークブートをやっていたので、大体は勘で出来てしまった。XPの時よりも素直に動いたし、WinPEの中にネットワークブート用のコマンドやツールが集められているので、やりやすかった。
*1:特殊といってもWindows PE 2.0はWindows Server 2003 SP1のカーネルntosknl.exeと全く同じファイルだった。