Creating PowerShell Drives for Fun and Profit

Creating PowerShell Drives for Fun and Profit

  • Comments 5
  • Likes

Summary: Learn different ways to work with Windows PowerShell drives, including using WMI to find the root.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I have been trying to grasp this idea of Windows PowerShell drives. I am not certain how they are useful, or how I can find information about them. Can you help?

—BP

 

Hey, Scripting Guy! AnswerHello BP,

Microsoft Scripting Guy Ed Wilson here. Of course, I can help. I wrote about PSDrives three weeks ago, so you may want to refer to that article for additional information about PSDrives.

The first thing to understand about PSDrives is that PSDrives are used as a way to abstract the complexity of accessing different types of information. As I mentioned yesterday, Windows PowerShell providers are used to perform the abstraction; PSDrives provide the way to interact with that data. The cool thing about Windows PowerShell providers is they do not need to be written by the Windows PowerShell team; using the software development kit (SDK), anyone can write their own Windows PowerShell provider and expose data sources to the Windows PowerShell user. For example, someone could write a Windows PowerShell provider for an XML document. You could then use Set-Location to the XML document drive, use Get-ChildItem, and return information from that document. The methodology mimics the same methodology used with the file system.

In my article about PSDrives from three weeks ago, I illustrate creating a new PSDrive that is centered on a particular folder. This makes it easier for me to work with all of my Hey, Scripting Guy! Blog posts.

Oh! By the way, I am rapidly approaching a major milestone on the Hey, Scripting Guy! Blog. To date, the Hey Scripting Guy! Blog has 1,049 posts written about VBScript; I only wrote a few of those articles. Most of those were written by the previous Scripting Guys. One of the first things I did when becoming the Microsoft Scripting Guy was shift the blog’s emphasis to Windows PowerShell. The Hey, Scripting Guy! Blog now has 1,004 posts about Windows PowerShell. I did not write all of those articles, because we have had 184 blog articles written by guest bloggers, including posts written by Honorary Scripting Guys. So after I write another 230 blog posts about Windows PowerShell, the blog will officially be weighted in favor of Windows PowerShell.

I am not limited to creating new PSDrives from the filesystem provider. I can create new drives that expose data from the other providers as well. For example, if I am interested in working with the registry, I might want a new PSDrive. The first thing to do is to see which registry drives are available. One way to find this information is to use the Get-PSDrive cmdlet, as shown here:

PS C:\> Get-PSDrive -PSProvider registry

 

Name               Used (GB)          Free (GB)           Provider            Root

HKCU                                                                Registry             HKEY_CURRENT_USER

HKLM                                                               Registry             HKEY_LOCAL_MACHINE

The previous command reveals two registry drives: HKCU and HCLM. To create a new PSDrive, I use the New-PSDrive Windows PowerShell cmdlet. When using the New-PSDrive cmdlet, I need to specify the provider, the registry provider for this example, a name, and the root location for the drive. The command and associated output are shown here:

PS C:\> New-PSDrive -PSProvider registry -Name HKCR -Root HKEY_CLASSES_ROOT

 

Name               Used (GB)          Free (GB)           Provider            Rouot

HKCR                                                                Registry             HKEY_CLASSES_ROOT

To use the drive, I can use it like any other drive. If I do not put a colon at the end of the drive name, an error is displayed. This is illustrated here:

PS C:\> Get-ChildItem HKCR

Get-ChildItem : Cannot find path 'C:\HKCR' because it does not exist.

At line:1 char:14

+ Get-ChildItem <<<<  HKCR

    + CategoryInfo          : ObjectNotFound: (C:\HKCR:String) [Get-ChildItem], ItemNotFoundExcept

   ion

    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

When I add the colon at the end of the drive name, the command works as shown here:

PS C:\> Get-ChildItem HKCR:

    Hive: HKEY_CLASSES_ROOT

 

SKC      VC Name                      Property

