1. トップ
  2. 新着ニュース
  3. IT
  4. IT総合

Windowsの「デスクトップ」や「ピクチャ」など、「既知のフォルダ(Known Folders)」を使う方法

ASCII.jp / 2023年4月30日 10時0分

 Windowsには、標準で作られるフォルダーがある。たとえば「デスクトップ」や「ピクチャ」といったものだ。これらは「既知のフォルダ」(Known Folders)と呼ばれている。既知のフォルダには、ファイルシステム上のパスと対応するディレクトリ(通常フォルダー)もあれば、実体を持たない(あるいは複数のディレクトリから構成される)特殊なフォルダー(仮想フォルダー)もある。

 「既知のフォルダ」のうち、ファイルシステム上のパスを持つディレクトリのいくつかは、パスを変更することが可能だ。前述のドキュメントやピクチャは、プロパティの「場所」タブで、移動させることができる。

「既知のフォルダ」は、プロパティにある「場所」タブで、他の場所に移動させることができる。このため、環境ごとに実パスが異なる可能性がある。また、サーバーとクライアント、エディション、言語などにより表示される名称も異なる

 また、OneDriveなどのWindowsの機能により、既知のフォルダの場所を変更することがある。つまり、既知のフォルダのパスには、既定値はあるものの、マシンやユーザーごとに異なる可能性がある。このため、既知のフォルダにアクセスする場合、現在の環境におけるパスを取得する必要がある。

そもそも「既知のフォルダ」とは?

 既知のフォルダに関しては、以前にこの連載でも扱っている。Windows 10 RS5(October 2018 Update)で発生したフォルダ消失のトラブルに関してだ。このトラブルの原因が「既知のフォルダ」だった(「Windows 10「October 2018 Update」でファイル消失の原因になったKnown Foldersって何?」)。

 Windowsでは、以前から標準のフォルダ構成がある。たとえば、Windowsは「C:\Windows」にインストールされ、プログラムは「C:\Program Folders」といった具合だ。しかし、こうした標準フォルダは、Windowsのバージョンやエディション、種類(クライアントかサーバーか)で異なるケースもある。最初は環境変数の初期値で実際の場所を示していた。当時は、すべての標準フォルダがファイルシステム上のディレクトリとして存在していたからである。

 しかし、Windows 95(1995年)/Windows NT 4.0(1996年)で、CSIDL(Constant Special item ID List)が導入された。理由の1つとしては、標準フォルダ構成がWindowsのバージョンなどで異なり、その数が増えてしまったこと(当時のWindowsはサービス終了期限が定められていなかった)。

 もう1つは、Windows 95でフォルダが導入されて、ディレクトリと特殊フォルダ(仮想フォルダ)が存在するようになったため、ファイルシステム上にユニークなパスを持たないフォルダができたからだ。たとえば、「ゴミ箱」は特殊なフォルダであり、ユーザーがエクスプローラーから見るものと、実際のディレクトリ内容(コマンドラインで表示されるもの)が異なっている。

 CSIDLでは、定数を使って標準フォルダからのパスを取得し、これを使ってフォルダにアクセスする。CSIDLには、パスを持たない特殊フォルダがあるが、そのパスを取得することはできず、専用のAPIなどを使ってアクセスする。

 Windows Vista(2006年)では、CSIDLに代わって「既知のフォルダ」(Known Folders)という仕組みが導入され、CSIDLによるアクセスは既知のフォルダの機能を使って実現されるようになった。ただ、互換性のため、現在でもCSIDLによるアクセスは可能である。

 既知のフォルダが扱う対象のリストは、以下にある。

●KNOWNFOLDERID (Knownfolders.h) - Win32 apps  https://learn.microsoft.com/ja-jp/windows/win32/shell/knownfolderid

 また、アプリケーションが独自の「既知のフォルダ」を作成することもできる。プログラムを使って、内容をエクスプローラーに表示する特殊フォルダを既知のフォルダとすることで、標準フォルダと同じ方法で移動などをさせることが可能になる。

 「既知のフォルダ」では、対象をGUIDで指定する。しかし、この方法は面倒であり、いまだにCSIDL定数によるアクセスが使われることが多い。というのも、上記のKNOWNFOLDERIDのうち、ファイルシステム上のパスに割り当てられているもののほとんどがCSIDLにも存在していたものだからだ。これは、対象をCSIDLの定数で指定するのみで、実際の処理は、.NETもしくは.NET Frameworkのオブジェクトがするため、将来的なAPIの変更には影響されない(はずである)。

