環境変数の値や、展開前の環境変数の値をレジストリから取得する方法や、GetEnvironmentVariablesメソッドで得た値をLINQで処理する方法を説明する。
一般的に環境変数の値を取得するのは簡単なことだが、アプリの実行中に変更された値や、展開される前の生の値を得ようと思うと首をひねる場合がある。本稿では、環境変数の値を取得する方法をまとめて解説する。
特定のトピックをすぐに知りたいという方は以下のリンクを活用してほしい。
なお、本稿に掲載したサンプルコードをそのまま試すにはVisual Studio 2015以降が必要である。サンプルコードはコンソールアプリの一部であり、コードの冒頭に以下の宣言が必要となる。
using Microsoft.Win32;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using static System.Console;
Imports Microsoft.Win32
Imports System.Console
アプリに与えられた環境変数の値を取得するには、Environmentクラス(System名前空間)のGetEnvironmentVariable静的メソッドかGetEnvironmentVariables静的メソッドを使う。
取得したい環境変数が1つだけの場合は、環境変数名を指定してGetEnvironmentVariable静的メソッドを使えばよい(次のコード)。
// 環境変数「TEMP」の値を取得する
var tempPath = Environment.GetEnvironmentVariable("temp");
WriteLine($"TEMP={tempPath}");
// 出力例:TEMP=C:\Users\biac\AppData\Local\Temp
' 環境変数「TEMP」の値を取得する
Dim tempPath = Environment.GetEnvironmentVariable("temp")
WriteLine($"TEMP={tempPath}")
' 出力例:TEMP=C:\Users\biac\AppData\Local\Temp
全ての環境変数を列挙したい場合は、GetEnvironmentVariables静的メソッドを使えばよい(次のコード)。
IDictionary envVars = Environment.GetEnvironmentVariables();
foreach (DictionaryEntry entry in envVars)
{
string name = entry.Key as string; // 環境変数の名前
string value = entry.Value as string; // 環境変数の値
WriteLine($"{name}={value}");
}
// 出力例:
// PROCESSOR_ARCHITEW6432=AMD64
// COMPUTERNAME=ELICHIKA
// CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
// (以下略)
Dim envVars As IDictionary = Environment.GetEnvironmentVariables()
For Each entry As DictionaryEntry In envVars
Dim name As String = TryCast(entry.Key, String) ' 環境変数の名前
Dim value As String = TryCast(entry.Value, String) ' 環境変数の値
WriteLine($"{name}={value}")
Next
' 出力例:
' PROCESSOR_ARCHITEW6432=AMD64
' COMPUTERNAME=ELICHIKA
' CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
' (以下略)
このようにして取得できる環境変数は、アプリの起動時にプロセスへ割り当てられたものである。アプリの実行中に(ユーザー操作などによって)環境変数が追加/変更されても、この方法では追加/変更後の値を取得できない。この問題の対処方法は、次の「システム/ユーザー/プロセスの環境変数」をご覧いただきたい。
また、このようにして取得した環境変数の値は、(もしあれば)他の環境変数の値を使って展開したものになっている。例えば、最初のサンプルコードで示した環境変数「TEMP」の本来の値は「%USERPROFILE%\AppData\Local\Temp」なのだが、「%USERPROFILE%」の部分が環境変数「USERPROFILE」の値を使って展開されて「C:\Users\biac\AppData\Local\Temp」になっているのだ。読み取るときはこのように展開された方が便利だ。しかし、環境変数の値を書き込むときには、展開前の生の値を元にして設定しないとシステムに不具合を引き起こす心配がある。展開前の値を取得したい場合は、後述の「生の環境変数」をご覧いただきたい。
環境変数は、3段階に分けて管理されている。
前述の方法で取得できるのはプロセスの環境変数なのだ。アプリ起動時にセットされるだけなので、その後にシステムやユーザーの環境変数に変化があっても、それは反映されない。そのため変更後の環境変数が取得できないということになる。また、アプリがプロセス環境変数に変更を加えても、それはシステムやユーザーの環境変数に反映されない。
システムやユーザーの環境変数を取得するには、引数にEnvironmentVariableTarget列挙体(System名前空間)を指定する(次のコード)。
// 結果を検証できるように、プロセスの環境変数「TEMP」を変更しておく
string tempFolder = Environment.ExpandEnvironmentVariables(@"%SystemDrive%\TEST");
Environment.SetEnvironmentVariable("temp", tempFolder);
// システム環境変数「TEMP」を取得する
var tempPathS = Environment.GetEnvironmentVariable("temp",
EnvironmentVariableTarget.Machine);
WriteLine($"システム TEMP={tempPathS}");
// 出力例:システム TEMP=C:\WINDOWS\TEMP
// ユーザー環境変数「TEMP」を取得する
var tempPathU = Environment.GetEnvironmentVariable("temp",
EnvironmentVariableTarget.User);
WriteLine($"ユーザー TEMP={tempPathU}");
// 出力例:ユーザー TEMP=C:\Users\biac\AppData\Local\Temp
// プロセス環境変数「TEMP」を取得する(EnvironmentVariableTarget未指定と同じ)
var tempPathP = Environment.GetEnvironmentVariable("temp",
EnvironmentVariableTarget.Process);
WriteLine($"プロセス TEMP={tempPathP}");
// 出力:プロセス TEMP=C:\TEST
// システム環境変数を列挙する例
IDictionary envVars
= Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine);
foreach (DictionaryEntry entry in envVars)
{
string name = entry.Key as string; // 環境変数の名前
string value = entry.Value as string; // 環境変数の値
……省略……
}
' 結果を検証できるように、プロセスの環境変数「TEMP」を変更しておく
Dim tempFolder As String _
= Environment.ExpandEnvironmentVariables("%SystemDrive%\TEST")
Environment.SetEnvironmentVariable("temp", tempFolder)
' システムの環境変数「TEMP」を取得する
Dim tempPathS = Environment.GetEnvironmentVariable("temp",
EnvironmentVariableTarget.Machine)
WriteLine($"システム TEMP={tempPathS}")
' 出力例:システム TEMP=C:\WINDOWS\TEMP
' ユーザーの環境変数「TEMP」を取得する
Dim tempPathU = Environment.GetEnvironmentVariable("temp",
EnvironmentVariableTarget.User)
WriteLine($"ユーザー TEMP={tempPathU}")
' 出力例:ユーザー TEMP=C:\Users\biac\AppData\Local\Temp
' プロセスの環境変数「TEMP」を取得する(EnvironmentVariableTarget未指定と同じ)
Dim tempPathP = Environment.GetEnvironmentVariable("temp",
EnvironmentVariableTarget.Process)
WriteLine($"プロセス TEMP={tempPathP}")
' 出力:プロセス TEMP=C:\TEST
' システムの環境変数を列挙する例
Dim envVars As IDictionary _
= Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine)
For Each entry As DictionaryEntry In envVars
Dim name As String = TryCast(entry.Key, String) ' 環境変数の名前
Dim value As String = TryCast(entry.Value, String) ' 環境変数の値
……省略……
Next
Environmentクラスで取得する環境変数の値は、他の環境変数を使って展開したものになっている。例えば、最初のサンプルコードで出力例として示した環境変数「TEMP」の本来の値は「%USERPROFILE%\AppData\Local\Temp」なのだが、「%USERPROFILE%」の部分が展開されて「C:\Users\biac\AppData\Local\Temp」として取得されているのだ。なお、この展開処理は、アプリがプロセスの環境変数に書き込んだ値には適用されない(例えば、アプリからプロセスの環境変数に「%USERPROFILE%」と設定してから読み出しても、「%USERPROFILE%」のままになる)。
システム環境変数とユーザー環境変数は、レジストリに保存されている。展開前の環境変数が欲しいときは、レジストリから直接取得すればよい(次のコード)。その際、オプションとしてRegistryValueOptions列挙体(Microsoft.Win32名前空間)のDoNotExpandEnvironmentNames値を指定すると、展開されていない環境変数の値が得られる。
// 展開前のシステムの環境変数「TEMP」を取得する
// システム環境変数が保管されているサブキーの名前
const string SystemEnvKeyName
= @"System\CurrentControlSet\Control\Session Manager\Environment";
// レジストリHKEY_LOCAL_MACHINEのサブキーを開く
RegistryKey regKeyS
= Registry.LocalMachine.OpenSubKey(SystemEnvKeyName);
// サブキー内から「TEMP」という名前の値を取得する
string tempPathS = regKeyS.GetValue("temp", string.Empty,
RegistryValueOptions.DoNotExpandEnvironmentNames) as string;
WriteLine($"システム TEMP={tempPathS}");
// 出力例:システム TEMP=%SystemRoot%\TEMP
// 展開前のユーザーの環境変数「TEMP」を取得する
// ユーザー環境変数が保管されているサブキーの名前
const string UserEnvKeyName = @"Environment";
// レジストリHKEY_CURRENT_USERのサブキーを開く
RegistryKey regKeyU
= Registry.CurrentUser.OpenSubKey(UserEnvKeyName);
// サブキー内から「TEMP」という名前の値を取得する
string tempPathU = regKeyU.GetValue("temp", string.Empty,
RegistryValueOptions.DoNotExpandEnvironmentNames) as string;
WriteLine($"ユーザー TEMP={tempPathU}");
// 出力例:ユーザー TEMP=%USERPROFILE%\AppData\Local\Temp
' 展開前のシステムの環境変数「TEMP」を取得する
' システム環境変数が保管されているサブキーの名前
Const SystemEnvKeyName As String _
= "System\CurrentControlSet\Control\Session Manager\Environment"
' レジストリHKEY_LOCAL_MACHINEのサブキーを開く
Dim regKeyS As RegistryKey _
= Registry.LocalMachine.OpenSubKey(SystemEnvKeyName)
' サブキー内から「TEMP」という名前の値を取得する
Dim tempPathS As String _
= TryCast(regKeyS.GetValue("temp", String.Empty,
RegistryValueOptions.DoNotExpandEnvironmentNames),
String)
WriteLine($"システム TEMP={tempPathS}")
' 出力例:システム TEMP=%SystemRoot%\TEMP
' 展開前のユーザーの環境変数「TEMP」を取得する
' ユーザー環境変数が保管されているサブキーの名前
Const UserEnvKeyName As String = "Environment"
' レジストリHKEY_CURRENT_USERのサブキーを開く
Dim regKeyU As RegistryKey _
= Registry.CurrentUser.OpenSubKey(UserEnvKeyName)
' サブキー内から「TEMP」という名前の値を取得する
Dim tempPathU As String _
= TryCast(regKeyU.GetValue("temp", String.Empty,
RegistryValueOptions.DoNotExpandEnvironmentNames),
String)
WriteLine($"ユーザー TEMP={tempPathU}")
' 出力例:ユーザー TEMP=%USERPROFILE%\AppData\Local\Temp
GetEnvironmentVariables静的メソッドで全ての環境変数を取得した後は、並べ替えたり特定の環境変数を見つけ出したりするためにLINQ拡張が使えると便利だ。しかし、GetEnvironmentVariables静的メソッドが返してくるコレクションはジェネリックではないので、そのままでは便利なLINQ拡張を使えないのである。そんなときは、LINQ拡張のOfTypeメソッド(またはCastメソッド)を使ってジェネリックコレクションに変換すればよい(次のコード)。
// 取得したままの順で列挙(比較用)
IDictionary envVarsU
= Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User);
foreach (DictionaryEntry entry in envVarsU)
{
string name = entry.Key as string;
string value = entry.Value as string;
WriteLine($"{name}={value}");
}
// 出力例:
// TEMP=C:\Users\biac\AppData\Local\Temp
// Path=C:\Users\biac\AppData\Local\Microsoft\WindowsApps;C:\Users\……省略……;
// TMP=C:\Users\biac\AppData\Local\Temp
// OneDrive=C:\Users\biac\OneDrive
// ジェネリックコレクションに変換
IEnumerable<DictionaryEntry> entries = envVarsU.OfType<DictionaryEntry>();
// LINQ拡張でソートしてから列挙
foreach (DictionaryEntry entry in entries.OrderBy(e => e.Key))
{
string name = entry.Key as string;
string value = entry.Value as string;
WriteLine($"{name}={value}");
}
// 出力例:
// OneDrive=C:\Users\biac\OneDrive
// Path=C:\Users\biac\AppData\Local\Microsoft\WindowsApps;C:\Users\……省略……;
// TEMP=C:\Users\biac\AppData\Local\Temp
// TMP=C:\Users\biac\AppData\Local\Temp
' 取得したままの順で列挙(比較用)
Dim envVarsU As IDictionary _
= Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)
For Each entry As DictionaryEntry In envVarsU
Dim name As String = TryCast(entry.Key, String)
Dim value As String = TryCast(entry.Value, String)
WriteLine($"{name}={value}")
Next
' 出力例:
' TEMP=C:\Users\biac\AppData\Local\Temp
' Path=C:\Users\biac\AppData\Local\Microsoft\WindowsApps;C:\Users\……省略……;
' TMP=C:\Users\biac\AppData\Local\Temp
' OneDrive=C:\Users\biac\OneDrive
' ジェネリックコレクションに変換
Dim entries As IEnumerable(Of DictionaryEntry) _
= envVarsU.OfType(Of DictionaryEntry)()
' LINQ拡張でソートしてから列挙
For Each entry As DictionaryEntry _
In entries.OrderBy(Function(e) e.Key)
Dim name As String = TryCast(entry.Key, String)
Dim value As String = TryCast(entry.Value, String)
WriteLine($"{name}={value}")
Next
' 出力例:
' OneDrive=C:\Users\biac\OneDrive
' Path=C:\Users\biac\AppData\Local\Microsoft\WindowsApps;C:\Users\……省略……;
' TEMP=C:\Users\biac\AppData\Local\Temp
' TMP=C:\Users\biac\AppData\Local\Temp
アプリのプロセスに与えられた環境変数の値を取得するのは簡単にできる。システム環境変数やユーザー環境変数、あるいは、展開される前の環境変数の値を取得したいときには工夫が必要だ。
利用可能バージョン:.NET Framework 2.0以降
カテゴリ:クラス・ライブラリ 処理対象:Windows環境
使用ライブラリ:Environmentクラス(System名前空間)
使用ライブラリ:EnvironmentVariableTarget列挙体(System名前空間)
使用ライブラリ:Registryクラス(Microsoft.Win32名前空間)
使用ライブラリ:RegistryValueOptionsクラス(Microsoft.Win32名前空間)
関連TIPS:Windowsのシステム・フォルダのパスを取得するには?
関連TIPS:マシン名/ユーザー名を取得するには?
関連TIPS:OSやプロセスが64bitかどうかを調べるには?[4以降、C#、VB]
関連TIPS:Windows OSの種類やバージョンを判別するには?
関連TIPS:Windowsフォルダのパスやドライブ名を取得するには?
関連TIPS:ユーザーのフル・ネーム(表示名)を取得するには?[C#、VB]
関連TIPS:作業フォルダのパスを取得/設定するには?[C#、VB]
関連TIPS:常に管理者としてアプリケーションを実行させるには?
関連TIPS:Stringクラスにより文字列を文字列で分割するには?[2.0のみ、C#、VB]
関連TIPS:構文:クラス名を書かずに静的メソッドを呼び出すには?[C# 6.0]
関連TIPS:VB.NETでクラス名を省略してメソッドや定数を利用するには?
関連TIPS:数値を右詰めや0埋めで文字列化するには?[C#、VB]
Copyright© Digital Advantage Corp. All Rights Reserved.