Summary: Learn how to use Windows PowerShell drives to simplify access to complex data storage paths.
Hey, Scripting Guy! I like using PSDrives. Unfortunately, a problem I have is that I never really know where I am at in the hierarchy. For example, if I am on my fso drive, where does that drive happen to be? Can you provide me with some special Scripting Guy tricks to help me with this problem? I earnestly await your reply.
—CL
Hello CL,
Microsoft Scripting Guy Ed Wilson here. I recently made a presentation for a group of Windows PowerShell enthusiasts, and one of the things I showed them was the concept of PSDrives. In fact, I think it is one of the revolutionary concepts that are exposed by Windows PowerShell. The ability to use the same Windows PowerShell cmdlets to work with disparate data sources is simply amazing. That I can use Get-ChildItem and retrieve a list of registry keys, certificates, files, folders, variables, aliases, and environmental variables makes Windows PowerShell truly a power(ful) shell.
I love creating custom PSDrives to simplify access to my Hey, Scripting Guy! Blog posts and scripts. To do this, I use the New-PSDrive cmdlet, specify the name of the provider (filesystem), and provide it with the name of the drive and the path to the root of the new drive. Here is the command I use on my laptop to create my special HSG drive:
New-PSDrive -PSProvider filesystem -Root C:\data\ScriptingGuys\2011 -Name hsg
When the command runs, it returns information about the newly created drive. The information is contained in the PSDriveInfo object that is shown here:
14:39:01 C:\> New-PSDrive -PSProvider filesystem -Root C:\data\ScriptingGuys\2011 -Name hsg | gm
TypeName: System.Management.Automation.PSDriveInfo
Name MemberType Definition
CompareTo Method int CompareTo(System.Management.Automation.PSDriveInfo drive), in...
Equals Method bool Equals(System.Object obj), bool Equals(System.Management.Aut...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Credential Property System.Management.Automation.PSCredential Credential {get;}
CurrentLocation Property System.String CurrentLocation {get;set;}
Description Property System.String Description {get;set;}
Name Property System.String Name {get;}
Provider Property System.Management.Automation.ProviderInfo Provider {get;}
Root Property System.String Root {get;}
Free ScriptProperty System.Object Free {get=## Ensure that this is a FileSystem drive...
Used ScriptProperty System.Object Used {get=## Ensure that this is a FileSystem drive...
After I have created my new PSDrive, I can change my working directory location to that drive. By changing my working directory, I gain easy access to the files and folders in that location. To change location to a new drive, I can use the Set-Location cmdlet and provide it with the name of the new PSDrive. In addition, to using the cmdlet name directly, there are three aliases that can also be used from the command line: cd, chdir, and sl. The following command uses the alias cd to change the working location to the hsg PSDrive. The Windows PowerShell prompt changes to reflect the new location (I have a custom Windows PowerShell prompt that displays the current time as well as the current location):
14:56:50 C:\> cd hsg:
14:57:44 hsg:\>
If I want to return to the C: drive, I can once again use the cd alias:
14:57:44 hsg:\> cd c:
15:00:31 C:\>
I use the up arrow to retrieve my previous command and return to the HSG drive. When I am on my HSG drive, I can use the Get-Location cmdlet to retrieve my current location. The default view returns only the path, as shown here:
15:03:30 hsg:\> Get-Location
Path
----
hsg:\
Okay, I will admit the default is basically useless when working interactively from the Windows PowerShell console because the default Windows PowerShell prompt includes the current location. However, as with everything else in Windows PowerShell, the Get-Location cmdlet returns an object. This means there are additional properties and methods that are available. A quick use of the Get-Member cmdlet shows me there are some interesting properties that could be helpful. The command to retrieve the members from the PathInfo object is shown here along with the associated output:
15:04:14 hsg:\> Get-Location | gm
TypeName: System.Management.Automation.PathInfo
Name MemberType Definition
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Drive Property System.Management.Automation.PSDriveInfo Drive {get;}
Path Property System.String Path {get;}
Provider Property System.Management.Automation.ProviderInfo Provider {get;}
ProviderPath Property System.String ProviderPath {get;}
The property that looks interesting to me is the ProviderPath property. To see if this will help me to resolve the actual path to the PSDrive, I pipe the output to the Format-List cmdlet. The command and associated output are shown here:
15:04:20 hsg:\> Get-Location | fl *
Drive: hsg
Provider: Microsoft.PowerShell.Core\FileSystem
ProviderPath: C:\data\ScriptingGuys\2011\
Path: hsg:\
Because the ProviderPath is a property of the PathInfo object, it means I can access it directly by using a dotted notation. The command to display only the value contained in the ProviderPath property is shown here along with the associated output:
15:04:32 hsg:\> (Get-Location).providerpath
C:\data\ScriptingGuys\2011\
The Convert-Path cmdlet knows how to convert a PSDrive for a file system location to the actual path to that filesystem location. In the following command, I use the Convert-Path cmdlet to convert the path to the HSG: drive:
15:17:20 hsg:\> Convert-Path -Path HSG:
C:\data\ScriptingGuys\2011\
It might be possible that I do not know where my actual working directory resides—or even what it is. This may be the situation when running inside a script. I can therefore use the Get-Location cmdlet to find out where my current working directory resides, and pass it to the Convert-Path cmdlet. The command and the associated output are shown here:
15:20:19 hsg:\> Convert-Path -Path (Get-Location)
C:\data\ScriptingGuys\2011\
If I am looking for PSDrives, I can use the Get-PSDrive cmdlet. If I do not supply any parameters, it will return all of the PSDrives on the system. However, because I am only concerned with PSDrives that are associated with the filesystem, I can specify that I only want PSDrives from the filesystem PSProvider. The command to return only PSDrives that are associated with the filesystem PSProvider is shown here:
Get-PSDrive -PSProvider filesystem
The command and associated output are shown in the following figure.
When switching working locations, I like to use the Push-Location cmdlet (alias is pushd) and Pop-Location (alias is popd) to store my current location, switch to another location, and then return to the previous location. As a simple example, I am going to store my current location (current c:\), change the working location to the HSG: drive, get a directory output, and then return to my original location (c:\). Here are the commands that accomplish these tasks:
Push-Location
Set-Location hsg:
Get-ChildItem
Pop-Location
In the following figure, I use aliases to accomplish these tasks. The figure includes the commands and the associated output.
As long as I am talking about Windows PowerShell cmdlets that help in working with paths and locations, I may as well talk about the Resolve-Path cmdlet. It is cool and very powerful when working at the Windows PowerShell console. It allows me to use wildcard characters in path names, and it will resolve the path and output all the paths that match the wildcard character pattern. An example of this technique is shown here:
15:58:30 C:\> Resolve-Path c:\da*\*\*11
Path
C:\data\BookScripts_VbScript\ch11
C:\data\Presentation\RoadToTechEd_2011
C:\data\Presentation\TechReady_2011
C:\data\ScriptingGuys\2011
The output from the Resolve-Path cmdlet returns the same PathInfo objects that were returned earlier. This means that I can use the Where-Object cmdlet to find only paths that are related to scripting. This command is shown here (? Is an alias for the Where-Object cmdlet):
Resolve-Path c:\da*\*\*11 | ? { $_.path -match 'scripting'}
I could even send the output to a ForEach-Object cmdlet and use the Get-ChildItem cmdlet to query each of the returned paths. The command to perform this action is shown here (the % symbol is an alias for ForEach-Object and gci is an alias for Get-ChildItem):
Resolve-Path c:\da*\*\*11 | ? { $_.path -match 'scripting'} | % {gci $_.path}
CL, that is all there is to working with paths and PSDrives in Windows PowerShell. Thank you for your question, and I invite you to join me for more cool stuff with Windows PowerShell.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy