TL;DR —
Environ("USERPROFILE")、Environ("TEMP")、Environ("USERNAME")は、Windows が すべてのプログラムに渡す変数を読むので、C:\Users\John\...を決してハードコードしなくて済みます — それは他のどのマシンでも壊れるパスです。落とし穴は静かです。存在しない、あるいは綴りを間違えた 名前は、エラーではなく空文字列を返します。だからEnviron("TMEP") & "\out.txt"は"\out.txt"になり、ドライブのルートに落ちます。すべてのEnvironの結果を、空になりうるものとして扱いましょう。
Sub EnvironDemo()
Debug.Print Environ("USERPROFILE") ' C:\Users\Ann
Debug.Print Environ("TEMP") ' C:\Users\Ann\AppData\Local\Temp
Debug.Print Environ("USERNAME") ' Ann
Debug.Print Environ("TMEP") ' "" — 綴り間違い、エラーは出ず、ただ空
End Sub
すべての Windows プログラムには、NAME=VALUE 文字列の小さな表 — 環境ブロック — が手渡されます。
そこには、ユーザーのプロファイルがどこにあるか、一時ファイルがどこへ行くか、誰がログインしているか、
などが記録されています。Environ は、その表をのぞく VBA の窓です。マシン固有のフォルダーを見つける
正しく可搬な方法であり、あなたが尊重しなければならない習慣がちょうど一つあります。持っていない名前を
尋ねると、文句を言うのではなく、空で答えるのです。
この記事で学べること
- 考え方の軸 —
Environは、このプログラムに対する Windows の生きたNAME=VALUE表を読む - 要点は可搬パス:ハードコードした
C:\Users\<名前>\...の代わりに - 存在しない、あるいは綴りを間違えた変数が
""を返す理由 — 静かなバグ — と、その防ぎ方 - 2 つの呼び出し形式:名前による
Environ("NAME")と、数値インデックスによるEnviron(n) - ブロックが Excel 起動時に取られたスナップショットである理由と、ここでの「古い」の意味
Environにできないこと — 変数を書く、あるいは起動後に変更されたものを読む
考え方の軸:Environ は Windows の name=value 表を読む
Windows がプログラムを起動するとき、NAME=VALUE のペアの一式をそのプログラムのメモリへコピーします
— プロセス環境です。そこには USERPROFILE=C:\Users\Ann、TEMP=C:\Users\Ann\AppData\Local\Temp、
COMPUTERNAME=DESK-01 など、数十のエントリが入っています。Environ は、その表で名前を引き、値を
テキストとして返すだけです。
Dim tempDir As String
tempDir = Environ("TEMP") ' 表に「TEMP」の下に格納された値を尋ねる
これがモデルのすべてです。Environ は、Excel が開く前に Windows が埋めておいた参照表の読み取り
です。Windows 設定へのライブなクエリでも、レジストリでも、現在の作業ディレクトリでもありません —
それらは別のものです。「表で名前を引く」ものと見えたとたん、以下のルールが導かれます。
ハードコードしたユーザーパスを置き換える — それが要点
そもそも Environ を使う理由はこれです。自分のマシンでしか動かないパスを書くのをやめる。
次の行は、他の誰かが実行した瞬間に壊れる典型的なマクロです。
Open "C:\Users\John\AppData\Roaming\MyApp\log.txt" For Append As #1 ' John のところでしか動かない
他の誰の PC にも、John という名前のユーザーはいません。パスを環境から組み立て直せば、どこでも 動きます。
Dim p As String
p = Environ("APPDATA") & "\MyApp\log.txt" ' C:\Users\<誰であれ>\AppData\Roaming\MyApp\log.txt
Open p For Append As #1
いちばんよく手に取る変数:USERPROFILE(ユーザーのホームフォルダー)、APPDATA と LOCALAPPDATA
(ユーザーごとのアプリデータ)、TEMP(作業用の一時ファイル)、USERNAME(誰がログインして
いるか)、COMPUTERNAME、そして PUBLIC。その結果を Open、
Dir、あるいは Shell コマンドに渡せば、マクロは
編集なしでどのマシンにも渡り歩けます。
存在しない変数はエラーではなく空文字列を返す
いちばん紛らわしい失敗を生む罠がこれで、Environ が表引きであることの直接の帰結です。そこに
ない名前を尋ねれば、空文字列が返る — エラーもなく、警告もなく。 たった 1 文字のタイプミスで
十分です。
Dim p As String
p = Environ("TMEP") & "\out.txt" ' TMEP は存在しない -> "" & "\out.txt" = "\out.txt"
Open p For Output As #1 ' ドライブのルートに C:\out.txt を作る — 意図したものではない
Environ の行では何も文句を言いません。「見つからない」がそれにとって正当な答えだからです。被害は
あとから、別の場所で現れます — ドライブのルートのファイル、開くのに失敗するパス、間違った場所に
作られたフォルダー — それを引き起こしたタイプミスから遠く離れて。大事なものはガードしましょう。
Dim tempDir As String
tempDir = Environ("TEMP")
If tempDir = "" Then
MsgBox "TEMP is not set - cannot continue.": Exit Sub
End If
持ち帰るべきルール:空の Environ の結果は例外ではなく、正常 — 値が欠けるとファイルが間違った
場所へ行ってしまう場面では、つねに確認しましょう。これは、Excel の外への呼び出しの多くを危険にする
のと同じ静かな失敗が、環境ブロックにこだました姿です。間違いへの答えは、大きな音を立てた停止では
なく、静かな空なのです。
2 つの呼び出し形式:名前とインデックス
Environ には 2 つの形があり、返すものが違います。文字列を渡せば、その変数の値が得られます。
数値を渡せば、その位置にある生の NAME=VALUE ペア全体が得られ、ブロック全体を列挙できます。
Debug.Print Environ("PATH") ' 名前で -> 値だけ: C:\Windows;C:\Windows\System32;...
Dim i As Integer, entry As String
i = 1
Do
entry = Environ(i) ' インデックスで -> 生のペア: "USERPROFILE=C:\Users\Ann"
If entry = "" Then Exit Do ' 空文字列がリストの終わりを示す
Debug.Print entry
i = i + 1
Loop
インデックス形式は、マシンにどんな変数が存在するかを発見する方法です — 診断に便利です。同じ 空文字列の合図が二役をこなしていることに注目してください。名前に対しては「見つからない」を意味し、 インデックスに対しては「リストの終わりを越えた」を意味します。ループも表引きも、そのたった一つの 約束事に寄りかかっています。
スナップショットの罠と、Environ にできないこと
Environ を Windows のライブな眺めだと期待する人を捕まえる制限が 2 つあります。
起動時のスナップショットである。 Excel は起動したときに環境ブロックをコピーしました。あとから
変数を変更しても — システムのプロパティ、setx コマンド、あるいは別のツールで — その同じ Excel
セッションの Environ は新しい値を見ません。それは Excel が開いたときのままの世界を映します。
更新するのは再起動です。
読むだけ。書けない。 Environ("X") = "Y" という形はありません。変数を設定するには、あるいは
起動後に変更された変数を読むには、CreateObject 経由で WScript.Shell
オブジェクトの Environment コレクションが必要です。
Dim sh As Object
Set sh = CreateObject("WScript.Shell")
Debug.Print sh.Environment("Process")("TEMP") ' 生きたプロセスの値
' sh.Environment("User")("MYVAR") = "hello" ' この形なら、ユーザー変数を「書ける」
Environ はまた、値がどのスコープから来たか — ユーザー、システム、プロセス — を教えられません。
Windows はそれらをあなたが見る一つのブロックへと統合し、Environ は統合された結果だけを報告します。
日常の可搬パスにはそれでちょうど十分です。WScript.Shell.Environment に手を伸ばすのは、変数を
書かなければならないとき、あるいは変更されたばかりの変数を読まなければならないときだけにしましょう。
率直な結論:空になりうると心得て使う、可搬パスの道具
Environ は一つの仕事でその居場所を勝ち取り、それをよくこなします。マシン固有のフォルダーを、
持ち運べるパスに変えることです。間違いはすべて、表引きが静かに外れうることを忘れたところに行き着き
ます。4 つのルールで覆えます。
- 可搬パスに使う →
Environ("APPDATA") & "\MyApp\..."。ハードコードしたC:\Users\<名前>\...は決して使わない。 - あらゆる結果を空になりうるものとして扱う → 存在しない、あるいは綴りを間違えた名前は、
エラーではなく
""を返す。欠けるとファイルが間違った場所へ行く値はガードする。 - 2 つの形を知る →
Environ("NAME")は値を返し、Environ(n)は生のNAME=VALUEペアを返して ブロックを列挙させる。 - 起動時のスナップショットであり、読み取り専用 → Excel 起動後に変更された変数は見えず、設定も
できない。それには
WScript.Shell.Environmentを使う。
これらを正しくすれば、「自分の PC では動くのに、相手のでは壊れる」種類のパスバグが一族まるごと 消えます — あなたは特定のユーザーを名指すのをやめ、フォルダーが実際にどこにあるかをマシンに尋ね 始めるのです。
ExcelMaster の活用
本当に時間を無駄にする Environ のバグは、静かなパスのバグです。C:\Users\John にハードコード
されて他の全員で失敗するマクロ、エラーもなくファイルをドライブのルートに落とすタイプミスした
変数名、変数が設定されていると決めてかかって TEMP から組み立てたパス。どれも、環境を使わないか、
確認せずに信じ込むか、どちらかから生まれます。
ExcelMaster は、可搬パスの
ロジックを正しく書きます。行き先を説明すれば — 「ログをユーザーの AppData フォルダーに保存して」、
あるいは「作業用ファイルを Temp ディレクトリに書き出して」 — 適切な Environ 変数からパスを組み立て、
値が空でなく返ってきたことを検証し、そのうえで初めてファイルを開いたり作ったりします。あなたは
どのフォルダーかを説明するだけで、どのユーザーかは説明しません。そして、どのマシンでも変更なしに
動くコードを、それが生み出します。
よくある質問
VBA で現在の Windows ユーザー名を取得するには?
Environ("USERNAME") を使います — 現在のユーザーのログイン名を返します。たとえば Ann です。これは、
Windows API 呼び出しなしに、誰がマクロを実行しているかを識別する軽量な方法です。ログイン名では
なくフルの表示名やドメインが必要なら、GetUserNameEx のような API が要りますが、ログの押印や
ユーザーごとのパスの組み立てには、Environ("USERNAME") が標準的な答えです。
VBA でユーザーの Temp や AppData フォルダーのパスを取得するには?
Environ("TEMP") はユーザーごとの一時フォルダー(通常は C:\Users\<名前>\AppData\Local\Temp)を
返し、Environ("APPDATA") はローミングのアプリケーションデータフォルダーを返します。どちらも
ユーザー固有なので、そこからパスを組み立てれば C:\Users\<名前> のハードコードを避けられます。使う
前につねに結果が空でないことを確認しましょう:t = Environ("TEMP") : If t = "" Then Exit Sub。存在
しない変数は、エラーを上げるのではなく空文字列を返すからです。
VBA で Environ が空文字列を返すのはなぜですか?
尋ねた変数名がプロセス環境に存在しないからです — たいていはタイプミス(TEMP の代わりに TMEP)、
別のスコープにしか存在しない変数、あるいは Excel の起動後に作られた変数です。Environ は
「見つからない」を正常な答えとして扱い、エラーなしに "" を返します。ガードを足しましょう:
If Environ("NAME") = "" Then ...。変数が Excel の起動後に設定されたなら、Excel を再起動するか、
CreateObject("WScript.Shell").Environment("Process")("NAME") で生きた値を読みます。
VBA の Environ で環境変数を設定・変更できますか?
いいえ。Environ は読み取り専用で、代入の形はありません。変数を作成・変更するには、WScript.Shell
オブジェクトを使います:CreateObject("WScript.Shell").Environment("User")("MYVAR") = "value" は
永続的なユーザー変数を設定します。加えた変更は、現在の Excel セッションの Environ には現れない
ことに注意してください。Environ は Excel が起動したときに取ったスナップショットを読むので、新しい
値を見るには再起動が必要です。
VBA ですべての環境変数を列挙するには?
Environ を名前ではなく数値で呼びます — Environ(1)、Environ(2)、というように — それぞれ
その位置にある生の NAME=VALUE ペアを返します。空文字列が返るまでループしましょう。それがリストの
終わりを示します:i = 1 : Do : e = Environ(i) : If e = "" Then Exit Do : Debug.Print e : i = i + 1 : Loop。
これは環境ブロック全体を列挙し、パスが期待どおりに解決しないときの診断に役立ちます。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-30。
関連ガイド: VBA Shell — 外部プログラムを起動する · VBA CreateObject・GetObject — 遅延バインディングと COM 自動化 · VBA FreeFile・Open — ファイル番号とテキストファイル · VBA Dir — ファイルの存在確認と列挙 · VBA CurDir・ChDir — カレントディレクトリ
