PowerShell ISE Remote Possibilities

Normally, I think of the PowerShell ISE as a script development tool. I typically don’t think of it as a daily management tool, primarily because everything shares the same scope and if you are running scripts and aren’t careful can sometimes lead to unexpected results. But the ISE feature I really like is the ability to open a new tab with a remote connection to another server. You can even specify alternate credentials.

Normally you can accomplish this by going to File – New Remote PowerShell tab or using the keyboard shortcut Ctrl+Shift+R. But if you want to open multiple remote tabs, say to key servers you want to manage, this gets a little tedious. Or perhaps you’d like to open multiple remote tabs in your PowerShell ISE profile script? We need a better way.

Fortunately, the PowerShell ISE has a scriptable object model. A remote tab is simply another PowerShell tab that has executed Enter-PSSession. Creating a new tab is pretty simple.

Once the tab is open you can use the Invoke() method to run a command in it.

If you need alternate credentials adjust the command. You can even change the tab’s display name.

The new remote tabThe new remote tab (Image Credit: Jeff Hicks)

But there are a few things to watch out for. First, it takes time to open a new tab and you have to wait for it to be ready to invoke commands. You might need to use a short Do loop.

And every time you open a new PowerShell tab, you are opening a new PowerShell session which means your profile scripts run as well. If you are like me, this adds a little overhead that is completely unnecessary since the remote tab won’t be using anything in my profile. So I need a way to open the tab without running any profiles. Fortunately, this can be done, but it is not something exposed in the ISE. But thanks to fellow PowerShell MVP Tobias Weltner, I now have some code that digs into the ISE internals and turns off the option to load profiles.

To re-enable, I can run the last line and set the value to $False.

And of course, I’ve tried to make this easier for you to use by creating a function for the PowerShell ISE called New-ISERemoteTab. You can find the source code on GitHub.

In addition to creating a new remote tab, my function also runs a few commands after the remote connection is established. I prefer a clean slate so I like to at least run Clear-Host. You can invoke commands in the remote tab from new tab object you created.

The other concession I had to make is that if you specify a credential, I have to temporarily export it to disk. Because the new tab is a new PowerShell session there’s no way that I can find to pass variables between session without writing them to disk. But at the end of the process the file is deleted.

Creating a remote tab with credentialCreating a remote tab with credential (Image Credit: Jeff Hicks)

And this is the result:

The new remote tabThe new remote tab (Image Credit: Jeff Hicks)

Feel free to modify the new tab commands. If you specify multiple computers and a credential, the same credential will be used for all connections.

But I also have an option to prompt for credentials. This will not write anything to disk and if you specify multiple computers, you can enter a different credential for different computers. I thought that could come in handy if you need to connect to workgroup-based servers.

The end result is that I can now easily create multiple remote tabs with a single command.

Creating multiple remote tabsCreating multiple remote tabs (Image Credit: Jeff Hicks)

There are a few other examples in command help.

I’ve tried to annotate the function so you can understand how it works but feel free to post questions or problem in GitHub. I’d also like to hear from you in the comments if you find this useful.

Enjoy!

UPDATE: I’m starting to see the benefit of GitHub. Since I published the original earlier today, someone has already improved it and I’ve incorporated those changes into the project.

A Spooky PowerShell Halloween

I shared some code yesterday on Twitter and Facebook, but you may have missed it and I wanted to have a more permanent record so this is it. In the spirit of the holiday I thought it would spooky to have a little fun with the PowerShell ISE.

A spooky Halloween theme for the ISEA spooky Halloween theme for the ISE (Image Credit: Jeff Hicks)

How did I get this? Well first, I recommend you save your existing settings. Run this command in the PowerShell ISE.

This will save current values for settings you are about to change to a CSV file. Then run these commands to change ISE options.

Scary easy, right? These settings will remain even if you restart the PowerShell ISE. To restore your original settings and sanity you can import the saved CSV:

Or go to Tools – Options – Manage Themes and select the default, or whatever you are using.

Restoring the ISE themeRestoring the ISE theme (Image Credit: Jeff Hicks)

Happy Trick or Treating!

Friday Fun: Open Last File in the PowerShell ISE

Over the last few articles I’ve been sharing some shortcuts to get most recently used or edited files. For today’s Friday Fun I thought I’d share something that I use in my PowerShell ISE profile. Whenever I start the ISE, I automatically open the last file I was working on. Instead of launching the ISE and then finding the most recent file in list under File, this happens automatically.

I found some information on this topic at PowerShell.com and revised it to meet my needs. The most recently used files are stored in an XML configuration file, which is good because I can use PowerShell to parse out the information I need. Unfortunately, the path to this file is pretty unwieldy:

$env:LocalAppData\microsoft_corporation\powershell_ise.exe_StrongName_lw2v2vm3wmtzzpebq33gybmeoxukb04w\3.0.0.0

Which translates to something like this:

C:\Users\Jeff\AppData\Local\microsoft_corporation\powershell_ise.exe_StrongName_lw2v2vm3wmtzzpebq33gybmeoxukb04w\3.0.0.0

The XML file is called user.config. With that, let’s get some PowerShell in here to get the XML.

The recent used list is stored under user settings.

The value should have what I need.

Looks like it is an array of strings.

Getting closer. It seems the last step I need is that string property.

This should be the same list as I see under File. But while this works, it assumes that the setting I want will always be at position 5 and that I know how to get there in the first place. The smarter way is to use an XPATH filter to find the data. I can use the SelectNodes() method.

