Export and Import PowerShell ISE Opened Files

Export and Import PowerShell ISE Opened Files

Rate This
  • Comments 3

Unlike other tools, PowerShell ISE doesn’t have project files. Project files are a good way to set your environment up with a well known state.

Thanks to the ISE Object Model, it is possible to add some project functionality.

The script below has two main functions “Export-ISEState” and “Import-ISEState”. They can be used to save files and PowerShellTabs and reopen them later.

Even script contents for untitled files are saved.

To save the current state (state = files and PowerShellTabs), use something like:

    Export-ISEState c:\temp\files.isexml

To load the state later run:

    Import-ISEState c:\temp\files.isexml

When exporting the current state the all titled files are saved with the script from my last post. This ensures you will have the same content when importing the state later.

For untitled files, the contents are saved. When untitled files are reloaded, new untitled files are created, if their contents are not already present in some untitled file.

If you like it, you can add it to your profile (psedit $profile will edit the ISE profile) or to a module imported in your profile.

Lucio Silveira [MSFT]

function Save-AllISEFiles

{

<#

.SYNOPSIS

    Saves all ISE Files except for untitled files. If You have multiple PowerShellTabs, saves files in all tabs.

#>

    foreach($tab in $psISE.PowerShellTabs)

    {

        foreach($file in $tab.Files)

        {

            if(!$file.IsUntitled)

            {

                $file.Save()

            }

        }

    }

}

 

function Export-ISEState

{

<#

.SYNOPSIS

    Stores the opened files in a serialized xml so that later the same set can be opened

 

.DESCRIPTION

    Creates an xml file with all PowerShell tabs and file information

   

.PARAMETER fileName

    The name of the project to create a new version from. This will also be the name of the new project, but with a different version

 

.EXAMPLE

    Stores current state into c:\temp\files.isexml

    Export-ISEState c:\temp\files.isexml

#>

 

    Param

    (

        [Parameter(Position=0, Mandatory=$true)]

        [ValidateNotNullOrEmpty()]

        [string]$fileName

    )

   

    # We are exporting a "tree" worth of information like this:

    #

    #  SelectedTabDisplayName: PowerShellTab 1

    #  SelectedFilePath: c:\temp\a.ps1

    #  TabInformation:

    #      PowerShellTab 1:

    #           File 1:

    #                FullPath:     c:\temp\a.ps1

    #                FileContents: $null

    #           File 2:

    #                FullPath:     Untitled.ps1

    #                FileContents: $a=0...

    #       PowerShellTab 2:

    #       ...

    #  Hashtables and arraylists serialize rather well with export-clixml

    #  We will keep the list of PowerShellTabs in one ArrayList and the list of files

    #  and contents(for untitled files) inside each tab in a couple of ArrayList.

    #  We will use Hashtables to group the information.

    $tabs=new-object collections.arraylist

   

    # before getting file information, save all untitled files to make sure their latest

    # text is on disk

    Save-AllISEFiles

 

    foreach ($tab in $psISE.PowerShellTabs)

    {

        $files=new-object collections.arraylist

        $filesContents=new-object collections.arraylist

        foreach($file in $tab.Files)

        {

            # $null = will avoid $files.Add from showing in the output

            $null = $files.Add($file.FullPath)

           

            if($file.IsUntitled)

            {

                # untitled files are not yet on disk so we will save the file contents inside the xml

                # export-clixml performs the appropriate escaping for the contents to be inside the xml

                $null = $filesContents.Add($file.Editor.Text)

            }

            else

            {

                # titled files get their content from disk

                $null = $filesContents.Add($null)  

            }

        }

        $simpleTab=new-object collections.hashtable

       

        # The DisplayName of a PowerShellTab can only be change with scripting

        # we want to maintain the chosen name       

        $simpleTab["DisplayName"]=$tab.DisplayName

       

        # $files and $filesContents is the information gathered in the foreach $file above

        $simpleTab["Files"]=$files

        $simpleTab["FilesContents"]=$filesContents

       

        # add to the list of tabs

        $null = $tabs.Add($simpleTab)

       

    }

   

    # tabsToSerialize will be a hashtable with all the information we want

    # it is the "root" of the information to be serialized in the hashtable we store...

    $tabToSerialize=new-object collections.hashtable

   

    # the $tabs information gathered in the foreach $tab above...

    $tabToSerialize["TabInformation"] = $tabs

   

    # ...and the selected tab and file.

    $tabToSerialize["SelectedTabDisplayName"] = $psISE.CurrentPowerShellTab.DisplayName

    $tabToSerialize["SelectedFilePath"] = $psISE.CurrentFile.FullPath

   

    # now we just export it to $fileName

    $tabToSerialize | export-clixml -path $fileName

}

 

 

