I came across a script that obfuscated its calls using the dot sourcing operator.
$ORMEFyak=.('n'+'ew-obje'+'ct') NeT.WebcLIENt;
This seems to be equivalent to:
$var = New-Object Net.WebClient
Running . "help" returns the contents of the help cmdlet.
Why exactly does the dot source operator act like this?
The behavior is not specific to ., the dot-sourcing operator; it equally applies to &, the call operator.
Only when you're invoking a script file (*.ps1) (or, less commonly, function or script block) do . and & behave differently: . runs the code directly in the caller's scope, whereas &, which is more typical, runs it in a child scope - see this answer for more information.
In the case of New-Object, as a cmdlet, you can technically use them interchangeably (or omit them altogether - see below), but for conceptual clarity it's better to use & unless actual dot-sourcing is required.
It isn't so much that they convert a string to a command, it is that their purpose is to execute a command given by its name, as a string, among other forms (see below).
The specific syntax used to provide or construct this name for . or & is incidental, and in your case a string-concatenation expression was used to obscure the name of the command being invoked.
However, specifying the name of a command unquoted, verbatim (if syntactically possible) is special in that you can then invoke without an operator - & is then implied; see below for an example.
Therefore, all of the following variations are equivalent (for the reasons stated above, I'm using &):
# Bareword (unquoted, verbatim) command name
# If you don't need dot-sourcing, you can invoke *as-is* -
# use of & is implied.
New-Object regex 'foo?'
# Optionally, use &
& New-Object regex 'foo?'
# If the command name *needs quoting*, is *(based on) a variable* or
# *built by an expression*, & is *required*
$cmd = 'New-Object'
& $cmd regex 'foo?'
& ('New-' + 'Object') regex 'foo?'
Note that in addition to acting on command names (strings), . and & can also invoke script blocks (e.g. & { New-Object regex 'foo?' }) and command-information objects returned by Get-Command (e.g., & (Get-Command New-Object) regex 'foo?')
Related
In GNU/Linux I would do:
PROGPATH=/long/and/complicated/path/to/some/bin
$PROGPATH/program args...
but in Powershell if I try this:
$PROGPATH=\long\and\complicated\path\to\some\bin
$PROGPATH\program args...
I get:
At script.ps1:2 char:...
+ $PROGPATH\program args ...
+ ~~~~~~~~
Unexpected token '\program' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
So how do I do this simple thing I know how to do in bash, in Powershell?
js2010's helpful answer shows the correct solution:
Because your command name/path contains a variable reference ($PROGPATH/...), you must invoke it with &.
The same applies if a grouping expression, (...) is used, or a subexpression, $(...) is involved.
Additionally, the same applies if a command name/path is quoted ('...' or "...")[1], as is required if the path contains spaces, for instance.
To put it differently: Direct invocation is only supported if the command name/path is a verbatim, unquoted string[1]; in all other cases, & must be used.
As for why:
&, the call operator is necessary to force interpretation of a statement as a command, i.e. to have it parsed in argument mode (see below), so as to result in command execution rather than expression evaluation.
PowerShell has two fundamental parsing modes:
argument mode, which works like a traditional shell, where the first token is a command name/path, such as a cmdlet or an external program, with subsequent tokens representing the arguments, which only require quoting if they contain shell metacharacters (chars. with special meaning to PowerShell, such as spaces to separate tokens).
expression mode, which works like expressions in programming languages.
PowerShell decides based on a statement's first token what parsing mode to apply:
If, among other things, the first token starts with a variable reference or is a quoted string, PowerShell parses in expression mode.
In expression mode, \ starts a new token, and unrecognized token \program results in the syntax error you saw.
(If you had used /, it would have been interpreted as the division operator, and program wouldn't be a valid divisor operand.)
[1] Note that if your executable path is a literal string (doesn't contain variable references of expressions) you may alternatively `-escape individual characters (spaces) in lieu of enclosing entire string in '...' or "...", in which case & is then not necessary; e.g.:
C:\Program` Files\Notepad++\notepad++.exe
With a literal string you can even employ partial single- or double-quoting as long as the first token is unquoted; e.g.:
C:\"Program Files"\Notepad++\notepad++.exe
Use the call operator "&". https://ss64.com/ps/call.html
Related: Executing a command stored in a variable from PowerShell
$progpath = 'c:\windows\system32'
& $progpath\notepad somefile.txt
Something with a space:
& 'C:\Program Files\internet explorer\iexplore' yahoo.com
Other options, adding to the path:
$env:path += ';C:\Program Files\internet explorer'
iexplore yahoo.com
And backquoting the spaces:
C:\Program` Files\internet` explorer\iexplore yahoo.com
On linux I can rappresent the / char in a different way:
${HOME:0:1}
So, for example, cat ${HOME:0:1}etc${HOME:0:1}passwd would be treated like cat /etc/passwd
Is there any way I can do the same thing on windows via powershell and cmd.exe for the backslash?
PowerShell has no equivalent to the parameter expansions available in POSIX-compatible shells such as Bash, of which your substring extraction (${HOME:0:1} to get the substring of length 1 at character position 0, i.e the first char. of the value of variable $HOME) is an example (link is to the Bash manual).
However, PowerShell makes it easy:
to embed the results of arbitrary expressions and even whole statements inside expandable (double-quoted) string ("..."), using $(...), the subexpression operator.
to pass the results of any expression or command (pipeline) as an argument to a command, by enclosing it in (...), the grouping operator.
The following command variations are equivalent, and dynamically use the platform-appropriate path (directory) separator, i.e. / on Unix-like platforms, and \ on Windows:
# -> '/etc/passwd' on Unix
# -> '\etc\passwd' on Windows
Write-Output "$([System.IO.Path]::DirectorySeparatorChar)etc$([System.IO.Path]::DirectorySeparatorChar)passwd"
# Ditto.
Write-Output ('{0}etc{0}passwd' -f [System.IO.Path]::DirectorySeparatorChar)
See also:
[System.IO.Path]::DirectorySeparatorChar
-f, the string format operator
How to set preference $ErrorView = "CategoryView" before start powershell.exe ?
powershell.exe -command "$ErrorView = "CategoryView" ; dir wrong.txt" doesnt work.
your code has a serious error in it. you used 4 double quotes instead of two on the outside and a pair of single quotes on the inside. [grin]
this works ...
powershell.exe -command "$ErrorView = 'CategoryView' ; dir wrong.txt; pause"
remove the pause when you are certain things are working as needed. [grin]
To complement Lee Dailey's helpful answer: As Lee points out, your primary problem is that you neglected to escape the " chars. embedded in your overall "..." command.
Assuming that you're calling your command from outside of PowerShell, such as from cmd.exe (Command Prompt):
Using embedded single-quoting ('...') in lieu of the embedded "..." is an option in this case, as shown in Lee's answer, because CategoryView is to be treated as a literal string.
Using ' for the embedded quoting conveniently obviates the need for escaping.
However, in cases where the embedded string contains variable references (e.g., $var) or expressions (e.g, $(Get-Date)), use of a double-quoted string ("...") is a must, because only double-quoted strings are expandable (interpolated). Escaping the embedded " as \" is then a must.
Note that, by contrast, inside PowerShell " chars. must be escaped as `".
# From cmd.exe, for instance.
C:\>powershell.exe -command "$ErrorView = \"CategoryView\"; dir wrong.txt"
If, for some reason, you must invoke another PowerShell instance from within PowerShell, use a script block ({ ... }), which also obviates the need for escaping (and better integrates with the calling session by returning objects from the invocation, not just strings).
# From Powershell.
PS> powershell.exe -command { $ErrorView = "CategoryView" ; dir wrong.txt }
A Perl system call must send the following string to the UnixShell:
'"XYZ"'
In my Perl script I have used the following command:
system("cleartool mkattr -replace ATTRIBUTE '"$attribute"' lbtype:$label");
Everything is well passed to the Shell Unix, except both uses of the quote character:
'
Indeed,
cleartool mkattr -replace ATTRIBUTE
The above command is passed as it is exactly what I want.
The Perl variables $attribute and $label are well interpreted.
But I don't know what to do to obtain exactly:
'"XYZ"'
Here XYZ is the value of the Perl variable $attribute
OS is AIX (Unix) and Shell is ksh. cleartool is the command line interface of Clearcase but no Clearcase skill is necessary to fix my problem.
If you want to execute a system command and don't have to use any shell syntax like redirects, it's usually better and safer to use the list form of system:
system(
'cleartool', 'mkattr', '-replace', 'ATTRIBUTE',
qq{"$attribute"}, qq{lbtype:$label}
);
# or, if you really want to pass both types of quotes:
system(
'cleartool', 'mkattr', '-replace', 'ATTRIBUTE',
qq{'"$attribute"'}, qq{lbtype:$label}
);
See perldoc -f system
It's not clear from your question if you want to pass '"XYZ"' or "XYZ".
See "Quote and Quote like Operators" and use qq{...}:
system(qq{cleartool mkattr -replace ATTRIBUTE '"$attribute"' lbtype:$label});
qq{...} is exactly like "..." except you can then use double quotes " in your string without escaping them.
You can use any character directly after the qq and must then use the same character to denote the end-of-string, i.e. qqX...X would work the same way. You would run into problems if your string contains Xes, so don't do that.
You can also use paired characters as delimiter ({}, (), <>) which is what you usually will see.
In Vim, I can echo the current filename using this command:
:echo #%
I found that information here: http://vim.wikia.com/wiki/Get_the_name_of_the_current_file
Can someone explain why the # symbol is necessary? If I enter the command without the # symbol, I get an error:
E15: Invalid expression: %
E15: Invalid expression: %
However, if I try to send the filename to a bang command as an argument, including the # sign appears as a regular character in the argument. Removing the # sign works. In other words, in my .bash_profile I have the following function:
test_func() {
echo $1
}
In Vim, I run:
:! test_func #% #outputs #path/to/my/file
:! test_func % #outputs path/to/my/file
What is the # symbol doing and why does it behave differently when sending the output to a bash function?
:echo takes a Vimscript expression, whereas :! takes and external command, which is a special case for a filename, which is accepted by :edit et al.
For external commands and filenames, there are special characters such as % and #, described under :help cmdline-special. This also includes this crucial sentence:
In Ex commands, at places where a file name can be used, the following
characters have a special meaning.
In contrast, :echo does not take a filename, but an expression. There are several ways to resolve the current filename; the most direct is via expand():
:echo expand('%')
Alternatively, as the current filename is also stored in a special register %, and registers are addressed via the # sigil:
:echo #%
The other way around
This also explains the frequent question of why :edit g:variable doesn't work as expected. Vim's evaluation rules are different than most programming languages. You need to use :execute in order to evaluate a variable (or expression); otherwise, it's taken literally; i.e. Vim uses the variable name itself as the argument.
I believe that is :h expr-register:
register expr-register #r
#r contents of register 'r'
The result is the contents of the named register, as a single string.
Newlines are inserted where required. To get the contents of the unnamed
register use #" or ##. See |registers| for an explanation of the available
registers.
When using the '=' register you get the expression itself, not what it
evaluates to. Use |eval()| to evaluate it.
As to why you don't need that for :! that is probably because of :h cmdline-special.
Ex special characters cmdline-special
Note: These are special characters in the executed command line. If you want
to insert special things while typing you can use the CTRL-R command. For
example, "%" stands for the current file name, while CTRL-R % inserts the
current file name right away. See |c_CTRL-R|.
Note: If you want to avoid the special characters in a Vim script you may want
to use |fnameescape()|.
In Ex commands, at places where a file name can be used, the following
characters have a special meaning. These can also be used in the expression
function expand() |expand()|.
% Is replaced with the current file name. :_% c_%