以前のエントリーで Windows 7 の C:\Program Fiels フォルダーを別ドライブに移動させる方法を紹介したが、本エントリーでは以前の加筆修正をまとめて 「x64 対応半自動化版」 とし、改めて 32ビット及び 64ビット環境双方でより汎用的に使える方法を紹介する。

※ 注意 ※

以下の作業で操作を誤ると、OS に回復不能な損傷を与えて Windows 及び各種アプリケーションの再インストールが必要になる他、データを失う等の副次的被害が発生する可能性があります。本ページで紹介するスクリプトは筆者の環境で意図通りに動作することを確認していますが、全ての環境において正常動作を保証するものではありません。

またスクリプトの処理内容を理解せずに改変及び実行することは、非常に危険です。本ページの内容を参考に行った作業によって何らかの損害を被った場合も筆者は一切の責任を負いませんので、お試しになる場合は、くれぐれも自己責任でお願いします。

想定する環境は Windows 7 Ultimate の 32ビット版及び 64ビット版。ProgramFiles フォルダーの移動前のパスを C:\Program Files、移動先のパスを D:\Program Files とし、文中では実パスに加え、それぞれ 「旧 ProgramFiles フォルダー」、「移動先 ProgramFiles フォルダー」 とも表記する。表示フォントによってはパス区切り記号の "¥" がバックスラッシュ (半角\) になるので、"/" と間違えないように注意。

作業の流れは以前と変わらず、次の通り。

  1. ローカル Administrator の有効化とパスワード設定。
  2. ProgramFiles フォルダーをコピー。
  3. レジストリの書き換え。
  4. 旧 ProgramFiles フォルダーの削除とシンボリック・リンク作成。
  5. 移動先のアプリケーションの動作確認。

 

1. ローカル Administrator の有効化とパスワード設定

まず、ローカル Administrator を有効化する。任意のユーザーでログオン後、スタート メニューの 「全てのプログラム」 → 「アクセサリ」 → 「コマンド プロンプト」 を右クリック → 「管理者として実行」 でコマンド プロンプトを管理者権限で起動し、次のコマンドを入力する。

・Administrator を有効化
> net user Administrator /active:yes

・パスワードを設定
> net user Administrator <PASSWORD>

・ログオフ
> logoff

管理者権限がない場合は、「システム エラー 5」 「アクセスが拒否されました」 等のエラーが発生する。コマンドが正常に終了したら、ログオフして Administrator でログオンし直す。

2. ProgramFiles フォルダーをコピー

次に旧 ProgramFiles フォルダーをコピーする。基本は xcopy コマンドに適切なオプションを与えて手動コピーだが、同じ作業を繰り返す可能性があるなら、バッチファイルでスクリプト化しておいた方が、ミスをするリスクを軽減できる。

以下のスクリプトは、旧 ProgramFiles フォルダーを所有権、アクセス許可設定、監査設定等を再現しつつ、移動先にコピーする。誤って実行してしまうことを防ぐため、Administrator 以外は実行できない (=最後に飛ばされる) ようにしている。ファイル名は拡張子が ".bat" なら何でも構わないが、"hoge.bat" にするよりは、例えば "MoveProgramFiles_2_Copy.bat" 等、処理内容を想像できる名前の方がいいと思う。

※ 03/05 追記
日本語環境に存在する "Program Files\Windows NT\アクセサリ" は同じ場所にある "Accessories" へのジャンクションだが、xcopy に /b オプションを付加しても参照先の実体がコピーされてしまう。この対策として、コピー先で "アクセサリ" を一度削除し、改めて同名のジャンクションを作成している。

@echo off
echo ### MOVING PROGRAMFILES: PHASE 2 ###
echo.

if not "%USERNAME%" equ "Administrator" (
    echo Only the Administrator can run this script.
    goto ERROR
)

rem User settings: START ==========
set FromDir=C:\Program Files
set FromDirX86=C:\Program Files (x86)
set ToDir=D:\Program Files
set ToDirX86=D:\Program Files (x86)
rem User settings: END ==========

:X86
if /i "%ProgramFiles%" equ "%FromDir%" (
    if exist "%FromDir%" (
        if not exist "%ToDir%" (
            xcopy /e /h /k /o /x /b /y "%FromDir%" "%ToDir%\"
            if exist "%ToDir%\Windows NT\アクセサリ" (
                takeown /f "%ToDir%\Windows NT\アクセサリ" /r /a /d y
                cacls "%ToDir%\Windows NT\アクセサリ" /t /e /c /g %USERNAME%:f
                rmdir /s /q "%ToDir%\Windows NT\アクセサリ"
                if not exist "%ToDir%\Windows NT\アクセサリ" mklink /j "%ToDir%\Windows NT\アクセサリ" "%ToDir%\Windows NT\Accessories"
            )
        )
    )
)