「既知のフォルダ」パスを調べる

 Windows 11では、既知のフォルダの実環境のパスを得る複数のAPIが用意されている。1つは、COMのIKnownFolderとIKnownFolderManagerインターフェースを使う方法だ。もう1つは、WinRTのWindows.Storage.KnownFoldersクラスを使うもの、あるいはWin32APIのシェル関数SHGetKnownFolderPathを使う方法などがある。しかし、これらは、どれもC++やC#などでプログラムを書かねばならず、「簡単」に使えるというものでもない。

 Windows PowerShell(あるいはPowerShell 7.x)から簡単に既知のフォルダのパスを得る方法として、.NETの「System.Environment」クラスの「GetFolderPath」メソッドがある。具体的には、以下のようになる。

[Environment]::GetFolderPath('Desktop')

PowerShellで「[Environment]::GetFolderPath」を使うことで、「既知のフォルダ」の現在の環境での実パスを求めることができ、カッコで囲めば、他のコマンドの引数に利用できる。既知のフォルダを指定する列挙値は、「[Environment+SpecialFolder]」に定義されていて、「[Enum]::GetNames」で一覧を得られる(撮影の都合でselectコマンドで出力数を制限している)

 上記は、デスクトップのパスを得る方法である。パラメーターとして指定可能な既知のフォルダは、実パスを持つもの(仮想フォルダーでないもの)に限定されており、CSIDL名を使う。その一覧は、以下にある。

●Environment.SpecialFolder 列挙型  https://learn.microsoft.com/ja-jp/dotnet/api/system.environment.specialfolder?redirectedfrom=MSDN&view=netframework-4.8.1

 ここにある「フィールド」の表の先頭の文字列か、次の列にある数字を指定する。たとえば、デスクトップなら「GetFolderPath(0)」でもよい。実はこの数字がCSIDLで使われていた定数である。カッコで囲んでおけば、戻ってくるパスを他のPowerShellコマンドの引数にできる。

 この列挙型自体は、PowerShellからは「[Environment+SpecialFolder]」としてアクセスでき、「[Environment+SpecialFolder]::desktop」とすることでデスクトップフォルダを指定できる。

[Environment]::GetFolderPath([Environment+SpecialFolder]::Desktop)

 「[Environment+SpecialFolder]」を使う方法は、面倒そうに見えるが、補完機能が使えるため、カッコ中の「::」の後ろで「D」キーを押したあとタブキーで補完候補を出せる。このクラスで開くことができる「既知のフォルダ」の一覧を得たければ

[Enum]::GetNames([Environment+SpecialFolder])

とする。

 日本語の場合、既知のフォルダには、ローカライズされた名称がつく。たとえば、「MyPicture」は「ピクチャ」となる。これを得るには、COMオブジェクト「Shell.Application」を作り、その“NameSpace”から実パスを使って日本語名を探す。

$shell = New-Object -ComObject Shell.Application $shell.NameSpace([Environment]::GetFolderPath('mypicture')) | select title

 残念ながらcmd.exeには、既知のフォルダのパスを得るためのコマンドはないが、pwsh.exe(PowerShell)、powershell.exe(Windows PowerShell)をコマンドとして使い、forコマンドで環境変数に入れる。具体的には以下のようになる。

for /f "usebackq delims=" %A in (`pwsh.exe -noprofile -command "[Environment]::GetFolderPath('Desktop')"`) do set MYP=%A

 これで環境変数“MYP”にデスクトップフォルダーのパスが入る。

cmd.exeには、既知のパスを扱うコマンドはない。だがPowerShell(pwsh.exe)やWindows PowerShell(powershell.exe)のコマンドラインから直接「[Environment]::GetFolderPath」を実行させることで、実パスを得ることができる。これをFORコマンドの逆クオートで実行させて、環境変数に設定できる

 既知のフォルダは、利用頻度が高く、スクリプトなどからもアクセスすることも多い。しかし、スクリプトの可用性や相互運用性を考えると、パスを決め打ちすることはできない。その場合、CSIDL名や番号を使って、パスを得る必要がある。それほど難しいことではないので、1回パターンを覚えれば、使い回しが可能だ。

この記事に関連するニュース

トピックスRSS

ランキング

記事ミッション中・・・

10秒滞在

記事にリアクションする

記事ミッション中・・・

10秒滞在

記事にリアクションする

デイリー: 参加する
ウィークリー: 参加する
マンスリー: 参加する
10秒滞在

記事にリアクションする

次の記事を探す

エラーが発生しました

ページを再読み込みして
ください