In our newsgroup (Microsoft.Public.Windows.Server.Scripting) , Mark Ayers asked the question:> Shouldn't best practice for scripts be full command name?
The answer is YES, NO, and MAYBE.
YES - Full names provide the most readable experience for scripts. This is very important. People often throw the rock at Perl saying that it is a "write-only language" meaning that after you write a script, you can't read it or understand what it does. 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. As such, script readability has always been a strong focus for us. 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).
NO - Not all aliases are the same. There are a special class of aliases that are READONLY and ALLSCOPE. You can find these with the following command:
gal | where {""+$_.options -match "Readonly" } | ft name, definition, options -auto
Take a look at how regular and predictable these are:
MSH> gal g* | where {""+$_.options -match "Readonly" } | ft name, definition, options -auto
Name Definition Options---- ---------- -------gal get-alias ReadOnly, AllScopegc get-content ReadOnly, AllScopegci get-childitem ReadOnly, AllScopegcm get-command ReadOnly, AllScopegdr get-drive ReadOnly, AllScopeghy get-history ReadOnly, AllScopegi get-item ReadOnly, AllScopegl get-location ReadOnly, AllScopegm get-member ReadOnly, AllScopegp get-property ReadOnly, AllScopegps get-process ReadOnly, AllScopegroup group-object ReadOnly, AllScopegsv get-service ReadOnly, AllScopegu get-unique ReadOnly, AllScopegv get-variable ReadOnly, AllScope
MSH> gal ?v | where {""+$_.options -match "Readonly" } | ft name, definition, options -auto
Name Definition Options---- ---------- -------gv get-variable ReadOnly, AllScopenv new-variable ReadOnly, AllScoperv remove-variable ReadOnly, AllScopesv set-variable ReadOnly, AllScope
MSH> gal n* | where {""+$_.options -match "Readonly" } | ft name, definition, options -auto
Name Definition Options---- ---------- -------nal new-alias ReadOnly, AllScopendr new-drive ReadOnly, AllScopeni new-item ReadOnly, AllScopenv new-variable ReadOnly, AllScope
MSH> gal *al | where {""+$_.options -match "Readonly" } | ft name, definition, options -auto
Name Definition Options---- ---------- -------epal export-alias ReadOnly, AllScopegal get-alias ReadOnly, AllScopeilal initialize-alias ReadOnly, AllScopeipal import-alias ReadOnly, AllScopenal new-alias ReadOnly, AllScopesal set-alias ReadOnly, AllScope
In previous drops, these aliases where CONSTANT which meant that users could not delete or remove them. They exist because they are very predictable and pithy short hands for the long names. 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. The community provided strong feedback that MSFT should not ship any CONSTANT aliases so we made them READONLY and ALLSCOPE. This means that you can remove them (using the -FORCE flag) and create your own definitions but it is strongly discouraged.
So in the end, you are pretty safe using the aliases that are READONLY and CONSTANT. You might argue that this is less safe then using the full command name. This would not be correct. Token resolution works by first expanding aliases then binding to a function, then a cmdlet, lastly as an external executable. When you type "Get-Process" - it could have been aliased to any other command or there could be a function with this name. So in the end, the READONLY ALLSCOPE aliases are just about as safe as the full command names.
MAYBE. The other thing you can do in your script is to set up the aliases you'll use yourself. Aliases are scoped so this is generally a safe operation and will not contaminate the users environment. Let me demonstrate using a one of my favorite functions that I define in my profile file, Start-NewScope and its alias sans
function Start-NewScope {param($Prompt = $null) Write-Host "Starting New Scope" if ($Prompt -ne $null) { if ($Prompt -is [ScriptBlock]) { $null = New-Item function:Prompt -Value $Prompt -force }else { function Prompt {"$Prompt"} } } $host.EnterNestedPrompt()}sal sans Start-NewScope
BTW - every time you enter a nested prompt, $NESTEDPROMPTLEVEL is incremented so I include this information in my prompt:
function prompt{"[{0}:{1}]MSH> " -f $PID, $NestedPromptLevel}
So watch that as I create and exit new scopes. I'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.
[3312:0]MSH> gal write |ft name,definition -auto
Name Definition---- ----------write write-object
[3312:0]MSH> write testtest# NOW WE START A NEW SCOPE AND REDEFINE WRITE[3312:0]MSH> sansStarting New Scope[3312:1]MSH> sal write write-error[3312:1]MSH> write testwrite test : test[3312:1]MSH> gal write |ft name,definition -auto
Name Definition---- ----------write write-error
# NOW WE EXIT THE SCOPE WHICH REMOVES THIS ALIAS # WHICH NOW REVEALS THE PREVIOUS DEFINITION[3312:1]MSH> exit[3312:0]MSH> write testtest[3312:0]MSH> gal write |ft name,definition -auto
Enjoy!
Jeffrey SnoverMonad Architect