I have a script where function parameters are expressed like this:
param(
${param1},
${param2},
${param3}
)
What does it mean? I have been unable to find documentation on this.
What's the point of writing parameters that way instead of the more usual
param(
$param1,
$param2,
$param3
)
?
#MikeZ's answer is quite correct in explaining the example in the question, but as far as addressing the question title, there is actually more to say! The ${} notation actually has two uses; the second one is a hidden gem of PowerShell:
That is, you can use this bracket notation to do file I/O operations if you provide a drive-qualified path, as defined in the MSDN page Provider Paths.
(The above image comes from the Complete Guide to PowerShell Punctuation, a one-page wallchart freely available for download, attached to my recent article at Simple-Talk.com.)
They are both just parameter declarations. The two snippets are equivalent. Either syntax can be used here, however the braced form allows characters that would not otherwise be legal in variable names. From the PowerShell 3.0 language specification:
There are two ways of writing a variable name: A braced variable name, which begins with $, followed by a curly bracket-delimited set of one or more almost-arbitrary characters; and an ordinary variable name, which also begins with $, followed by a set of one or more characters from a more restrictive set than a braced variable name allows. Every ordinary variable name can be expressed using a corresponding braced variable name.
From about_Variables
To create or display a variable name that includes spaces or special characters, enclose the variable name in braces. This directs Windows PowerShell to interpret the characters in the variable name literally.
For example, the following command creates and then displays a variable named "save-items".
C:\PS> ${save-items} = "a", "b", "c"
C:\PS> ${save-items}
a
b
c
They are equivalent. It's just an alternative way of declaring a variable.
If you have characters that are illegal in a normal variable, you'd use the braces (think of it as "escaping" the variablename).
There is one additional usage.
One may have variable names like var1, var2, var11, var12, var101, etc.
Regardless if this is desirable variable naming, it just may be.
Using brackets one can precisely determine what is to be used:
assignment of $var11 may be ambiguous, using ${var1}1 or ${var11} leaves no room for mistakes.
Related
Exploring the difference between help and get-help I did:
cd Function:
get-content help
all the input-parameter are defined like: [string]${Name}
$=initiate a variable, {} a hashtable??
Thanks for your help.
For the official documentation, see the conceptual about_Variables help topic (invoke it with help about_Variables), and in particular its "Variable Names that Include Special Characters" section.
Enclosing the name of a variable in {...} - e.g. ${foo} - unambiguously delimits the variable name (foo).
While you can use this notation with any variable reference, doing so is required in the following scenarios:
If the name contains unusual characters, such as - or . (see the linked help topic for the exact set of permissible characters); e.g.:
${foo-bar}
${foo.bar}
If the variable reference is embedded in an expandable string ("..."), you may need to tell PowerShell where the variable name ends, if the immediately following characters would otherwise be interpreted as part of the variable name; e.g.:
"${foo}: bar" - without the {...}, PowerShell would interpret $foo: as an (incomplete) variable name, which fails, because foo is then interpreted as the name of a PS drive in the context of namespace variable notation.
Note: An alternative in this case is to `-escape the : character: "$foo`: bar"
"A ${foo}l and his money ..." - without the {...}, PowerShell would look for variable $fool instead.
While in your example (${Name}) enclosing in {...} is not necessary, the reason that it is used is that the code was automatically generated as a proxy function that wraps the Get-Help cmdlet, and this generation mechanism methodically encloses all variables in {...}.
I recently discovered that you can get powershell's functions by reference using the modifier $function:. But I noticed a strange problem...
By convention, POSH uses a {Verb}-{Noun} convention for function names, where {Verb} is part of aproved POSH verb names. For instance: Get-Member or Invoke-WebRequest.
The thing is, that calling $function:Get-Member, for example, is not valid because of the hyphen; it works just fine if you declare a function like ShowMessage and calls: $fn = $function:ShowMessage. So I'd like to know if there's a way to escape this call.
PS.: I do know of another option, but is much much more verbose:
function Show-Message { Write-Host "Foo"; }
$fn = (Get-Item "function:Show-Message").ScriptBlock;
$fn.Invoke();
Update: Although #PetSerAl was very helpfull and explained the problem, I'll mark #Ansgar Wiechers's response as the answer because it's better documented.
function: is a PSDrive, not a (scope)modifier. As for using it with variable-like notation ($function:name): the rules for variable names with special characters apply here as well.
From the documentation:
VARIABLE NAMES THAT INCLUDE SPECIAL CHARACTERS
Variable names begin with a dollar sign. They can include alphanumeric characters and special characters. The length of the variable name is limited only by available memory.
Whenever possible, variable names should include only alphanumeric characters and the underscore character (_).Variable names that include spaces and other special characters, are difficult to use and should be avoided.
To create or display a variable name that includes spaces or special characters, enclose the variable name in braces. This directs PowerShell to interpret the characters in the variable name literally.
Your notation should thus look like this:
${function:Show-Message}
It can be invoked like this:
& ${function:Show-Message}
PS > function ]{1}
PS > ]
1
PS >
PS
Why does this work?
What else can I name a function? All I've found so far that works is * and ].
You can name it almost anything. You can even include newlines and emoji* in the name.
function Weird`nFunctionの名前😀 { Write-Host hey }
$c = gcm Weird*
$c.Name
& $c
Escaping helps with lots of things like that:
function `{ { Write-Host cool }
`{
function `0 { Write-Host null }
gci function:\?
I'll add that this is true for variables too, and there's a syntax that removes the need to do most escaping in the variable name: ${varname} (as opposed to $varname).
With that, you could easily do:
${My variable has a first name,
it's
V
A
something
R,
whatever I dunno
🤷} = Get-Process
You'll note that if you then start typing like $MyTAB it will tab complete in a usable way.
To (somewhat) answer why this should work, consider that the variable names themselves are just stored in .Net strings. With that in mind, why should there be a limit on the name?
There will be limits on how some of these names can be used in certain contexts, because the parser will not understand what to do with it if the names don't have certain characters escaped, but literal parsing of PowerShell scripts are not the only way to use functions or variables or other language constructs, as I've shown some examples of.
Being less limiting also means being able to support other languages and cultures by having wide support for character sets.
To this end, here's one more thing that might surprise you: there are many different characters to represent the same or similar things that we take for granted in code, like quotation marks for example.
Some (human) languages or cultures just don't use the same quote characters we do in English, don't even have them on the keyboard. How annoying would it be to type code if you have to keep switching your keyboard layout or use ALT codes to quote strings?
So what I'm getting at here is that PowerShell actually does support many quote characters, for instance, what do you think this might do:
'Hello’
Pretty obvious it's not the "right" set of quotes on the right side. But surprisingly, this works just fine, even though they aren't the same character.
This does have important implications if you're ever generating code from user input and want to avoid sneaky injection attacks.
Imaging you did something like this:
Invoke-Expression "echo '$($userMsg -replace "'","''")'"
Looks like you took care of business, but now imagine if $userMsg contained this:
Hi’; gci c: -recurse|ri -force -whatif;'
For what it's worth, the CodeGeneration class is aware of this stuff ;)
Invoke-Expression "echo '$([System.Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($userMsg))'"
* PowerShell Console doesn't have good support for Unicode, even though the language does. Use ISE to better see the characters.
This is a weird one. Normally when I execute an external command from powershell I use the & operator like this:
& somecommand.exe -p somearguments
However, today I came across the . operator used like this:
.$env:systemdrive\chocolatey\chocolateyinstall\chocolatey.cmd install notepadplusplus
What purpose does the period serve in this scenario? I don't get it.
The "." dot sourcing operator will send AND receive variables from other scripts you have called. The "&" call operator will ONLY send variables.
For instance, considering the following:
Script 1 (call-operator.ps1):
clear
$funny = "laughing"
$scriptpath = split-path -parent $MyInvocation.MyCommand.Definition
$filename = "laughing.ps1"
"Example 1:" # Call another script. Variables are passed only forward.
& $scriptpath\$filename
"Example 2:" # Call another script. Variables are passed backwards and forwards.
. $scriptpath\$filename
$variableDefinedInOtherScript
Script 2 (laughing.ps1):
# This is to test the passing of variables from call-operator.ps1
"I am $funny so hard. Passing variables is so hilarious."
$variableDefinedInOtherScript = "Hello World!"
Create both scripts and ONLY run the first one. You'll see that the "." dot sourcing operator sends and receives variables.
Both have their uses, so be creative. For instance, the "&" call operator would be useful if you wanted to modify the value(s) of variables in another script while preserving the original value(s) in the your current script. Kinda a safeguard. ;)
The Short:
It is a Special Operator used to achieve what regular operators cannot achieve. This particular operator . actually has two distinctively different Special Operator use cases.
The Long:
As with any other language, scripting or otherwise, PowerShell script also supports many different types of Operators to help manipulate values. These regular operators include:
Arithmetic
Assignment
Comparison
Logical
Redirection
List item
Split and Join
Type
Unary
However, PowerShell also supports whats known as Special Operators which are used to perform tasks that cannot be performed by the other types of operators.
These Special Operators Include:
#() Array subexpression operator
& Call operator
[ ] Cast operator
, Comma operator
. Dot sourcing operator
-f Format operator
[ ] Index operator
| Pipeline operator
. Property dereference operator
.. Range operator
:: Static member operator
$( ) Subexpression operator
. Dot sourcing operator: is used in this context to allow a script to run in the current scope essentially allowing any functions, aliases, and variables which has been created by the script to be added to the current script.
Example:
. c:\scripts.sample.ps1
NoteThat this application of the . Special Operator is followed by a space to distinguish it from the (.) symbol that represents the current directory
Example:
. .\sample.ps1
. Property dereference operator: Allows access to the properties and methods of of an object which follows the . by indicating that the expression on the left side of the . character is an object and the expression on the right side of the is an object member (a property or method).
Example:
$myProcess.peakWorkingSet
(get-process PowerShell).kill()
Disclaimer & Sources:
I had the same question while looking at a PowerShell script that I was trying to expand on its feature sets and landed here when doing my research for the answer. However I managed to find my answer using this magnificent write up on the Microsoft Development Network supplemented with this further expansion of the same ideas from IT Pro.
Cheers.
The dot is a call operator:
$a = "Get-ChildItem"
. $a # (executes Get-ChildItem in the current scope)
In your case, however, I don't see what it does.
.Period or .full stop for an objects properties; like
$CompSys.TotalPhysicalMemory
See here: http://www.computerperformance.co.uk/powershell/powershell_syntax.htm#Operators_
This answer is to expand slightly upon those already provided by David Brabant and his commenters. While those remarks are all true and pertinent, there is something that has been missed.
The OPs use of & when invoking external commands is unnecessary. Omitting the & would have no effect (on the example of his usage). The purpose of & is to allow the invocation of commands whose names are the values of a (string) expression. By using the & above, powershell then (essentially) treats the subsequent arguments as strings, the first of which is the command name that & duly invokes. If the & were omitted, powershell would take the first item on the line as the command to execute.
However, the . in the second example is necessary (although, as noted by others, & would work just as well in this case). Without it, the command line would begin with a variable access ($env:systemdrive) and so powershell would be expecting an expression of some form. However, immediately following the variable reference is a bare file path which is not a valid expression and will generate an error. By using the . (or &) at the beginning of the line, it is now treated as a command (because the beginning doesn't look like a valid expression) and the arguments are processed as expandable strings (" "). Thus, the command line is treated as
. "$env:systemdrive\chocolatey\chocolateyinstall\chocolatey.cmd" "install" "notepadplusplus"
The first argument has $env:systemdrive substituted into it and then . invokes the program thus named.
Note: the full description of how powershell processes command line arguments is way more complicated than that given here. This version was cut down to just the essential bits needed to answer the question. Take a look at about_Parsing for a comprehensive description. It is not complete but should cover most normal usage. There are other posts on stackoverflow and github (where powershell now resides) that cover some of the seemingly quirky behaviour not listed in the official documentation. Another useful resource is about_Operators though again this isn't quite complete. An example being the equivalence of . and & when invoking something other than a powershell script/cmdlet getting no mention at all.
I am a novice. My question is what is the "-" before the keys (type, expires name etc) standing for? Why not just use the plain hash table way and discard the hyphen?
# #!/usr/local/bin/perl -w
use CGI;
$q = CGI->new;
print $q->header(-type=>'image/gif',-expires=>'+3d');
$q->param(-name=>'veggie',-value=>'tomato');
The author already explained in the documentation.
Most CGI.pm routines accept several
arguments, sometimes as many as 20
optional ones! To simplify this
interface, all routines use a named
argument calling style that looks like
this:
print
$q->header(-type=>'image/gif',-expires=>'+3d');
Each argument name is preceded by a
dash. Neither case nor order matters
in the argument list. -type, -Type,
and -TYPE are all acceptable. In
fact, only the first argument needs to
begin with a dash. If a dash is
present in the first argument, CGI.pm
assumes dashes for the subsequent
ones.
Several routines are commonly called
with just one argument. In the case
of these routines you can provide the
single argument without an argument
name. header() happens to be one of
these routines. In this case, the
single argument is the document type.
print $q->header('text/html');
See perlop:
If the operand is an identifier, a string consisting of a minus sign concatenated with the identifier is returned. Otherwise, if the string starts with a plus or minus, a string starting with the opposite sign is returned. One effect of these rules is that -bareword is equivalent to the string "-bareword". (emphasis mine)
This is just an older style of perl arguments that isn't usually used in newer modules. It's not exactly deprecated, it's just an older style based on how Perl allows you to not quote your hash keys if they start with a dash.
I don't know what you mean by the 'plain hashtable way'. The way CGI::pm is implemented, names of properties are (in most cases) required to be preceded by '-', presumably so that they can be identified.
Or to put it another way, the hash-key required by CGI::header to identify the 'type' property is '-type'.
That's just the way CGI.pm is defined.