C# - C:\ProgramData と Everyoneフルコントール
はじめに
本記事では、Windows の C:\ProgramData
フォルダについて記載します。
その後、関連する情報として、フォルダのアクセス権限を Everyone フルコントールにする C# サンプルコードを掲載します。
テスト環境
ここに記載した情報/ソースコードは、Visual Studio Community 2022 を利用した下記プロジェクトで生成したモジュールを Windows 11 24H2 で動作確認しています。
- Windows Forms - .NET Framework 4.8
- Windows Forms - .NET 8
- WPF - .NET Framework 4.8
- WPF - .NET 8
データ格納フォルダ
特殊フォルダ
プロダクト(アプリケーション)のデータ格納フォルダとして、以下が定義されています。
- Environment.SpecialFolder.CommonApplicationData
- すべてのユーザが使用するプロダクト固有のデータを格納する共通フォルダ
- 通常は全ユーザで書き込み可能ですが、特定の条件下では管理者権限が必要となる場合もあります
- 実体バス:
C:\ProgramData
- 隠しフォルダとして扱われているため、エクスプローラでは「隠しファイル:表示」にしないと表示されません
- Environment.SpecialFolder.ApplicationData
- カレントユーザのプロダクト固有のデータを格納するフォルダ
- 該当ユーザにフルコントールが付与されています
- 実体バス:
C:\Users\<ユーザ名>\AppData\Roaming
string programdata = Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
string appdata = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData);
Console.WriteLine($"CommonApplicationData: {programdata}");
Console.WriteLine($"ApplicationData: {appdata}");
各プロダクトでは、これらのフォルダ下に 会社名\プロダクト名
もしくは プロダクト名
というフォルダを作成して、各種データを格納します。
会社名:Hoge、プロダクト名:FooBar
C:\ProgramData\Hoge\Foobar
C:\Users\<ユーザ名>\AppData\Roaming\Hoge\Foobar
データ格納フォルダをインストールフォルダと別に用意する理由のひとつは、プロダクトのアンインストール時にデータを維持できるようにするためです。
CommonApplicationData
一般的には、インストーラ(UAC により昇格された管理者権限で実行)によって、CommonApplicationData 配下にプロダクト用のフォルダを作成し、用途に応じたサブフォルダを作成します。
これらは、用途にあわせて、次のようなアクセス権限を設定します。
対象サブフォルダの用途 | アクセス権限 |
---|---|
構成ファイルやテンプレートなど参照のみのデータを格納 | 一般ユーザは読み取りのみ可 |
ログや共有データなど更新するデータを格納 | Everyone フルコントール |
Windows の基本的な設計方針としては、ApplicationData を使用してユーザごとに変化するデータ(設定ファイル、キャッシュなど)を管理することが推奨されています。
この場合、インストール時に作成された初期設定を CommonApplicationData 配下に格納し、アプリケーション初回起動時にユーザの ApplicationData にコピーして、以降はユーザごとに個別に管理するといった方法が考えられます。
一方で、CommonApplicationData を用いて、すべてのユーザが共有して更新可能なデータを扱うこともあります。
この場合、インストーラによって対象フォルダやそのサブフォルダに Everyone フルコントールを明示的に付与することで、全ユーザでの書き込みを保証することができます。
Everyone フルコントール
// 指定フォルダを Everyone フルコントール
// 権限不足とならないように管理者権限で実行が望ましい
private void SetFullAccessForFolder(string folder)
{
// フォルダ存在確認
if (!Directory.Exists(folder))
{
try
{
// 対象フォルダ存在しないので作成
Directory.CreateDirectory(folder);
}
catch (UnauthorizedAccessException)
{
// TODO - 権限不足
Console.WriteLine("フォルダ作成エラー: 権限不足");
return;
}
catch (SecurityException)
{
// TODO - セキュリティ例外
Console.WriteLine("フォルダ作成エラー: セキュリティ例外");
return;
}
}
try
{
// Everyone
var everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
// 現在のアクセス権取得
var directoryInfo = new DirectoryInfo(folder);
var security = directoryInfo.GetAccessControl();
// LINQ を利用してすでに Everyone フルコントロール権限があるか判定
bool bAlready = security
.GetAccessRules(true, true, typeof(SecurityIdentifier))
.Cast<FileSystemAccessRule>()
.Any(rule => rule.IdentityReference.Value == everyone.Value
&& (rule.FileSystemRights & FileSystemRights.FullControl)
== FileSystemRights.FullControl);
// 未付与時にフルコントロール付与
if (!bAlready)
{
var newRule = new FileSystemAccessRule(
everyone, FileSystemRights.FullControl,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None, AccessControlType.Allow);
// アクセス権限付与
security.AddAccessRule(newRule);
directoryInfo.SetAccessControl(security);
}
}
catch (UnauthorizedAccessException)
{
// TODO - 権限不足
Console.WriteLine("アクセス権制御エラー: 権限不足");
return;
}
catch (SecurityException)
{
// TODO - セキュリティ例外
Console.WriteLine("アクセス権制御エラー: セキュリティ例外");
return;
}
}
以下のように利用します。
string programdata = Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
string company = "Hoge"; // TODO
string product = "FooBar"; // TODO
string settings = "CommonSettings"; // TODO
SetFullAccessForFolder($@"{programdata}\{company}\{product}\{settings}");
出典
本記事は、2025/06/23 Qiita 投稿記事の転載です。
Discussion