The query essentially says find any node that is a <setting> and that has a name attribute of “MRU”. XML is case-sensitive so I have to match what is in the XML file.

With this it is just as easy to get the most recent file.

Once I know the file name it is trivial to load it into the ISE.

The other way I could have selected the node is with Select-XML.

The node property has the setting I need. I can simply keep drilling until I get the value I want.

In this case I’m only selecting the first item. I could have used these code snippets in my profile, but I decided to create a function to retrieve the MRU list.

The function encapsulates everything I’ve shown you. Although I set a default path using a wildcard.

I did this to keep things easier to read and on the off chance that the strong name value might change at some point. By the way I am running this on PowerShell 4.0. I have not tested with v5.

To get the full path, I can resolve this path with a wildcard.

Most everthing else is the same. This function is in my PowerShell ISE profile script and at the end I open the most recent file.

It’s that easy. And because the function is in my profile, I can run it anytime. Although note that the XML file won’t get updated until you close the ISE. Personally, all these little things add up over the course of a day and make my work a bit more fun. Enjoy.

Friday Fun: Edit Recent File

As you might imagine I work on a lot of PowerShell projects at the same time. Sometimes I’ll start something at the beginning of the week and then need to come back to it at the end of the week. The problem is that I can’t always remembered what I called the file. So I end up listing files, sorting by last write time and then looking at the last 10 or so. Time to be more efficient so I came up with a little PowerShell v3 function called Edit-RecentFile.


#requires -version 3.0

Function Edit-RecentFile {

<# .Synopsis Open selected files for editing in the PowerShell ISE .Description This command will list the most recently modified files in the specified directory. By default the command will list the 25 most recently modified files. Using Out-Gridview as an interface, you can select the files you wish to edit and they will open in the PowerShell ISE. If you are already in the ISE then each file will open in a new tab. This command requires PowerShell v3. .Example PS C:\> edit-recentfile d:\myscripts -last 10
.Example
PS C:\> edit-recentfile c:\work\*.txt
#>

[cmdletbinding()]
Param(
[Parameter(Position=0)]
[ValidateScript({Test-Path $_})]
[string]$Path="c:\scripts",
[Parameter(Position=1)]
[ValidateNotNullorEmpty()]
[int]$Last=25,
[switch]$Recurse
)

Write-Verbose "Getting $last recent files from $path."

#get last X number of files from the path and pipe to Out-Gridview
$files = Get-ChildItem -Path $Path -file -Recurse:$Recurse |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -First $Last -Property FullName,LastWriteTime,Length,Extension |
Out-GridView -Title "Select one or more files to edit and click OK" -PassThru

#if files were selected, open them in the ISE
if ($files) {
Write-Verbose "Opening`n$($files.fullname | out-string)"
#if in the ISE use PSEDIT
if ($host.name -match "ISE") {
Write-Verbose "Detected the PowerShell ISE"
psedit $files.Fullname
}
else {
#otherwise assume we're in the console
Write-Verbose "Defaulting to PowerShell console"
ise ($files.FullName -join ",")
}
} #if $files

} #close Edit-RecentFile

The core section gets the directory listing of the most recently modified files but then pipes them to Out-Gridview.

Edit-RecentFile

In PowerShell v3, Out-Gridview has been extended so that you can select one or more items and pass them back to the pipeline.


$files = Get-ChildItem -Path $Path -file -Recurse:$Recurse |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -First $Last -Property FullName,LastWriteTime,Length,Extension |
Out-GridView -Title "Select one or more files to edit and click OK" -PassThru

Once I have the collection of files, I can use the FullName property and open them in the PowerShell ISE. From the console I can use the ise alias and pass a comma separated list of files. The fun part is turning the array of file paths into a comma separated string. But that is easily done using the -Join operator.


ise ($files.FullName -join ",")

If I am in the PowerShell ISE already, I can do a similar thing using the PSEDIT command, although this takes the array without any reformatting.


if ($host.name -match "ISE") {
Write-Verbose "Detected the PowerShell ISE"
psedit $files.Fullname
}

The function has a default path set to C:\Scripts which you might want to change. By default the function will only look in the root of the folder, but you can use -Recurse. The download file will also create an alias erf, for the function.

Download Edit-RecentFile and let me know how it works out for you.

PowerShell ISE AddOn ModuleMenu

Recently I did an online presentation on ISE Addons. As I was preparing for the talk one thing led to another, as they usually do when I’m working in PowerShell, and before I knew it I had a new add-on for the PowerShell ISE. This addon creates a menu for all of the modules in your module path.

The module looks at the $env:PSModulePath environmental variable and creates a submenu for each module. I came up with a nice two level Write-Progress command because at least on my desktop I have a lot of modules.

My script creates a sub menu for each discovered module.

You can import the module directly from the menu, and when you do, my module dynamically updates the menu with options to look at all the commands in the module and to remove it.

The module menu uses Out-Gridview quite a bit to keep things graphical, but it is view only. However, I added a nice module summary.

To try this out, download ModuleMenu.zip and extract to your modules folder. Then in the ISE, import module ModuleMenu. Everything is contained in a single .psm1 file which you can edit directly from the menu! Perhaps you might not need the module, but it offers some nice examples of creating ISE add-on menu items. Once PowerShell v3 is released, much of this will probably be irrelevant. I’ll worry about that later.

Enjoy!