I am looking for a way to get the paths of the My Documents folders from all users (each user) of a local machine. I found several articles, but they show how to do this for the current user.
I tested the code below, using SHGetKnownFolderPath, but it works only for the logged user. In the class ctor that receives a WindowsIdentity object, I create it with tokens of other users, but the paths returned were of the logged-in user.
Does anyone know how I could get the folders paths?
Thanks.
using Syroot.Windows.IO;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace ConsoleApplication2
{
class Program
{
private static Dictionary<KnownFolderType, KnownFolder> _knownFolderInstances;
static void Main(string[] args)
{
KnownFolderType type = KnownFolderType.Documents;
KnownFolder knownFolder = new KnownFolder(type);
//Ctor with WindowsIdentity parameter
//public KnownFolder(KnownFolderType type, WindowsIdentity identity)
//{
// Type = type;
// Identity = identity;
//}
// Write down the current and default path.
Console.WriteLine(knownFolder.Type.ToString());
try
{
Console.Write("Current Path: ");
Console.WriteLine(knownFolder.Path);
Console.Write("Default Path: ");
Console.WriteLine(knownFolder.DefaultPath);
}
catch (ExternalException ex)
{
// While uncommon with personal folders, other KnownFolders don't exist on every system, and trying
// to query those returns an error which we catch here.
Console.WriteLine("<Exception> " + ex.ErrorCode);
}
Console.ReadLine();
}
private static KnownFolder GetInstance(KnownFolderType type)
{
// Check if the caching directory exists yet.
if (_knownFolderInstances == null)
{
_knownFolderInstances = new Dictionary<KnownFolderType, KnownFolder>();
}
// Get a KnownFolder instance out of the cache dictionary or create it when not cached yet.
KnownFolder knownFolder;
if (!_knownFolderInstances.TryGetValue(type, out knownFolder))
{
knownFolder = new KnownFolder(type);
_knownFolderInstances.Add(type, knownFolder);
}
return knownFolder;
}
/// <summary>
/// The per-user Documents folder.
/// Defaults to "%USERPROFILE%\Documents".
/// </summary>
public static KnownFolder Documents
{
get { return GetInstance(KnownFolderType.Documents); }
}
}
}
KnownFolder.cs
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace Syroot.Windows.IO
{
/// <summary>
/// Represents a special Windows directory and provides methods to retrieve information about it.
/// </summary>
public sealed class KnownFolder
{
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="KnownFolder"/> class for the folder of the given type. It
/// provides the values for the current user.
/// </summary>
/// <param name="type">The <see cref="KnownFolderType"/> of the known folder to represent.</param>
public KnownFolder(KnownFolderType type)
: this(type, WindowsIdentity.GetCurrent())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="KnownFolder"/> class for the folder of the given type. It
/// provides the values for the given impersonated user.
/// </summary>
/// <param name="type">The <see cref="KnownFolderType"/> of the known folder to represent.</param>
/// <param name="identity">The <see cref="WindowsIdentity"/> of the impersonated user which values will be
/// provided.</param>
public KnownFolder(KnownFolderType type, WindowsIdentity identity)
{
Type = type;
Identity = identity;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets the type of the known folder which is represented.
/// </summary>
public KnownFolderType Type
{
get;
private set;
}
/// <summary>
/// Gets the <see cref="WindowsIdentity"/> of the user whose folder values are provided.
/// </summary>
public WindowsIdentity Identity
{
get;
private set;
}
/// <summary>
/// Gets or sets the default path of the folder.
/// This does not require the folder to be existent.
/// </summary>
/// <exception cref="ExternalException">The known folder could not be retrieved.</exception>
public string DefaultPath
{
get
{
return GetPath(KnownFolderFlags.DontVerify | KnownFolderFlags.DefaultPath);
}
set
{
}
}
/// <summary>
/// Gets or sets the path as currently configured.
/// This does not require the folder to be existent.
/// </summary>
/// <exception cref="ExternalException">The known folder could not be retrieved.</exception>
public string Path
{
get
{
return GetPath(KnownFolderFlags.DontVerify);
}
set
{
SetPath(KnownFolderFlags.None, value);
}
}
/// <summary>
/// Gets or sets the path as currently configured, with all environment variables expanded.
/// This does not require the folder to be existent.
/// </summary>
/// <exception cref="ExternalException">The known folder could not be retrieved.</exception>
public string ExpandedPath
{
get
{
return GetPath(KnownFolderFlags.DontVerify | KnownFolderFlags.NoAlias);
}
set
{
SetPath(KnownFolderFlags.DontUnexpand, value);
}
}
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Creates the folder using its Desktop.ini settings.
/// </summary>
/// <exception cref="ExternalException">The known folder could not be retrieved.</exception>
public void Create()
{
GetPath(KnownFolderFlags.Init | KnownFolderFlags.Create);
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private string GetPath(KnownFolderFlags flags)
{
IntPtr outPath;
int result = SHGetKnownFolderPath(Type.GetGuid(), (uint)flags, Identity.Token, out outPath);
if (result >= 0)
{
return Marshal.PtrToStringUni(outPath);
}
else
{
throw new ExternalException("Cannot get the known folder path. It may not be available on this system.",
result);
}
}
private void SetPath(KnownFolderFlags flags, string path)
{
int result = SHSetKnownFolderPath(Type.GetGuid(), (uint)flags, Identity.Token, path);
if (result < 0)
{
throw new ExternalException("Cannot set the known folder path. It may not be available on this system.",
result);
}
}
/// <summary>
/// Retrieves the full path of a known folder identified by the folder's known folder ID.
/// </summary>
/// <param name="rfid">A known folder ID that identifies the folder.</param>
/// <param name="dwFlags">Flags that specify special retrieval options. This value can be 0; otherwise, one or
/// more of the <see cref="KnownFolderFlags"/> values.</param>
/// <param name="hToken">An access token that represents a particular user. If this parameter is NULL, which is
/// the most common usage, the function requests the known folder for the current user. Assigning a value of -1
/// indicates the Default User. The default user profile is duplicated when any new user account is created.
/// Note that access to the Default User folders requires administrator privileges.</param>
/// <param name="ppszPath">When this method returns, contains the address of a string that specifies the path of
/// the known folder. The returned path does not include a trailing backslash.</param>
/// <returns>Returns S_OK if successful, or an error value otherwise.</returns>
/// <msdn-id>bb762188</msdn-id>
[DllImport("Shell32.dll")]
private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags,
IntPtr hToken, out IntPtr ppszPath);
/// <summary>
/// Redirects a known folder to a new location.
/// </summary>
/// <param name="rfid">A <see cref="Guid"/> that identifies the known folder.</param>
/// <param name="dwFlags">Either 0 or <see cref="KnownFolderFlags.DontUnexpand"/>.</param>
/// <param name="hToken"></param>
/// <param name="pszPath"></param>
/// <returns></returns>
/// <msdn-id>bb762249</msdn-id>
[DllImport("Shell32.dll")]
private static extern int SHSetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags,
IntPtr hToken, [MarshalAs(UnmanagedType.LPWStr)]string pszPath);
// ---- ENUMERATIONS -------------------------------------------------------------------------------------------
/// <summary>
/// Represents the retrieval options for known folders.
/// </summary>
/// <msdn-id>dd378447</msdn-id>
[Flags]
private enum KnownFolderFlags : uint
{
None = 0x00000000,
SimpleIDList = 0x00000100,
NotParentRelative = 0x00000200,
DefaultPath = 0x00000400,
Init = 0x00000800,
NoAlias = 0x00001000,
DontUnexpand = 0x00002000,
DontVerify = 0x00004000,
Create = 0x00008000,
NoAppcontainerRedirection = 0x00010000,
AliasOnly = 0x80000000
}
}
}
I figured it out. I got all SIDs from the system and then searched the Windows registry for each SID by the "Personal" key in the following format: "HKEY_USERS" + "SID" + "\ Software \ Microsoft \ Windows \ CurrentVersion \ Explorer \ Shell Folders \ Personal ". The "Personal" key retains the current path of each user's "My Documents" folder.
Get SIDs:
public static List<string> GetMachineSids()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_UserProfile");
var regs = searcher.Get();
string sid;
List<string> sids = new List<string>();
foreach (ManagementObject os in regs)
{
if (os["SID"] != null)
{
sid = os["SID"].ToString();
sids.Add(sid);
}
}
searcher.Dispose();
return sids.Count > 0 ? sids : null;
}
Get MyDocuments Path:
public static List<string> GetMyDocumentsPathAllUsers()
{
const string parcialSubkey = @"\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders";
string subkey = string.Empty;
const string keyName = "Personal";
//get sids
List<string> sids = GetMachineSids();
List<string> myDocumentsPaths = new List<string>();
if (sids != null)
{
foreach (var sid in sids)
{
//get paths
subkey = sid + parcialSubkey;
using (RegistryKey key = Registry.Users.OpenSubKey(subkey))
{
if (key != null)
{
Object o = key.GetValue(keyName);
if (o != null)
{
myDocumentsPaths.Add(o.ToString());
}
}
}
}
}
return myDocumentsPaths.Count > 0 ? myDocumentsPaths : null;
}
User contributions licensed under CC BY-SA 3.0