3          16 *                              {ContentViewModeLayoutPatternForBrowse, ContentViewModeFo...

1          2 .386                           {(default), PerceivedType}

2          3 .3g2                           {(default), PerceivedType, Content Type}

2          3 .3gp                           {(default), PerceivedType, Content Type}

<<OUTPUT TRUNCATED>>

I do not have to create a PSDrive at a root location. I can specify a different location. For example, I might want a PSDrive that exposes the HKEY_LOCAL_MACHINE\SOFTWARE hive. To do this, I use the New-PSDrive cmdlet, specify the registry provider, give it a name, and identify the root of the drive. The resultant command is shown here:

PS C:\> New-PSDrive -PSProvider registry -Name sw -Root HKLM:\SOFTWARE

 

Name               Used (GB)          Free (GB)           Provider            Root

Sw                                                                    Registry             HKEY_LOCAL_MACHINE\SOFTWARE

I can then change my working location to the new software drive, and use the Get-ChildItem cmdlet to explore the drive. These two commands are shown here:

PS C:\> Set-Location sw:

PS sw:\> Get-ChildItem

 

 

    Hive: HKEY_LOCAL_MACHINE\SOFTWARE

 

                                                                       

SKC                  VC Name                                  Property

0                      1 7-Zip                                      {Path}

1                      0 Analog Devices                       {}

1                      0 ATI Technologies                     {}

756                   1 Classes                                   {(default)}

8                      0 Clients                                    {}

1                      1 CXT                                        {IsDriverLoaded}

1                      0 Hewlett-Packard                      {}

3                      0 IBM                                        {}

1                      0 IM Providers                           {}

2                      0 InstalledOptions                      {}

1                      0 Intel                                       {}

3                      1 LENOVO                                 {(default)}

198                   0 Microsoft                                {}

3                      0 MozillaPlugins                         {}

1                      0 MSIT TPM Crypto Provider       {}

1                      0 nsoftware                               {}

4                      1 NVIDIA Corporation                {nvDelFiles}

2                      0 ODBC                                     {}

4                      0 Policies                                   {}

5                      0 PowerPivot                             {}

0                      16 RegisteredApplications           {Windows Address Book, Paint, Windows Search,

1                      0 Sonic                                      {}

4                      0 Synaptics                                {}

1                      1 tdbg_trace                              {(default)}

35                     1 Wow6432Node                       {(default)}

1                      0 Xerox                                     {}

Some companies, such as Microsoft, make extensive use of certificates. A PSDrive that is useful is to create one that exposes the my certificate store for the current user. In the following command, I use the certificate provider to create a new certificate drive named mycerts.

PS C:\> New-PSDrive -Name mycerts -PSProvider certificate -Root cert:\CurrentUser\My

 

Name               Used (GB)          Free (GB)           Provider            Root

Mycerts                                                             Certificate          \CurrentUser\My

After I have the mycerts: drive, I can easily query the drive to find certificates that are going to expire in the next month:

PS C:\> Get-ChildItem mycerts: | where { $_.notafter -le "11/1/2011" } | select thumbprint, notafter

 

Thumbprint                                                                   NotAfter

4D43DC0CDFE1FDF31857FFA03120ACF4DB5C3CE6           10/1/2011 2:01:33 PM

I do not have to use a specific location when creating a new PSDrive. For example, I can use an environmental variable if I want to. In the following example, I create a new PSDrive called tmp that points to the temp folder in my profile. To get at this location, I use the $env:temp variable:

PS C:\> New-PSDrive -Name tmp -PSProvider filesystem -Root $env:temp

 

Name               Used (GB)          Free (GB)           Provider            Root

Tmp                                          47.49                FileSystem         C:\Users\edwils\AppData\Local\Temp

Well, if I can use an environmental variable when creating a new PSDrive, can I use a WMI query? In the following command, I use a WMI query to find the drive on my machine that has the greatest amount of free space. I then create a new PSDrive called data: that is located on that drive. This is a really cool way to have immediate access to the drive on your machine that has the greatest amount of free space. Here is the command:

PS C:\> New-PSDrive -Name data -PSProvider filesystem -Root (gwmi win32_logicaldisk | sort freespace

 -Descending | select deviceID -First 1).deviceID

 

Name               Used (GB)          Free (GB)           Provider            Root     CurrentLocation

Data                 100.02               47.49                FileSystem         C:\

 

After the drive is created, I can easily set my working location to that drive:

PS C:\> Set-Location data:

PS data:\>

 

By the way, the WMI query I used to find the drive with the most free space is shown here (it is useful in and of itself):

(gwmi win32_logicaldisk | sort freespace -Descending | select deviceID -First 1).deviceID 

 

Well, BP, that is all there is to playing around with new PSDrives. Join me tomorrow when I will have a guest blog article written by Boe Prox. It is cool, and you will not want to miss it.

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

 

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Ed,

    this is in deed cool stuff!

    As I already mentioned before: the provider system of powershell is great, but often it is overlooked or underestimated.

    The possiblilties in connection with powershell's capablity to evaluate subexpressions are endless. I should investigate this feature further! ( maybe it is something that will be needed for the sg2012 :-)

    Klaus.

  • @Klaus you are right, this is really cool stuff. I LOVE the fact I can use a WMI query to determine my PSDrive, or a system variable. The possibilities are much greater, than doing a simple drive\folder mapping.

  • Good topic. I'm trying to do something similar with credentials to access the other server and it's saying it can't find path using GetchildItem. Any ideas? I don't think I need a colon like you have above.

    function GetSecureLogin(){
    $global:username = "stuff"
    $global:password = get-content C:\filename.txt | convertto-securestring
    }

    function Cleanup([string]$Drive) {
    try {
    $deleteTime = -42
    $now = Get-Date
    **#this is saying cannot find path '\\name.na.xxx.net\20xServerBackup\V' name truncated**
    Get-ChildItem -Path $Drive -Recurse -Force |Where-Object {$_.LastWriteTime -lt $limit} | Remove-Item -Force
    }
    Catch{
    Write-Host "Failed"
    }
    }

    #####################start of script####################
    $share = '\\name.na.xxx.net\20xServerBackup\'
    $TheDrive = '\\name.na.xxx.net\20xServerBackup\VMs\'

    $global:password = ""
    $global:username = ""
    GetSecureLogin

    net use $share $global:password /USER:$global:username

    [array]$DriveArray = @(TheDrive)

    try{
    $i=0
    for ($i = $DriveArray.GetLowerBound(0); $i -le $DriveArray.GetUpperBound(); $i++) {
    $tempDrv = $DriveArray[$i]
    Cleanup $tempDrv
    }
    }
    catch [Exception] {
    Write-Host $_.Exception.Message
    }

  • You can even mount HKEY_USERS
    New-PSDrive -PSProvider registry -Name HKU -Root HKEY_USERS
    Get-ChildItem HKU:

    The only thing you cannot do is load other users' .DAT file
    There seems to be no powershell equivalent to "reg load"

  • You can P/Invoke the load command for the reg hive just like REG does it via an API call.