Fun with PSDrive Locations

A PowerShell PSDrive is a mapping between a PowerShell provider and a resource. The majority of our work is done in a file system PSDrive that corresponds to a file system drive. Let me show you a little trick that might come in handy with a PSDrive. My “trick” should apply to just about any PSDrive, but I’m going to demonstrate with a file system drive.

First, here’s what one of these drives looks like.


PS C:\> get-psdrive e | format-list

Name : E
Description : VM
Provider : Microsoft.PowerShell.Core\FileSystem
Root : E:\
CurrentLocation :

Notice the CurrentLocation property. It is blank. When I set my location to this drive, I’ll be at the root.


PS C:\> e:
PS E:\> cd \temp
PS E:\temp>

Now, look at the PSDrive again.


PS E:\temp> get-psdrive e | format-list

Name : E
Description : VM
Provider : Microsoft.PowerShell.Core\FileSystem
Root : E:\
CurrentLocation : temp

As you would expect, the CurrentLocation property has changed. Now for the cool part. You can change the location “behind the scenes”. This works best if you aren’t in the drive you are going to change. All I need to do is get the PSDrive object and set a new value for the CurrentLocation property. The value is relative to the root of the PSDrive.


PS E:\temp> cd c:\
PS C:\> (get-psdrive e).Currentlocation="\stuff\this\that"

I could have saved the results of the Get-PSDrive expression to a variable and then set the CurrentLocation property, but because I’m doing this interactively in the shell I opted for a shortcut approach. When I change back to E: I am in a new folder.


PS C:\> cd e:
PS E:\stuff\this\that>

Sure, I could have used Set-Location and specified the path. But maybe you want to pre-set a location for a future command. I can see setting a default locations for some PSDrives in your PowerShell profile.


(get-psdrive c).CurrentLocation="\scripts"
(get-psdrive e).CurrentLocation="\temp"
(get-psdrive hklm).CurrentLocation="\Software\Microsoft\Windows\CurrentVersion"
CD S:

In a new shell, these drives automatically have a new default location.


PS S:\> get-psdrive c,e,hklm | format-list

Name : C
Description :
Provider : Microsoft.PowerShell.Core\FileSystem
Root : C:\
CurrentLocation : \scripts

Name : E
Description : VM
Provider : Microsoft.PowerShell.Core\FileSystem
Root : E:\
CurrentLocation : \temp

Name : HKLM
Description : The configuration settings for the local machine.
Provider : Microsoft.PowerShell.Core\Registry
Root : HKEY_LOCAL_MACHINE
CurrentLocation : \Software\Microsoft\Windows\CurrentVersion

PS S:\> cd hklm:
PS HKLM:\Software\Microsoft\Windows\CurrentVersion>

This gives me defaults that mean less typing, but I haven’t given up the ability to navigate elsewhere in the PSDrive.

Module Mania

More and more, you’re seeing members of the Windows PowerShell community package their contributions into modules, myself included. Although you’ll probably still see a lot of individual functions because it is often easier to demonstrate or educate. I received a comment on my Weather module that I thought merited a complete post, since I expect there are many administrators still new enough to PowerShell and especially PowerShell 2.0. The question is basically, “I’ve downloaded a module. Now what?”

One major benefit of a module over snapins, is that modules can be deployed with a simple file copy. There is no installation, registration, or the like. Extract the files and PowerShell can use them. But where? Windows PowerShell 2.0 will examine a system environmental variable called %PSMODULEPATH%
[CC LANG=”DOS”]
C:\Users\Jeff\>echo %psmodulepath%
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
[/CC]
The path you see here is for modules that would apply to any user of this computer. Open a PowerShell prompt and look at the variable and you will also see a path that is set for the current user.
[cc lang=”powershell”]
PS C:\> $env:psmodulepath
C:\Users\Jeff\Documents\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
[/cc]
The Modules directory does not exist by default, nor does WindowsPowerShell for that matter, so you might need to create them. Underneath the Modules directory you will have a folder for each module. Thus, you would extract my weather module to a folder called JH-Weather. In that folder are all the module files.

For the most part, these should be the only paths you need. But if you would like to specify an additional module path, you can modify the environmental variable by appending a new path.
[cc lang=”powershell”]
PS C:\> $env:psmodulepath=$env:psmodulepath + “;c:\scripts”
PS C:\> $env:psmodulepath.split(“;”)
C:\Users\Jeff\Documents\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
c:\scripts
[/cc]
Now, PowerShell will also search C:\Scripts for any modules.  HOWEVER..this modification is only for the current PowerShell session. If I open a new PowerShell session, I’ll be back to the same path. If you always need this path, then add the modification command to your PowerShell profile script. Make sure you make the change in your profile before you attempt to import any modules from the new folder.

