runtime: Environment.GetFolderPath() doesn't support all KNOWNFOLDERID's

(Redirecting from (https://github.com/PowerShell/PowerShell/issues/11240))

It should be possible to retrieve the location of all “special folders” instead of hardcoding them (or assuming they are just subfolders of the user’s profile folder).

As of today, Environment.GetFolderPath() (which reportedly relies on SHGetKnownFolderPath()) doesn’t support all KNOWNFOLDERID’s. Here’s a few of the ones that are not supported:

FOLDERID_Downloads
FOLDERID_DocumentsLibrary
FOLDERID_CameraRoll

This piece of code

using System;

namespace GetFolderPath
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (Environment.SpecialFolder folder in (Environment.SpecialFolder[]) Enum.GetValues(typeof(Environment.SpecialFolder)))
            {
                Console.WriteLine("{0,-30}{1}", folder, Environment.GetFolderPath(folder));
            }
        }
    }
}

outputs only this subset of folder paths:

Desktop                       C:\Users\joe\Desktop
Programs                      C:\Users\joe\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
MyDocuments                   C:\Users\joe\Documents
MyDocuments                   C:\Users\joe\Documents
Favorites                     C:\Users\joe\Favorites
Startup                       C:\Users\joe\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
Recent                        C:\Users\joe\AppData\Roaming\Microsoft\Windows\Recent
SendTo                        C:\Users\joe\AppData\Roaming\Microsoft\Windows\SendTo
StartMenu                     C:\Users\joe\AppData\Roaming\Microsoft\Windows\Start Menu
MyMusic                       C:\Users\joe\Music
MyVideos                      C:\Users\joe\Videos
DesktopDirectory              C:\Users\joe\Desktop
MyComputer                    
NetworkShortcuts              C:\Users\joe\AppData\Roaming\Microsoft\Windows\Network Shortcuts
Fonts                         C:\windows\Fonts
Templates                     C:\Users\joe\AppData\Roaming\Microsoft\Windows\Templates
CommonStartMenu               C:\ProgramData\Microsoft\Windows\Start Menu
CommonPrograms                C:\ProgramData\Microsoft\Windows\Start Menu\Programs
CommonStartup                 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
CommonDesktopDirectory        C:\Users\Public\Desktop
ApplicationData               C:\Users\joe\AppData\Roaming
PrinterShortcuts              
LocalApplicationData          C:\Users\joe\AppData\Local
InternetCache                 C:\Users\joe\AppData\Local\Microsoft\Windows\INetCache
Cookies                       C:\Users\joe\AppData\Local\Microsoft\Windows\INetCookies
History                       C:\Users\joe\AppData\Local\Microsoft\Windows\History
CommonApplicationData         C:\ProgramData
Windows                       C:\windows
System                        C:\windows\system32
ProgramFiles                  C:\Program Files
MyPictures                    C:\Users\joe\Pictures
UserProfile                   C:\Users\joe
SystemX86                     C:\windows\SysWOW64
ProgramFilesX86               C:\Program Files (x86)
CommonProgramFiles            C:\Program Files\Common Files
CommonProgramFilesX86         C:\Program Files (x86)\Common Files
CommonTemplates               C:\ProgramData\Microsoft\Windows\Templates
CommonDocuments               C:\Users\Public\Documents
CommonAdminTools              C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools
AdminTools                    C:\Users\joe\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Administrative Tools
CommonMusic                   C:\Users\Public\Music
CommonPictures                C:\Users\Public\Pictures
CommonVideos                  C:\Users\Public\Videos
Resources                     C:\windows\resources
LocalizedResources            
CommonOemLinks                
CDBurning                     C:\Users\joe\AppData\Local\Microsoft\Windows\Burn\Burn

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 4
  • Comments: 55 (21 by maintainers)

Commits related to this issue

Most upvoted comments

But I can’t tell you if Windows 7 is planned to be dropped in .NET 7 / 8 / whenever this feature will make the cut.

I can’t offer an official word, but I know of no plans to drop Windows 7 support in .NET 7 given it remains in extended support until 2023

Thank you for checking on the folder names and other discussions.

I’m still sorting my notes a bit from the many comments written throughout the years, but have updated mine above (which I slightly use as my blueprint for an API proposal):

  • Name it SpecialFolder.Downloads, not SpecialFolder.MyDownloads
  • Let #63214 handle the “Movies” MyVideo folder bug on macOS (together with some others).
  • Do not touch VB SpecialDirectories class.

For simplicity, at the moment I’d prefer to only focus on the “missing user folders” common to Linux / macOS / Windows, e.g. “Downloads” and “Public” (despite the latter not being a user-specific folder on Windows, but I think that is neglectible since everyone has access to it by default).

In the interest of pushing this forward I’ve put together a spreadsheet of all the KnownFolderIds that are missing, as well as whether they’re usable on *nix or mac.

What I don’t have is a good way to collaborate on these, as I’m not a mac or *nix user so I’m not sure what the sane defaults would be.

(read-only view of the spreadsheet) https://1drv.ms/x/s!Aqd0GRdPyzYske0aoWS8kUiTamIu7A?e=bBfntf

One thing that struck me as a bit odd while I was working on this is that MyComputer is a valid SpecialFolder. This is the only KnownFolderId which is marked as a Virtual folder, and I don’t think it will EVER return a valid path on Windows.

Yeah, from my first uneducated look on that it seems that Personal/MyDocuments is “incorrect” on Android too. Should go in sync with your existing changes on macOS / Linux. Also, I’m not sure why UserProfile is retrieved from the HOME environment variable unlike the home path in that method itself using PersistedFiles.GetHomeDirectory(); even if there are technical reasons, the naming is very confusing to say the least.

I’ll definitely wait until you finished your changes to not clash with them, and then update my post above to include Android. New special folders have been asked for since their introduction in Windows Vista, they can certainly wait a bit more 😃

Yeah, whenever I mentioned “Unix”, I meant both macOS and Linux. And I agree, adding exceptionally much magic for determining these folder’s names or getting them localized is not meaningful here.

After this discussion and my own personal reconsideration, I updated my recap to return empty paths on those systems. After all, the reason the public subfolders were added was only because they are important on Windows. 😃

EDIT: Now my last bullet “Other “special” folders (like Windows’ “Saved Games” or “Public Desktop”) are not included due to them having no meaningful cross-platform counterpart.” looks a little dumb. I could just aswell add those folders for Windows-only now.

Yes, I’ve mentioned this in the "foot"notes under the table, footnote 4 specifically. Indeed ‘or’ is just to save space in the table, I linked to the existing code in footnote 1.