Click here to Skip to main content
15,881,812 members
Articles / Operating Systems / Windows

Saving PowerShell commands across sessions

Rate me:
Please Sign up or sign in to vote.
3.86/5 (3 votes)
21 May 2008CPOL6 min read 44.3K   127   25   5
A set of functions to provide the ability to save commands to be used in future PowerShell sessions.

Image 1

Introduction

PowerShell is a useful tool for developers and system administrators alike. Much of its usefulness comes from being able to craft a complicated, multi-part command to get some useful piece of information. The problem is that once I close the window, the command is gone. If I really want to save that command, I could make a script, but that involves taking several steps to open a text editor, type in the command, and save the script file. Furthermore, I then have to type in the full path of the script when I want to run it later. Also, when I make a script, I feel the need to include descriptive comments such as the purpose of and arguments to the script. All I really want is a quick and easy way to save commands and execute them later.

Background

Doing a little searching on the web revealed the Get-History cmdlet, which allows you to see the entire command history that has been saved so far. There is also the Add-History cmdlet, but my attempts to use it to load in saved commands proved unsuccessful. The commands would be shown by Get-History but did not appear to be accessible via the up or down keys, which is the normal way to cycle through the history.

Even if it had worked, I wanted a way to be able to save an arbitrary number of commands and be able to execute them easily without having to arrow through the history. Another shortcoming of that approach is that the loaded commands would eventually be pushed out of the history, requiring some method to reload the commands into the history. With those limitations in mind, I set about writing my own functions.

Why functions and not a set of script files? The main reason for using functions instead of script files is that I can call them from any location without having to type the path to the directory where I keep my scripts. Once the functions have been added to the $profile file, the functions will be loaded every time PowerShell starts, and be available for use without any further intervention from me. Since I am too lazy to type out the entire function names every time, I also set a short alias in the $profile file for each of the functions. For those not as familiar with PowerShell, it is as simple as this:

Set-Alias nsc NewSaveCommand

The key to making this all work is that PowerShell has an eval type function. The Invoke-Expression cmdlet will take a string either through the pipeline or as an argument and execute it as a PowerShell command. This allows you to save a command into a small text file and later load and execute the command.

Using the Code

There are four functions needed for the full set of features. They are:

  • NewSavedCommand
  • RemoveSavedCommand
  • GetSavedCommand
  • ExecuteSavedCommand

The function of each should be clear from the name, but the way they work is worth explaining.

NewSavedCommand will save the last command entered (before the command to save the last command, of course) to a text file in the same directory as your PowerShell profile file. The name of the file is in the form <number>.psc, where the number chosen is the smallest number that is not already taken. This means that if you have several commands and start deleting them, the next commands you add will fill in the blank numbers instead of being added to the end while leaving gaps.

RemoveSavedCommand will remove a saved command that you no longer want to keep around. This will free up the command number to be used again by the next command you save. If you pass a negative number to the function, all of your saved commands will be deleted. You have been fairly warned.

GetSavedCommand can either print a list of all saved commands or can print out the entire text of a particular saved command. In the screenshot, you can see the results of passing no argument (or a negative one) to the function. One of my commands is quite long and goes off the screen. To see the entire command, I simply call the function again with the number of the command I want to see. That command is one that I will probably want to call throughout the next few weeks, and you can see how useful it is to not have to remember and retype the entire thing.

ExecuteSavedCommand takes the number of the command to be executed as a parameter and will read in the contents of <number>.psc and pass that to Invoke-Expression. The result will be that your complicated, specially crafted command will be executed, without having to type in the entire text again.

Points of Interest

One interesting thing I came across while making these functions is the ability to format your output as a table without having predefined classes and properties. The first call to GetSavedCommand in the screenshot shows the results. Here's the corresponding code:

Get-ChildItem (Split-Path $profile -parent) *.psc | 
    Format-Table @{Label='Number'; 
         Expression={[int]([System.IO.Path]::GetFileNameWithoutExtension($_.FullName))}},
         @{Label='Command'; Expression={Get-Content $_.FullName}} -auto

If you are not familiar with PowerShell, a few notes about the syntax are in order. @{} creates a hashtable that can be filled with key-value pairs. The semicolon is used as a separator because the comma is already used to make arrays (no braces or parentheses are needed to make an array, just a list of comma separated values). For those used to coding in C style languages, you may guess that the Expression value is a block of code, and you would be correct.

Format-Table is a built-in cmdlet that allows you to pass the object to be formatted through the pipeline and specify the properties as arguments. If you want to show something that is not a property, however, you will need to use the hashtable syntax shown above. Label is the name that will be shown at the top of the column and Expression is a code block that calculates the value for that column. The -auto argument simply tells the cmdlet to auto-size the columns to prevent a lot of whitespace.

Room for Improvement

After creating the functions, I thought of a few potential improvements that I decided not to implement for my own use. They should not be too difficult to add, and I would be willing to add them if several people would find them useful.

  • Ability to save more than just the last command entered. This would probably be implemented by passing the ID of the command returned from the Get-History cmdlet to the NewSavedCommand function.
  • Ability to pass arguments to the saved commands.

History

  • 21 May 2008
    • Initial version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalawesome Pin
maxwellsmarta865-Aug-09 20:30
maxwellsmarta865-Aug-09 20:30 
GeneralThanks Pin
lucastar2-Feb-09 12:08
lucastar2-Feb-09 12:08 
GeneralRe: Thanks Pin
Gideon Engelberth12-Feb-09 3:02
Gideon Engelberth12-Feb-09 3:02 
AnswerRe: Thanks Pin
mkmurray27-Mar-09 11:13
mkmurray27-Mar-09 11:13 
GeneralGideon --I really liked your article Pin
onisick27-May-08 4:54
onisick27-May-08 4:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.