Easily Finding Special Paths for PowerShell Scripts
Paths to key operating system and user folders aren’t always standardized
November 18, 2011
Even in the most standardized networks, it's easy to specify the incorrect paths to special folders such as My Documents or temporary folders that havespecial roles in Windows. Fortunately, you can ask Windows where particular folders are located. After I explain the root of the problem, I'll show youhow to make Microsoft PowerShell scripts consistently find the right path, even in nonstandard setups.
Understanding the Problem
Although working with files and folders is a standard task for network administrators, the specific paths to those folders aren't standard. Windowsinstallations, upgrades, hardware installations, user policies, and machine policies can all lead to wildly varying paths for special folders. Even instandardized networks, variations are possible due to machine roles or user requirements.
Some of these paths are relatively easy to find with PowerShell variables. For example, the $home variable always contains the literal path to a user'shome folder. However, finding other paths might require some guesswork. For example, if your users are mainly running Windows 7 or Windows Vista, youcould try accessing the folder that contains temporary Internet files by using the path $homeAppDataLocalMicrosoftWindowsTemporary InternetFiles. However, this path will fail for users running an earlier Windows OS or if their temporary Internet files are redirected to a differentlocation. Standardizing isn't always possible, and coding in all sorts of checks for special cases will end up being cumbersome and confusing.
Fortunately, there's an easier way. Instead of guessing, you can use the Microsoft .NET Framework's System.Environment class to obtain paths. By usingthe OS APIs, you have access to more information than you can get from environment variables alone. The information is also more reliable becauseWindows uses the same technique to determine paths.
Using System.Environment in PowerShell
In PowerShell, you specify a .NET class by using its name in square brackets, like this: [System.Environment]. To simplify using the System namespace,PowerShell lets you omit the System. portion, so you can use [Environment] for brevity.
To find the paths of special folders, the first step is to determine what special folders are exposed. The Environment class has a special enumeratedlist of the canonical names for these folders. A quick way to show these names is to use the command
[Environment+SpecialFolder]::GetNames([Environment+SpecialFolder])
In Windows 7, this command returns a list of names like that shown in Figure 1. You can find the meanings of these names in the"Environment.SpecialFolder Enumeration" web page. Note that some of thespecial folders listed in this web page aren't available within PowerShell.
Figure 1: Special folders’ canonical names
At the bottom of the "Environment.SpecialFolder Enumeration" web page, you'll find a PowerShell script by Thomas Lee demonstrating how to list thespecial folders' names and their paths. There are two details you should know about accessing these folders. First, if a folder doesn't exist, you'llget an empty path back. Second, some folders might not be accessible from an unprivileged account.
Thomas Lee's script works well if you just want to see the names and paths. However, what can you do if you want to easily use those paths in scripts?There are many possible approaches. I'll show you three of them. Each is useful in different situations, but all of them require that you understandwhat the names like ProgramFiles or Startup mean, as defined in the "Environment.SpecialFolder Enumeration" web page.
Suppose you want to access a specific folder, such as the one named Desktop. In PowerShell syntax, the ID of this specific folder is[Environment+SpecialFolder]::Desktop. You provide this ID as an argument to the Environment class's static GetFolderPath method, like this
[Environment]::GetFolderPath("Desktop")
This command returns the exact path to the current user's Desktop folder.
To get an entire list of folders and their paths (which are accessible by name), you can use the code in Listing 1. It creates a hash table named$SpecialFolders, gets the names of all the special folders known to the .NET Framework, then gets the paths of those folders. The code adds eachnon-empty special folder path to the hash table, indexed by the folder name. You can see the contents of the hash table by simply entering$SpecialFolders after the PowerShell prompt and pressing Enter. Figure 2 shows sample results from running the code in Listing 1.
Figure 2: Special folders’ names and paths in a hash table
Turning Special Folders Into Drives
The technique that I like to use is to create PowerShell drives from each special folder path, using the canonical folder name as the drive name. Thecode in Listing 2 creates named drives from the special folder paths, producing output that will look similar to Figure 3, depending on your system.It's then possible to access items using these drive names without having to think about user context or actual paths. You can see the drives' actualpaths by running the code
Get-PSDrive | ft name,root -AutoSize
Figure 3: PowerShell drives with mappings for special folders
When you need to perform tasks in one of the special folders, you just need to specify the drive name. For example, if you need to copy the entire setof Favorites items in Microsoft Internet Explorer (IE) to a folder on the F drive, you'd run the command
Copy-Item -Path Favorites: -Destination F:Favorites -Recurse
If you want to list the last 20 documents accessed in reverse chronological order, you'd use the command
gci Recent: | Sort-Object -Property LastWriteTime -Descending
The code in Listing 3 finds the largest 10 files in the Documents folder and shows them in descending order based on size. The output includes the lasttime the files were modified (LastWriteTime) so that you can determine if any of the files are currently being edited. The code in Listing 4 retrievesthe display name and URL for each Favorite item in IE, generating a scrollable list with spaces between items for easy reading.
Considering Other Methods
In my experience, I've found that using System.Environment is the most reliable technique for finding a path to a special folder. Creating PowerShelldrives from these paths makes this technique very useful. However, sometimes you might not be able to find what you need this way. Although I won't gointo detail about them, there are alternatives.
As I mentioned previously, you can try constructing a path using standard PowerShell variables (or shell variables accessible through the env: drive)and some guesswork. However, this technique is much less reliable. At the very least, you should use PowerShell's Test-Path cmdlet to confirm that thepath actually exists.
Another technique that's a little more complicated but gives access to even more special folders is to use the Shell.Application COM object's NameSpacemethod. You can also use this method in Windows Script Host (WSH) scripts. To explore this technique, search the Internet using Shell.Application andNameSpace as the search terms.
Overall, my preferred method remains creating PowerShell drives using the code in Listing 2. It lets me concentrate on the task I'm trying toaccomplish instead of the mechanics for performing it.
Listing 1: Code to Create a Hash Table That Contains Special Folders’ Names and Paths
$SpecialFolders = @{}
$names = [Environment+SpecialFolder]::GetNames( `
[Environment+SpecialFolder])
foreach($name in $names)
{
if($path = [Environment]::GetFolderPath($name)){
$SpecialFolders[$name] = $path
}
}
Listing 2: Code to Create Named Drives from Special Folders’ Paths
$names = [Environment+SpecialFolder]::GetNames( `
[Environment+SpecialFolder])
foreach($name in $names)
{
if($path = [Environment]::GetFolderPath($name)){
New-PSDrive -Name $name -PSProvider FileSystem -Root $path
}
}
Listing 3: Code to Find the 10 Largest Files in the Documents Folder
gci Personal: -Recurse -Force -ea SilentlyContinue |
Sort-Object -Property Length -Descending |
Select-Object -First 10 |
Format-Table -AutoSize -Wrap -Property `
Length,LastWriteTime,FullName
Listing 4: Code to Display the Name and URL for Each Favorite Item in IE
gci -Path Favorites: -Recurse |
?{$_.Length} |
%{$_.BaseName; Get-Content $_.FullName |
Select-String ^url=*|
%{$_ -replace "^url=","" ;""}
}
About the Author
You May Also Like