Delen via


Is it safe to use ALIASES in scripts?

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, AllScope
gc get-content ReadOnly, AllScope
gci get-childitem ReadOnly, AllScope
gcm get-command ReadOnly, AllScope
gdr get-drive ReadOnly, AllScope
ghy get-history ReadOnly, AllScope
gi get-item ReadOnly, AllScope
gl get-location ReadOnly, AllScope
gm get-member ReadOnly, AllScope
gp get-property ReadOnly, AllScope
gps get-process ReadOnly, AllScope
group group-object ReadOnly, AllScope
gsv get-service ReadOnly, AllScope
gu get-unique ReadOnly, AllScope
gv get-variable ReadOnly, AllScope

MSH> gal ?v | where {""+$_.options -match "Readonly" } |
ft name, definition, options -auto

Name Definition Options
---- ---------- -------
gv get-variable ReadOnly, AllScope
nv new-variable ReadOnly, AllScope
rv remove-variable ReadOnly, AllScope
sv set-variable ReadOnly, AllScope

MSH> gal n* | where {""+$_.options -match "Readonly" } |
ft name, definition, options -auto

Name Definition Options
---- ---------- -------
nal new-alias ReadOnly, AllScope
ndr new-drive ReadOnly, AllScope
ni new-item ReadOnly, AllScope
nv new-variable ReadOnly, AllScope

MSH> gal *al | where {""+$_.options -match "Readonly" } | ft name, definition, options -auto

Name Definition Options
---- ---------- -------
epal export-alias ReadOnly, AllScope
gal get-alias ReadOnly, AllScope
ilal initialize-alias ReadOnly, AllScope
ipal import-alias ReadOnly, AllScope
nal new-alias ReadOnly, AllScope
sal 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 test
test

# NOW WE START A NEW SCOPE AND REDEFINE WRITE
[3312:0]MSH> sans
Starting New Scope
[3312:1]MSH> sal write write-error
[3312:1]MSH> write test
write 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 test
test
[3312:0]MSH> gal write |ft name,definition -auto

Name Definition
---- ----------
write write-object

Enjoy!

Jeffrey Snover
Monad Architect

Comments

  • Anonymous
    April 16, 2006
    Excellent discussion.  It sheds light on many useful elements including teh question of how to catch the script "exit" for cleanup tasks.

    It would be useful to have a "built-in" export converter for scripts that would convert all aliases for portability.  This would allow for efficient typing without the need to find and converrt temporary or non-portable aliases.  It would also accomplish eliminating the worry over aliases.

  • Anonymous
    April 16, 2006
    > It would be useful to have a "built-in" export converter for
    > scripts that would convert all aliases for portability.

    We've talked about this from about day 2 of the project.  It has never risen to the top of the to-do list for V1.  I'm not sure whether it will for V2 or not - it all depends on customer feedback - e.g. is this a REAL problem or a POTENTIAL problem.  That said, what is more likely to occur is that we've been discussing the benefits of publishing our parse tree (the results of our parser) using public classes or exporting it to XML.  This would enable a whole range of community supplied utilities functions like the one mentioned here.  

    As always, there is no promise that this will be coming but I thought I would share the current state-of-thought.

    jps
  • Anonymous
    April 16, 2006
    >we've been discussing the benefits of publishing our parse tree (the results of our parser) using public classes or exporting it to XML

    That would work.

    It's probably not a REAL problem and with fore-knowledge it shouldn't be a POTENTIAL problem.  Anyway, we can build an external script parser that will work for now as everything needed is already in MSH.

    Thanks for the info.  V1 is looking real good.
  • Anonymous
    January 21, 2009
    The comment has been removed
  • Anonymous
    May 29, 2009
    PingBack from http://paidsurveyshub.info/story.php?title=monad-is-it-safe-to-use-aliases-in-scripts