(another in the “Things you’ll want to do with PowerShell V2” series)

One of the tricks I have been meaning to post for a little while is a neat way to edit a file in the new PowerShell Integrated Scripting environment. If you are working in the “traditional” shell you just type “notepad filename” and you’re editing the file but what how can you have a command line to load up a file in the ISE ? It turns out to be quite easy. $psise.CurrentPowerShellTab.Files.add(C:\myStuff\MyFile.ps1)

The ISE has an object model and there is an automatic variable which points to the root of it, so all you have to do call one of its objects, give i the full path of the file to load and hey presto. But it doesn’t exactly trip off the fingers.

So here was the first go.

function edit
{ param ( $Path )
    $null = $psise.CurrentPowerShellTab.Files.add($_.path)
}

Easy enough, but PowerShell can do much better than that. For starters it can resolve the path for us, and if it resolves to multiple files (for example *.ps1) then we’ll get all of them.

function edit
{ param ( $Path )
             Resolve-path $path | foreach-Object { $null = $psise.CurrentPowerShellTab.Files.add($_.path)}
}

My first instinct was to hand Resolve-path one item at a time, but it is quite happy being passed multiple paths like *ps1,*.PsXML so this version of the function will version open multiple wildcards. This was starting to look like I would want to be able to pipe things into it. And By now I was realizing that I would want to use it in the traditional shell as well. So I made three final modifications . The first one says I can pass it objects which have a Path, FileName or FullName property and that property will get treated as the path. The Second is because a function can have a begin, process and end block, this should go in the process block to be called for each object piped in, and the last says if the the name of the PowerShell host isn’t the ISE then launch the file in notepad.

function edit
{ param ([parameter(ValueFromPipelineByPropertyName=$true)][Alias("FullName","FileName")]$Path )
    process {
             Resolve-path $path | foreach-Object { $_
                if ($host.name -match "\sISE\s") {$null = $psise.CurrentPowerShellTab.Files.add($_.path)}
                else                             {notepad.exe $_.path}
            }
   }
}

I had the first version working for a few days before I changed it to allow the value from pipe line by property name after reading something on our internal PowerShell alias (I’d swear it came from James Brundage but I can’t find it). It means I don’t have to test for different kinds of objects being piped into the command - I can just anticipate the property names. This came into its own last night when I found I had the same error in about 20 different PS1 files. It was easy enough to find them all and open them with one command.

select-string -Pattern "ParameterSet" -path *.ps1 | edit

The updated version is now in my profile – and since moving up to version 2, my profile has become one which works for both ISE and Traditional PowerShell – there are actually 6 profiles, current user, and all user and all hosts/”current host”  - which is either the Shell or ISE host. The table below maps them out – but you can find them as properties of $profile.

$profile.CurrentuserCurrenthost $env:userProfile\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1
or
$env:userProfile\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
$profile.CurrentuserAllhosts $env:userProfile\Documents\WindowsPowerShell\profile.ps1
$profile.AllusersCurrentHost $env:windir\System32\WindowsPowerShell\v1.0\Microsoft.PowerShellISE_profile.ps1
or
$env:windir\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1
$profile.AllusersAllHosts $env:windir\System32\WindowsPowerShell\v1.0\profile.ps1

Bonus Looking for the information about profiles I found this post of Jeffrey’s on adding custom commands to the menus in the ISE. The syntax has changed but it showed me how I could do

$psise.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("Bulk edit", {Edit (Read-host "Enter file(s)") }, 'Ctrl+E')

and have bulk edit on a hot key / menu item…