:X64
if /i "%ProgramFiles(x86)%" equ "%FromDirX86%" (
    if exist "%FromDirX86%" (
        if not exist "%ToDirX86%" (
            xcopy /e /h /k /o /x /b /y "%FromDirX86%" "%ToDirX86%\"
        )
    )
)

:END
echo.
echo Copying ProgramFiles directories was completed.
echo Replace paths in your registry as follows:
if /i "%ProgramFiles%" equ "%FromDir%" (
    echo   "%FromDir%" to "%ToDir%"
)
if /i "%ProgramFiles(x86)%" equ "%FromDirX86%" (
    echo   "%FromDirX86%" to "%ToDirX86%"
)

:ERROR
pause

コピーが完了したら、旧 ProgramFiles フォルダーと移動先 ProgramFiles フォルダーのプロパティ・ウィンドウを並べて、ファイルやフォルダーの数、合計サイズが正しいことを目視確認する。(03/05 追記: xcopy に /b オプションがなかった過去の記事を参考に実施した方は、"Phase 4" のスクリプトを参考に移動先 ProgarmFiles フォルダー内の "WindowsNT\アクセサリ" の所有権とフルコントロールを設定後に削除し、mklink /j で Accessories へのジャンクションを作成すると、同等の結果となる)

尚 「ディスク上のサイズ」 は、それぞれのフォルダーが存在するパーティションのクラスター・サイズ (=アロケーション・ユニット・サイズ) によっては、一致しないことがある。前述の内容が正しければ、数値が違っていても気にする必要はない。

3. レジストリの書き換え

ProgramFiles フォルダーのコピーが完了したら、レジストリ中に存在する文字列 "C:\Program Files" を "D:\Program Files" に置換する。ただ該当箇所は大量に存在するので、Windows 標準の 「レジストリ エディター」 でチマチマ置換する自信がなければ (僕は無理)、Registry ToolkitRegGrep (32ビット環境のみ) 等の便利なツールを利用した方がいい。

Registry Toolkit を使う場合は、ツリー構造の "My Registry" を選択した状態でメニューの 「Registry」 → 「Search of Replace in Registry」 ダイアログを表示させ、"Settings" の "Match Case"、"Search/Replace In" の "Data" と "Value" のチェックを ON にして、「Replace」 ボタンをクリックする (各項目名が何を指すのか不明な場合は、こちらのサイトが参考になる)。"Start In:" が "My Registry" 以外になっている場合はレジストリの全域をスキャンできないので、忘れずに確認する。ヒットした文字列を全て置換するには、最初に表示されるダイアログで 「Replace Rest」 ボタンをクリック。

尚、Registry Toolkit はシェアウェア (32ビット版/64ビット版各 $25.00、両方で $35.00。いずれも本エントリー執筆時点での価格) だが、今回限りの利用であれば、未登録状態でも目的は達せられる。もちろんそのまま使い続けたいと思えばライセンス購入を検討すればいいし、他に使い慣れたレジストリ編集ツールがあれば、そちらを使っても一向に構わない。

20100228a_1.jpg
Registry Toolkit での置換

環境によっては 8.3形式の短いファイル名が使われている可能性もあるので、C:\PROGRA~1 を検索してみて、存在すれば D:\PROGRA~1 に置換する。

さらに、アプリケーション単位の INI ファイル等で旧 ProgramFiles フォルダーがフルパスで指定されている場合も不具合が予想されるので、移動先 ProgramFiles フォルダー内で文字列 "C:\Program Files" を検索する。その際はファイルの内容を検索対象に含めるため、事前に 「フォルダー オプション」 の 「検索」 タブにある 「検索項目」 で、「ファイル名と内容を常に検索する」 を選択しておく。

クリーン・インストール直後の僕の環境 (=ドライバー類も OS デフォルトのまま) では、8.3形式の ProgramFiles フォルダーのパスや、修正が必要な INI ファイルは見つからなかった。クリーン・インストール直後のように結果が予測できる単純な環境であれば、これらの検索は省略しても問題ないと思う。

旧 ProgramFiles フォルダーを指す全ての文字列置換が完了後、Windows 7 を再起動する。

4. 旧 ProgramFiles フォルダーの削除とシンボリック・リンク作成

