{"id":10761,"date":"2006-04-25T12:18:00","date_gmt":"2006-04-25T12:18:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/2006\/04\/25\/is-it-safe-to-use-aliases-in-scripts\/"},"modified":"2019-02-18T13:25:01","modified_gmt":"2019-02-18T20:25:01","slug":"is-it-safe-to-use-aliases-in-scripts","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/is-it-safe-to-use-aliases-in-scripts\/","title":{"rendered":"Is it safe to use ALIASES in scripts?"},"content":{"rendered":"<p>In&nbsp;our newsgroup (Microsoft.Public.Windows.Server.Scripting) , Mark Ayers asked the question:<br \/>&gt; Shouldn&#8217;t best practice for scripts be full command name?<\/p>\n<p>The answer is YES, NO, and MAYBE.<\/p>\n<p><strong>YES <\/strong>&#8211; Full names provide the most readable experience for scripts.&nbsp; This is very important.&nbsp; People&nbsp;often throw the rock at Perl saying that it is a &#8220;write-only language&#8221; meaning that after you write a script, you can&#8217;t read it or understand what it does.&nbsp; We believe that Monad scripts will be widely shared and will be used in environments where it is really important to know exactly what is going on.&nbsp; As such, script readability has always been a strong focus for us.&nbsp; This is one of the key reasons why we support both a pithy and verbose invocation model (pithy for high-speed interactive use, verbose for scripting).<\/p>\n<p><strong>NO <\/strong>&#8211; Not all aliases are the same.&nbsp; There are a special class of aliases that are READONLY and ALLSCOPE.&nbsp; You can find these with the following command:<\/p>\n<p>gal | where {&#8220;&#8221;+$_.options -match &#8220;Readonly&#8221; } | ft name, definition, options -auto<\/p>\n<p>Take a look at how regular and predictable these are:<\/p>\n<p><font face=\"Courier New\" size=\"2\">MSH&gt; gal g* | where {&#8220;&#8221;+$_.options -match &#8220;Readonly&#8221; } |<br \/>ft name, definition, options -auto<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">Name&nbsp; Definition&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Options<br \/>&#8212;-&nbsp; &#8212;&#8212;&#8212;-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212;&#8212;-<br \/>gal&nbsp;&nbsp; get-alias&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>gc&nbsp;&nbsp;&nbsp; get-content&nbsp;&nbsp; ReadOnly, AllScope<br \/>gci&nbsp;&nbsp; get-childitem ReadOnly, AllScope<br \/>gcm&nbsp;&nbsp; get-command&nbsp;&nbsp; ReadOnly, AllScope<br \/>gdr&nbsp;&nbsp; get-drive&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>ghy&nbsp;&nbsp; get-history&nbsp;&nbsp; ReadOnly, AllScope<br \/>gi&nbsp;&nbsp;&nbsp; get-item&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>gl&nbsp;&nbsp;&nbsp; get-location&nbsp; ReadOnly, AllScope<br \/>gm&nbsp;&nbsp;&nbsp; get-member&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>gp&nbsp;&nbsp;&nbsp; get-property&nbsp; ReadOnly, AllScope<br \/>gps&nbsp;&nbsp; get-process&nbsp;&nbsp; ReadOnly, AllScope<br \/>group group-object&nbsp; ReadOnly, AllScope<br \/>gsv&nbsp;&nbsp; get-service&nbsp;&nbsp; ReadOnly, AllScope<br \/>gu&nbsp;&nbsp;&nbsp; get-unique&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>gv&nbsp;&nbsp;&nbsp; get-variable&nbsp; ReadOnly, AllScope<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">MSH&gt; gal ?v | where {&#8220;&#8221;+$_.options -match &#8220;Readonly&#8221; } |<br \/>ft name, definition, options -auto<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">Name Definition&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Options<br \/>&#8212;- &#8212;&#8212;&#8212;-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212;&#8212;-<br \/>gv&nbsp;&nbsp; get-variable&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>nv&nbsp;&nbsp; new-variable&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>rv&nbsp;&nbsp; remove-variable ReadOnly, AllScope<br \/>sv&nbsp;&nbsp; set-variable&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">MSH&gt; gal n* | where {&#8220;&#8221;+$_.options -match &#8220;Readonly&#8221; } |<br \/>ft name, definition, options -auto<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">Name Definition&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Options<br \/>&#8212;- &#8212;&#8212;&#8212;-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212;&#8212;-<br \/>nal&nbsp; new-alias&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>ndr&nbsp; new-drive&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>ni&nbsp;&nbsp; new-item&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>nv&nbsp;&nbsp; new-variable ReadOnly, AllScope<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">MSH&gt; gal *al | where {&#8220;&#8221;+$_.options -match &#8220;Readonly&#8221; } | ft name, definition, options -auto<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">Name Definition&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Options<br \/>&#8212;- &#8212;&#8212;&#8212;-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212;&#8212;-<br \/>epal export-alias&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>gal&nbsp; get-alias&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>ilal initialize-alias ReadOnly, AllScope<br \/>ipal import-alias&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>nal&nbsp; new-alias&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<br \/>sal&nbsp; set-alias&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReadOnly, AllScope<\/font><\/p>\n<p>In previous drops, these aliases where CONSTANT which meant that users could not delete or remove them.&nbsp; They exist because they are very predictable and pithy short hands for the long names.&nbsp; We made them constant so that you could feel safe using them in any script and that you could share that script with other people knowing that you were guaranteed that those aliases would exist everywhere and mean the same thing so your scripts would not break.&nbsp; The community provided strong feedback that MSFT should not ship any CONSTANT aliases so we made them READONLY and ALLSCOPE.&nbsp; This means that you can remove them (using the -FORCE flag) and create your own definitions but it is strongly discouraged.<\/p>\n<p>So in the end, you are pretty safe using the aliases that are READONLY and CONSTANT.&nbsp; You might argue that this is less safe then using the full command name.&nbsp; This would not be correct.&nbsp; Token resolution works by first expanding aliases then binding to a function, then a cmdlet, lastly as an external executable.&nbsp; When you type &#8220;Get-Process&#8221;&nbsp; &#8211; it could have been aliased to any other command or there could be a function with this name.&nbsp;So in the end, the READONLY ALLSCOPE aliases are just about as safe as the full command names.<\/p>\n<p><strong>MAYBE.&nbsp; <\/strong>The other thing you can do in your script is to set up the aliases you&#8217;ll use yourself.&nbsp; Aliases are scoped so this is generally a safe operation and will not contaminate the users environment.&nbsp; Let me demonstrate using a one of my favorite functions that I define in my profile file, Start-NewScope and its alias sans&nbsp;<\/p>\n<p><font face=\"Courier New\" size=\"2\">function Start-NewScope <br \/>{<br \/>param($Prompt = $null) Write-Host &#8220;Starting New Scope&#8221;<br \/>&nbsp; if ($Prompt -ne $null)<br \/>&nbsp; {&nbsp; if ($Prompt -is [ScriptBlock])<br \/>&nbsp;&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $null = New-Item function:Prompt -Value $Prompt -force<br \/>&nbsp;&nbsp;&nbsp;&nbsp; }else<br \/>&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; function Prompt {&#8220;$Prompt&#8221;}<br \/>&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp; }<br \/>&nbsp; $host.EnterNestedPrompt()<br \/>}<br \/>sal sans Start-NewScope<\/font><\/p>\n<p>BTW &#8211; every time you enter a nested prompt, $NESTEDPROMPTLEVEL is incremented so I include this information in my prompt:<\/p>\n<p><font face=\"Courier New\" size=\"2\">function prompt<br \/>{<br \/>&#8220;[{0}:{1}]MSH&gt; &#8221; -f $PID, $NestedPromptLevel<br \/>}<\/font><\/p>\n<p>So watch that as I create and exit new scopes.&nbsp; I&#8217;ll create a new scope, redefine some aliases and then exit the scope and show how those aliases are cleaned up and the old aliases are now in scope.<\/p>\n<p><font face=\"Courier New\" size=\"2\">[3312:0]MSH&gt; gal write |ft name,definition -auto<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">Name&nbsp; Definition<br \/>&#8212;-&nbsp; &#8212;&#8212;&#8212;-<br \/>write write-object<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">[3312:0]MSH&gt; write test<br \/>test<\/p>\n<p># NOW WE START A NEW SCOPE AND REDEFINE WRITE<br \/>[3312:0]MSH&gt; sans<br \/>Starting New Scope<br \/>[3312:1]MSH&gt; sal write write-error<br \/>[3312:1]MSH&gt; write test<br \/>write test : test<br \/>[3312:1]MSH&gt; gal write |ft name,definition -auto<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">Name&nbsp; Definition<br \/>&#8212;-&nbsp; &#8212;&#8212;&#8212;-<br \/>write write-error<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\"># NOW WE EXIT THE SCOPE WHICH REMOVES THIS ALIAS <br \/># WHICH NOW REVEALS THE PREVIOUS DEFINITION<\/font><br \/><font face=\"Courier New\" size=\"2\">[3312:1]MSH&gt; exit<br \/>[3312:0]MSH&gt; write test<br \/>test<br \/>[3312:0]MSH&gt; gal write |ft name,definition -auto<\/font><\/p>\n<p><font face=\"Courier New\" size=\"2\">Name&nbsp; Definition<br \/>&#8212;-&nbsp; &#8212;&#8212;&#8212;-<br \/>write write-object<\/font><\/p>\n<p>Enjoy!<\/p>\n<p>Jeffrey Snover<br \/>Monad Architect<\/p>\n<p>[<i>Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.<\/i>]<\/p>\n<p>PSMDTAG:FAQ: Is it save to use ALIASES in scripts?<\/p>\n<p>PSMDTAG:FAQ: What is the difference between CONSTANT and READONLY?<\/p>\n<p>PSMDTAG:FAQ: Nested Prompt &#8211; How do I know if I&#8217;m in a nested prompt? $NestedPromptLevel<\/p>\n<p>PSMDTAG:CMDLET: Get-Alias, gal, <\/p>\n<p>PSMDTAG:INTERNAL: built in aliases are READONLY, ALLSCOPE&nbsp;which makes reasonably safe to use in scripts.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In&nbsp;our newsgroup (Microsoft.Public.Windows.Server.Scripting) , Mark Ayers asked the question:&gt; Shouldn&#8217;t best practice for scripts be full command name? The answer is YES, NO, and MAYBE. YES &#8211; Full names provide the most readable experience for scripts.&nbsp; This is very important.&nbsp; People&nbsp;often throw the rock at Perl saying that it is a &#8220;write-only language&#8221; meaning that [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[10],"class_list":["post-10761","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","tag-faq"],"acf":[],"blog_post_summary":"<p>In&nbsp;our newsgroup (Microsoft.Public.Windows.Server.Scripting) , Mark Ayers asked the question:&gt; Shouldn&#8217;t best practice for scripts be full command name? The answer is YES, NO, and MAYBE. YES &#8211; Full names provide the most readable experience for scripts.&nbsp; This is very important.&nbsp; People&nbsp;often throw the rock at Perl saying that it is a &#8220;write-only language&#8221; meaning that [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/10761","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=10761"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/10761\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=10761"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=10761"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=10761"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}