function Import-ISEState

{

<#

.SYNOPSIS

    Reads a file with ISE state information about which files to open and opens them

 

.DESCRIPTION

    Reads a file created by Export-ISEState with the PowerShell tabs and files to open

   

.PARAMETER fileName

    The name of the file created with Export-ISEState

 

.EXAMPLE

    Restores current state from c:\temp\files.isexml

    Import-ISEState c:\temp\files.isexml

#>

 

    Param

    (

        [Parameter(Position=0, Mandatory=$true)]

        [ValidateNotNullOrEmpty()]

        [string]$fileName

    )

   

   

    # currentTabs is used to keep track of the tabs currently opened.

    # If "PowerShellTab 1" is opened and $fileName contains files for it, we

    # want to open them in "PowerShellTab 1"

    $currentTabs=new-object collections.hashtable

    foreach ($tab in $psISE.PowerShellTabs)

    {

        $currentTabs[$tab.DisplayName]=$tab

    }

   

    $tabs=import-cliXml -path $fileName

 

    # those will keep track of selected tab and files   

    $selectedTab=$null

    $selectedFile=$null

 

    foreach ($tab in $tabs.TabInformation)

    {

        $newTab=$currentTabs[$tab.DisplayName]

        if($newTab -eq $null)

        {

            $newTab=$psISE.PowerShellTabs.Add()

            $newTab.DisplayName=$tab.DisplayName

        }

        #newTab now has a brand new or a previouslly existing PowerShell tab with the same name as the one in the file

       

        # if the tab is the selected tab save it for later selection

        if($newTab.DisplayName -eq $tabs.SelectedTabDisplayName)

        {

            $selectedTab=$newTab

        }

       

        # currentUntitledFileContents keeps track of the contents for untitled files

        # if you already have the content in one of your untitled files

        # there is no reason to add the same content again

        # this will make sure calling import-ISEState multiple times

        # does not keep on adding untitled files

        $currentUntitledFileContents=new-object collections.hashtable

        foreach ($newTabFile in $newTab.Files)

        {

            if($newTabFile.IsUntitled)

            {

                $currentUntitledFileContents[$newTabFile.Editor.Text]=$newTabFile

            }

        }

       

        # since we will want both file and fileContents we need to use a for instead of a foreach

        for($i=0;$i -lt $tab.Files.Count;$i++)

        {

            $file = $tab.Files[$i]

            $fileContents = $tab.FilesContents[$i]

 

            #fileContents will be $null for titled files

            if($fileContents -eq $null)

            {

                # the overload of Add taking one string opens the file identified by the string

                $newFile = $newTab.Files.Add($file)

            }

            else # the file is untitled

            {

                #see if the content is already present in $newTab

                $newFile=$currentUntitledFileContents[$fileContents]

               

                if($newFile -eq $null)

                {

                    # the overload of Add taking no arguments creates a new untitled file

                    # The number for untitled files is determined by the application so we

                    # don't try to keep the untitled number, we just create a new untitled.

                    $newFile = $newTab.Files.Add()

               

                    # and here we restore the contents

                    $newFile.Editor.Text=$fileContents

                }

            }

       

            # if the file is the selected file in the selected tab save it for later selection   

            if(($selectedTab -eq $newTab) -and ($tabs.SelectedFilePath -eq $file))

            {

                $selectedFile = $newFile

            }

        }

    }

   

    #finally we selected the PowerShellTab that was selected and the file that was selected on it.

    $psISE.PowerShellTabs.SetSelectedPowerShellTab($selectedTab)

    if($selectedFile -ne $null)

    {

        $selectedTab.Files.SetSelectedFile($selectedFile)

    }

}

 

 

Leave a Comment
  • Please add 6 and 5 and type the answer here:
  • Post
  • If only it was possible to put the export into an event handler for powershell.exiting and the import into your profile. Unfortunately the asynchronous nature of eventing's powershell.exiting means that the ISE OM is often disposed and/or GC'd before the event handler can read the files collection. Sigh.

  • This is awesome.  This functionality was one of the main reasons I was using other IDEs instead of ISE.

    @Oisin G. you may not be able to reliably hook into the exiting event handler, but you can easily create another keyboard shortcut Save State And Exit, and have your profile Load State when a new PS session is started.  I show how to do this in my blog post blog.danskingdom.com/powershell-ise-multiline-comment-and-uncomment-done-right-and-other-ise-gui-must-haves

  • I've made a feature request to have this functionality added in a later version of ISE.  Go up-vote it at connect.microsoft.com/.../windows-powershell-ise-add-ability-to-save-load-session-state

Page 1 of 1 (3 items)