旧 ProgramFiles フォルダーを削除する前には、所有権を奪ったり、アクセス許可設定を変更する作業が必要になる。HDD を別のマシンに接続したり、KNOPPIX  等の CD-ROM/DVD-ROM から起動して NTFS パーティションの操作が可能な Linux から削除する方法もあるが、Windows XP にはなかった便利なコマンドが使える Windows 7 では、バッチファイルでスクリプト化しておいて直接実行するのが確実で手っ取り早い。

以下のスクリプトは、takeown で 旧 ProgramFiles フォルダーと 64ビット環境では ProgramFiles(x86) フォルダーの所有権を Administrator に設定し、cacls で Administrator にフルコントロール権限を与えてから rmdir で削除後、mklink で C:\ 直下に移動先 ProgramFiles フォルダーと、64ビット環境では ProgramFiles(x86) フォルダーへのシンボリック・リンクを作成する。旧 ProgramFiles フォルダー削除時に邪魔になるサービス IP Helper は処理前に停止させ、処理後に改めて起動させる。また前述のスクリプト同様、Administrator 以外は実行できない (=最後に飛ばされる) ようにしている。

ここでもファイル名は何でもいいが、"MoveProgramFiles_4_Remove.bat" 等、処理内容を想像できる名前が望ましい。

@echo off
echo ### MOVING PROGRAMFILES: PHASE 4 ###
echo.

if not "%USERNAME%" equ "Administrator" (
    echo Only the Administrator can run this script.
    goto ERROR
)

rem User settings: START ==========
set FromDir=C:\Program Files
set FromDirX86=C:\Program Files (x86)
set ToDir=D:\Program Files
set ToDirX86=D:\Program Files (x86)
rem User settings: END ==========

net stop "IP Helper"

:X86
if /i "%ProgramFiles%" equ "%ToDir%" (
    if exist "%ToDir%" (
        if exist "%FromDir%" (
            takeown /f "%FromDir%" /r /a /d y
            cacls "%FromDir%" /t /e /c /g %USERNAME%:f
            rmdir /s /q "%FromDir%"
            if not exist "%FromDir%" mklink /d "%FromDir%" "%ToDir%"
        )
    )
)

:X64
if /i "%ProgramFiles(x86)%" equ "%ToDirX86%" (
    if exist "%ToDirX86%" (
        if exist "%FromDirX86%" (
            takeown /f "%FromDirX86%" /r /a /d y
            cacls "%FromDirX86%" /t /e /c /g %USERNAME%:f
            rmdir /s /q "%FromDirX86%"
            if not exist "%FromDirX86%" mklink /d "%FromDirX86%" "%ToDirX86%"
        )
    )
)

net start "IP Helper"
echo.
dir /a C:\
if exist "%ToDir%" (
    echo.
    set ProgramFiles
    set CommonProgramFiles
)

:END
echo.
echo Moving ProgramFiles directories was completed.

:ERROR
pause

シンボリック・リンクは、レジストリの編集不可能な領域に書かれているパス対策。旧 ProgramFiles フォルダーのパスで移動先 ProgramFiles フォルダーにアクセスできるようにするための仕組みで、シンボリック・リンクを作成しない状態では、デスクトップの右クリック・メニューの 「ガジェット」 が機能しなかった。とりあえず他には目立った不具合は見つからなかったが、作成しておいた方がよさそうだ。

5. 移動先のアプリケーションの動作確認

移動させたアプリケーションが正常に動作することを確認し、作業完了。

