{"id":11981,"date":"2011-11-25T00:01:00","date_gmt":"2011-11-25T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2011\/11\/25\/use-powershell-commands-from-one-session-in-another-session\/"},"modified":"2011-11-25T00:01:00","modified_gmt":"2011-11-25T00:01:00","slug":"use-powershell-commands-from-one-session-in-another-session","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-commands-from-one-session-in-another-session\/","title":{"rendered":"Use PowerShell Commands from One Session in Another Session"},"content":{"rendered":"<p><span style=\"font-family:Lucida Sans Typewriter;font-size:small\"><b>Summary<\/b>: Learn how to automatically save commands from one session, and then use them in a new Windows PowerShell session.<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">Microsoft Scripting Guy, Ed Wilson, is here. One of the fun things about getting to travel around and talk to people who are using Windows PowerShell on a daily basis to automate their systems is the quality of the questions I receive. One question that has come up several times in the last month that the Scripting Wife and I have been traveling is, &ldquo;How can I save my history when I exit Windows PowerShell, and then have that history available to me when I open up Windows PowerShell again?&rdquo;<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">I gave this some thought&hellip; <\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">I decided that it would be trivial to import automatically saved history when Windows PowerShell starts, and that the <i>issue <\/i>would be saving the Windows PowerShell history when Windows PowerShell exits. One student who was in my class in Irvine, California suggested that I automatically save each command into a history file as I type the commands. In this way, when I exit the Windows PowerShell console, I will already have an up-to-date history file. While this technique is not impossible, it could have an unintended performance hit, and I decided against it. <\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">Another idea I had was to use the Windows PowerShell transcript. It is easy to start the transcript each time Windows PowerShell starts by adding the <b>Start-Transcript<\/b> command to the Windows PowerShell profile. I could then parse the Windows PowerShell transcript and pull out all of the commands. After I had all of the commands, it would be possible to add them to the history. But that would require creating a <b>HistoryInfo<\/b> object. <\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">In the end, I decided to create two functions and add them to my profile. The first function imports a saved history.xml file into the current Windows PowerShell session. The second function exports the current history to a history.xml file, and then it exits Windows PowerShell. <\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">The trick is to call the function that exports the history.xml file prior to exiting Windows PowerShell instead of clicking the &ldquo;X&rdquo; on the Windows PowerShell console, or typing <i>exit <\/i>to exit Windows PowerShell. As always, when I create a function, I also like to create an alias for that function. The two commands from my profile that create the aliases are shown here.<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">New-Alias -Name eps -Value Exit-PsWithHistory -description &quot;mred alias&quot;<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">New-Alias -Name ips -Value Import-PSHistory -Description &quot;mred alias&quot;<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">Instead of automatically importing the saved history, I manually type the alias for my import saved history function. The reason for this is that I do not always want to import my saved history; but, this is simply the way I work. I could easily modify my profile so that I do import my history automatically, and then I could simply clear the history if I did not want to use it. It will require a bit of testing before I make up my mind as to which action is most efficient. <\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">Here is my function to export command history to a history.xml file and exit Windows PowerShell. <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-size:small\"><b><span style=\"font-family:Segoe\">Function Exit-PsWithHistory<\/span><\/b><\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">{<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp;If(!(Test-Path $PSHistory)) <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp; {New-Item -path $PSHistory -itemtype directory}<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp; Get-History -count $MaximumHistoryCount | Export-Clixml -Path (Join-Path $PSHistory -child history.xml)<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp;Exit<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">} #end function Exit-PsWithHistory<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">The <b>Exit-PsWithHistory<\/b> function relies on the <b>$PSHistory<\/b> variable. This is a variable that I define in my Windows PowerShell profile, and it points to the folder I use to store my history.xml file. Here is the command that creates the <b>$PSHistory<\/b> variable. <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">$PSHistory = Join-path -path (split-path $PROFILE) -ChildPath history<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">So, I use the <b>Test-Path<\/b> cmdlet to see if there is a folder named <i>History <\/i>in my Windows PowerShell profile folder. If it does not exist, I create it by using the <b>New-Item<\/b> cmdlet. <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">If(!(Test-Path $PSHistory)) <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp; {New-Item -path $PSHistory -itemtype directory}<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">I then use the <b>Get-History<\/b> cmdlet to get all of the items in my command history. By default, the <b>Get-History<\/b> cmdlet returns only 32 items from the history. If I want to get all of the commands in my command history, I have to specify a value for the <i>Count <\/i>parameter. The most logical thing to do is to use the <b>$MaximumHistoryCount<\/b> variable to specify this number. In this way, if I increase the maximum history count from the default value of 64 to another number, my function will always export all of the commands. I use the <b>Export-CliXML<\/b> cmdlet to export my command history into an .xml file, and I use <b>Join-Path<\/b> to create the path to my file. This command is shown here. <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">Get-History -count $MaximumHistoryCount | Export-Clixml -Path (Join-Path $PSHistory -child history.xml)<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">The last thing I do is call the <i>exit <\/i>command to exit Windows PowerShell. <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">The function to import my saved history.xml file appears here. <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">Function Import-PsHistory<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">{<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp;If(Test-Path $PSHistory)<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp;{<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp; Import-Clixml -Path (Join-Path -path $PSHistory -child history.xml) |<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp; Add-history<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp;}<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">} #end function import-psHistory<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">Once again, I use the <b>Test-Path<\/b> cmdlet to ensure that the history folder exists. If it does, I assume that a history.xml file exists. This is not a major problem, because the only reason the History folder would exist, would be if I had created it. If I did create it, it should have been when I was exporting a history.xml file. <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">If(Test-Path $PSHistory)<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">The next thing I do is import the xml file, and pipeline it to the Add-History cmdlet. Here is that portion of the function.<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">Import-Clixml -Path (Join-Path -path $PSHistory -child history.xml) |<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">&nbsp; Add-history<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">I bump up my maximum history by assigning a new value to the variable. Rather than typing a big, long, complicated number, I simply use the <i>kb <\/i>administrative constant to allow me to create 2048 history entries. This command is shown here. <\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">$MaximumHistoryCount = 2kb<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">You might wonder, &quot;How large&nbsp;can I create the <b>$maximumHistoryCount<\/b> variable?&quot; To determine the maximum allowed value, I use the <b>Get-Variable<\/b> cmdlet. This command is shown here.<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">Get-Variable MaximumAliasCount | select -ExpandProperty attributes<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">&nbsp;<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MinRange&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MaxRange TypeId<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212;&#8212;&#8211;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212;&#8212;&#8211; &#8212;&#8212;<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 32768 System.Management.Automation.Validat&#8230;<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">One thing to keep in mind, is when you use the <b>Get-Variable<\/b> cmdlet, do not include the dollar sign prefix. If I do include the dollar sign prefix of the variable, I obtain a rather cryptic error that states Windows PowerShell cannot find a variable with the name of 2048. Because I recognize that number as the value I had increased the <b>$maximumhistorycount<\/b> variable to, it makes sense. I then drop the dollar sign, and return the <b>psvariable<\/b> object. I then send the variable to the <b>Format-List<\/b> cmdlet, and I choose all of the properties. The result reveals that there is an object hiding in the <b>attributes<\/b> variable. I then pipe the <b>psvariable<\/b> object to the <b>Select-Object<\/b> cmdlet, and I use the <i>ExpandProperty <\/i>parameter to expand the object that is stored in the <b>attributes<\/b> property. These commands are shown here.<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">get-variable maximumhistorycount<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">get-variable maximumhistorycount | fl *<\/span><\/p>\n<p style=\"padding-left:30px\"><span style=\"font-family:Segoe;font-size:small\">get-variable maximumhistorycount | select -ExpandProperty attributes<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">The commands and their associated output are shown here. <\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\"><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0250.hsg-11-25-11-1.png\"><img decoding=\"async\" alt=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0250.hsg-11-25-11-1.png\" title=\"Image of command output\" \/><\/a><\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">In the following image, I show my profile with the two new functions, the two aliases, and the two variable assignments.<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\"><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0207.hsg-11-25-11-2.png\"><img decoding=\"async\" alt=\"Image of script\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0207.hsg-11-25-11-2.png\" title=\"Image of script\" \/><\/a><\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">To exit Windows PowerShell, I use the <b>eps<\/b><i> <\/i>alias (my alias for the <b>Export-PsWithHistory<\/b> function. When I start Windows PowerShell, my profile runs, and it loads the functions, aliases, and variables into memory. I then type the <b>Import-PsHistory<\/b> command (I can also use the <b>ips<\/b><i> <\/i>alias). After I do that, I populate my history with all of my previous commands. I use the <b>h<\/b><i> <\/i>(alias for <b>Get-History<\/b>) command to see what commands I now have available to me in my command history. This sequence of commands is shown in the image that follows.<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\"><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1680.hsg-11-25-11-3.png\"><img decoding=\"async\" alt=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1680.hsg-11-25-11-3.png\" title=\"Image of command output\" \/><\/a><\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">There is one downside to this technique: Imported commands (via <b>Add-History<\/b>) do not populate the up and down arrows. But, dude (or dudette), with 2048 potential commands in the command history, that would be a ridiculous amount of Up and Down arrowing; that is why there are single letter aliases for <b>Get-History<\/b> and for <b>Invoke-History<\/b>.<\/span><\/p>\n<p><span style=\"font-family:Segoe;font-size:small\">Join me tomorrow for the Weekend Scripter when I will explore more coolness related to Windows PowerShell.<\/span><\/p>\n<p><span style=\"font-size:small\"><span style=\"font-family:Segoe\">I invite you to follow me on <\/span><a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\"><span style=\"color:#0000ff;font-family:Segoe\">Twitter<\/span><\/a><span style=\"font-family:Segoe\"> and <\/span><a href=\"http:\/\/bit.ly\/scriptingguysfacebook\"><span style=\"color:#0000ff;font-family:Segoe\">Facebook<\/span><\/a><span style=\"font-family:Segoe\">. If you have any questions, send email to me at <\/span><a href=\"mailto:scripter@microsoft.com\" target=\"_blank\"><span style=\"color:#0000ff;font-family:Segoe\">scripter@microsoft.com<\/span><\/a><span style=\"font-family:Segoe\">, or post your questions on the <\/span><a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\"><span style=\"color:#0000ff;font-family:Segoe\">Official Scripting Guys Forum<\/span><\/a><span style=\"font-family:Segoe\">. See you tomorrow. Until then, peace.<\/span><\/span><\/p>\n<p><span style=\"font-size:small\"><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Learn how to automatically save commands from one session, and then use them in a new Windows PowerShell session. Microsoft Scripting Guy, Ed Wilson, is here. One of the fun things about getting to travel around and talk to people who are using Windows PowerShell on a daily basis to automate their systems is [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[51,293,144,3,4,45],"class_list":["post-11981","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-getting-started","tag-history","tag-profiles","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Learn how to automatically save commands from one session, and then use them in a new Windows PowerShell session. Microsoft Scripting Guy, Ed Wilson, is here. One of the fun things about getting to travel around and talk to people who are using Windows PowerShell on a daily basis to automate their systems is [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/11981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=11981"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/11981\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=11981"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=11981"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=11981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}