The Get-Module cmdlet will show all currently loaded modules. If you want to see all the available modules use the -ListAvailable parameter.
[cc lang=powershell]
PS C:\> Get-Module -ListAvailable | Sort Name | Select Name

Name
—-
ActiveDirectory
AdminConsole
AppLocker
BitsTransfer
BSonPosh
DnsShell
DotNet
FileSystem
Godot7
GPAnswers
GroupPolicy
IsePack
JDHTools
JH-Weather
JH-WindowsUpdate
LocalUsersGroups
PowerShellPack
PSCodeGen
Pscx
PSDiagnostics
PSImageTools
PSRSS
PSSystemTools
PSUserTools
scripts
ShowTree
TaskScheduler
TroubleshootingPack
WebAdministration
WPK
[/cc]

When I want to use a module I import it into my session.
[cc lang=”powershell”]
PS C:\> Import-Module WebAdministration
[/cc]
Use Get-Command to see the module contents.

Creating modules is a completely different topic for another day, but I hope this has helped get you started in the right direction regarding what to do with modules. If not, let me know. There is also a help topic, About_Modules you should read. Don Jones and I also cover modules in Windows PowerShell 2.0: TFM

Cool Custom Consoles

Ok, maybe this isn’t as slick as something from West Coast Customs but maybe you’d like to add a little style to your PowerShell session. I’m talking about the (by now) staid blue console. Perhaps you don’t like blue or the color contrast isn’t too your liking. Here are some things to try if you want to customize your console.

Continue reading

Get Profiles

Keith Hill posted a bit of PowerShell code a few days ago that piqued my interest. I knew that in PowerShell, the $profile variable would list your current profile.

PS C:\> $profile

C:\Users\Jeff\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

This is handy because it makes it easy to call up my script editor if I need to make a change. But Keith showed that there’s much more useful information there and I decided to take advantage. Continue reading

Powershell: Exit Stage Left

While reviewing and revising the manuscript for Windows PowerShell v2.0: TFM 3rd ed. I had the opportunity to revisit our chapter on working with events in PowerShell. An event in Windows is when something happens like a mouse-click, a process being created or window resized. In PowerShell you can easily watch for an event of interest and then do something when it happens or fires. This is referred to as an event subscription.

PowerShell v2.0 has a few event related cmdlets you can use for creating an event subscription: Register-WMIEvent, Register-ObjectEvent and Register-EngineEvent. Today I want to show you something I think you might find helpful using the last cmdlet in the list.

Register-EngineEvent is used to to subscribe to Powershell related events such as when PowerShell is exiting. I’ve been asked in the past if PowerShell has a shutdown script mechanism and it doesn’t. But you can create your own with this cmdlet.

The cmdlet needs the sourceid of the event and a script block that will execute when the event fires.,

PS C:\> register-engineevent PowerShell.Exiting –action {write-host "Au revoir, adios and good-bye" –foregroundcolor Green}

Run this in your PowerShell session and you should see a new event subscription.

PS C:\> Get-EventSubscriber

SubscriptionId   : 1
SourceObject     :
EventName        :
SourceIdentifier : PowerShell.Exiting
Action           : System.Management.Automation.PSEventJob
HandlerDelegate  :
SupportEvent     : False
ForwardEvent     : False

Type Exit to close PowerShell and you should briefly see your logoff message. Are you starting to get some ideas?

Obviously you don’t want to have to recreate the event subscription every time you start PowerShell, so add it to your PowerShell profile. Here’s something I’ve been trying lately.


As you can see the Action scriptblock can be as long as you need it. I have commented out for right now a line that executes a shutdown script. I can modify this script as needed to do tasks such as exporting history, aliases or whatever and it will run whenever PowerShell exits.

I like my computer to be friendly so I have it speak to me, I use the SAPI.SPVoice object earlier in my profile to create $voice. If I have the speakers turned down, I’ll at least see a message written to the screen. The last item is creating a log file in my temp directory that simply stores the current date and time and a timespan object indicating how long my PowerShell session was running.

The entire Register-EngineEvent expression is piped to Out-Null simply to supress the output object.

Of course there are caveats. This doesn’t work with PowerShell ISE or most likely other applications that host PowerShell, although perhaps you’ll test and let me know. The event also won’t fire if you kill the PowerShell process or close the window using the window control. You must type ‘Exit’ to trigger the event which will kick off your action scriptblock.

Does this look interesting? How do you think you could take advantage of this? What types of exiting actions are you using? I hope you’ll share.