12 Responses to this entry.

  • Natz:

    Windows Vista Ultimate (x86) において、本エントリーの手順で ProgramFiles フォルダーを移動させられることを確認。

  • None:

    HPを参考にProgram Files フォルダーを別ドライブに移動してみましたが、Windows Updateで80070011エラーが出るようになりました。
    ネットで調べてみたところフォルダー移動が原因のようでpending.xmlを都度編集すればよさそうなことはわかったのですが、同様の現象起こっていますか?もし起こっていて何か簡単な対策ご存知でしたらご教示ください。

  • Natz:

    コメントありがとうございます。
    今まで数台の Windows 7 (x86/x64) で ProgramFiles フォルダーを移動させていますが、特に不具合はなく、その現象も初めて耳にしました。
    Windows Update 等で導入されるプログラムが移動前のパスを参照していても、移動後のパスへのシンボリック・リンクで回避できそうに思えますが、ダメでしょうか?

  • Natz:

    補足です。エラー番号は違うものの (8020000E)、

    http://forums.techarena.in/windows-update/646990.htm

    のような情報がありました。要は %windir%\SoftwareDistribution をリネームするだけですが、同フォルダーは必要に応じて自動生成されるので、特に問題はないと思います。Windows Update がフォルダーを見ている真っ最中等でリネームに失敗する場合は、Windows の起動直後や、Windows Update を一時無効にする等の方法で、リネームできると思います。

    「問題ないはず」 と言いつつ、過去にインストールした Windows Update の履歴が失われる弊害はありそうですが、リネームしたフォルダーから何かファイルを書き戻すことで、復活させられるかもしれません (この辺の操作は未検証です)。

    解決策となるかはわかりませんが、参考までに。

  • iwao:

    Cドライブをどうにか軽くできないものかと、いろいろ探しまわってここを発見したので早速やってみました。

    当方win7(64bit) Ultimateです。
    フォルダ移動後も問題なく稼働しています。

    1つ気になる点があるのですが、フォルダ移動後も何かをインストールするたびにCドライブの残量が減っていっているように見えるのですが、これは表示だけの問題で実際は減ってはいないのでしょうか?

  • Natz:

    > iwao さん
    コメントありがとうございます。アプリケーションによっては %ProgramFiles% 以外の場所、%windir% や %appdata% 等にファイルをコピーするものもありますので、「C ドライブの空き容量が減っているように見える」 場合は、実際に減っているはずです。一方 「%windir% の合計サイズが増えているように見える」 場合は、Windows Update 等で %windir%\winsxs 以下にハードリンク (=パスや名前が異なり別のファイルに見えるものの、データの実体は 1つ) が増え、実際の容量は変化していない可能性があります。

    OS インストール直後の状態等で、%ProgramFiles% を削除しても C ドライブの空き容量が増えない現象も、この %windir%\winsxs に蓄積されるハードリンクが原因です。Windows 上ではわかりませんが、Linux 等の UNIX 系 OS で C ドライブのパーティションを覗いてみると、winsxs 以下にはハードリンク数が 2 以上のファイルが大量に存在していることがわかります。

    例えば Windows 7 (32ビット版) インストール直後の状態で "C:\Program Files\Internet Explorer" 直下にある "iexplore.exe" 等を winsxs 内で検索すると、同名ファイルが存在し、ハードリンク数は 2 です。しかしこの記事の手順で %ProgramFiles% を別ドライブに移動させた後に同じファイルを winsxs 内で検索すると、ファイルは見つかりますが、ハードリンク数が 1 に減っています。これはハードリンクにはパーティションをまたいで作成できない制約があり、%ProgramFiles% の移動先が別ドライブ (=異なるパーティション) だと、自動的にリンクが切れるためです。

    このことから、「%ProgramFiles% を移動させたのに C ドライブの空き容量が増えない」 現象は、

    1. OS インストール直後の %ProgramFiles% 以下のファイルに関しては、%windir%\winsxs にハードリンクが作成されている。
    2. %ProgramFiles% を別ドライブに移動させると、システム上の 「プログラムのインストール先」 としての %ProgramFiles% はその通りに移動し、それ以後インストールされるファイルも移動先の %ProgramFiles% にコピーされるようになるが、移動前に winsxs 以下に作成されていたハードリンクはそのまま残る。

    が原因であることがわかります。

    従って 「*以後* C ドライブに余計なファイルがコピーされ *にくい* 環境を作る」 ことを目的に %ProgramFiles% を移動させた場合は、ほぼ期待通りの効果が得られますが、「今 C ドライブが苦しいから空き容量を増やす」 ことを目的に実施すると、環境によっては期待外れの結果になる可能性があります。

    「環境によっては」 と書いたのは、winsxs にハードリンクが作成されるのは、Windows がデフォルトで持っているファイルや Microsoft 製品等、Windows Update の対象となるデータに限定されるためです。OS インストール直後等、移動前の %ProgramFiles% にこの種のデータしかない場合 (=ほぼ全てのデータのハードリンクが winsxs に存在している状態) は、%ProgramFiles% を移動させても空き容量はほとんど変化しませんし、逆にサード・パーティ製 (=Windows Update とは無関係) のアプリケーションを大量にインストールしている場合は、winsxs にハードリンクが作成されていないファイルの方が多くなるので、目に見えて空き容量が増えるはずです。

    前者のケースでも winsxs 内のファイルを削除すれば確実に空き容量は増えますが、%ProgramFiles% 以下のフォルダー構造とは異なることや、Windows Update (のロールアップ情報等) の絡みで、機械的にファイル名で検索して削除、とはできなそうですし、強行した場合は副作用があるでしょうから、この件に関しては、少なくとも現時点では 「こう言うもんだ」 と諦めた方がいいと思います。

  • Andy:

    Natzさん、初めましてアンディと申します。
    このサイトに記載されていたバッチファイルを利用して
    私もProgram Filesを移動しました。

    お世話になりましたので、お礼を申し上げます。

    なお、この記事をもとに私が行った手順を記した記事を
    私もブログに書きましたので、よかったら見てくださいw
    http://andy2525.blog52.fc2.com/blog-entry-115.html
    (無駄に長いです…)

  • Natz:

    > アンディさん
    コメントありがとうございます。お役に立てましたでしょうか。
    blog を拝見したところ、通常はレジストリ置換後に Windows を再起動すると、ProgramFiles 等の環境変数の値が変わっていることが多いと思いますが、変わらないこともあるんですね。やはりこの手の作業を初めて実施する場合は、いざとなったらクリーン・インストールできる環境を整えておかないと、怖いですね。

  • Taka:

    こんにちは。
    ぼくもこのサイトを参考にProgram FiresをDへ移動しました。
    ありがとうございました。

    ところが、旧ProgramFilesフォルダーの削除とシンボリック・リンク作成のバッチファイルを適用したのですが、Natzさんご指摘のとおり、デスクトップ→右クリック→カジェットが機能しません。
    これはシンボルリンクが作成されてないとみていいのでしょうか?

  • Natz:

    > Taka さん
    コメントありがとうございます。シンボリック・リンクは、エクスプローラーで C:\ を見れば "Program Files" や "Program Files (x86)" がショートカットのアイコンが付いたフォルダーとして見えますし、コマンド・プロンプトで見れば <SYMLINKD> として表示されることから、存在が確認できます。見当たらなければ何らかの理由で作成に失敗している可能性がありますが、手動で作成すれば問題ないと思います。ただし、フォルダー本体の移動が正常に完了していることが前提になります。

    こちらで検証した限りでは、フォルダーが正常に移動し、シンボリック・リンクが作成された状態であれば、デスクトップの右クリック→「ガジェット」は正常に動作しています。シンボリック・リンクが存在していて「ガジェット」が効かない場合、ひょっとすると他に原因があるかもしれません。

  • Nand:

    全ての手順を終わらせてエクスプローラーで確認したところ
    C:\にC:\Program Files (x86)が残って、(x86)のシンボリックリンクは
    ありませんでした。C:\の(x86)の中には二つほどフォルダもあります。
    ちなみにD:/にはしっかり全てコピーされているようです。

    シンボリックリンクはC:\Program Filesの方だけあります。なので
    (x86)のシンボリックリンクも作ろうと、Administratorでrmdirコマンドで
    C:\Program Files (x86)をディレクトリごと削除した後
    そのシンボリックリンクを作成しようとしましたが、rmdirでアクセス拒否
    されてしまい削除できません。お手数ですが削除方法とシンボリック作成方法を
    ご教授願えないでしょうか?

  • Natz:

    > Nand さん
    コメントありがとうございます。スクリプト中ではフォルダーの削除を確認してからシンボリック・リンクを作成しますので、何らかの理由でフォルダーを削除できなかった場合は、シンボリック・リンクは作成されません。

    Administrator による takeown → cacls のコンボも空しく "C:\Program Files (x86)" フォルダーの削除に失敗するなら、何かのプロセスが使用中である可能性があります。削除実行前にレジストリの置換 → 再起動を実施していても "C:\Program Files (x86)" フォルダーが使用中の場合は、レジストリのどこかに置換から漏れた文字列が残ってるのかもしれません。アプリケーションによっては INI や XML 等のテキスト・ファイルにパスが書かれていることもありますが、これは完全に環境に依存しますので、お使いのマシンを注意深く確認してください、としか言えません。

    強行する場合は、残った "C:\Program Files (x86)" 中に残ったフォルダーやファイルから当たりを付け、怪しいプロセスをタスク・マネージャ-で殺したりサービスを止める等して再度手動で削除を試みるか、KNOPPIX 等の CD-R/DVD-R/USB メモリから起動する Linux で "Program Files (x86)" フォルダーを削除するか、"Program Files (x86)" フォルダーが含まれる HDD を別マシンに接続して、別マシン上で削除する、ぐらいでしょうか。

    元フォルダーの削除に成功すれば、mklink コマンドで元フォルダーと同じ場所に同名のシンボリック・リンクを作成できるはずです。