I have an Azure Devops Pipeline Task for .NET Core, specifying the 'test' command.
One of the parameters is 'Path to project(s)'. You can specify multiple globbing patterns, each on its own line.
Now I want to make this value settable at queueing time by using a variable $(UnitTestPatterns). But a variable cannot have a multiline value. How can I specify 2 or more globbing patterns in a way that all are evaluated?
I have tried a pipe '|', a comma ',' and a semicolon ';' as separators, none have worked. The log of the task then shows ##[warning]Project file(s) matching the specified pattern were not found.
Example multiline value:
**/Project.*.Tests/*.csproj
!**/Project.Module2.Tests/*.csproj
I want a variable like this (with probably some secret separator, the ';' does not work):
$(UnitTestPatterns) = **/Project.*.Tests/*.csproj; !**/Project.Module2.Tests/*.csproj
I am using the UI to set the variable, not YAML.
It looks that this is not supported. Please check this topic on Developer Community. You may also check this topic where you will find workaround.
Related
I am writing a program prog.exe that retrieves all arguments that are passed to it (in the form of a "sentence", not standalone arguments).
I just realized that in some cases only part of the line is retrieved, and this is when there are #parameters:
PS > ./prog.exe this is a #nice sentence
Only this, is and a are retrieved. In case I do not use # I get all of them. I presume this is because everything after the # is interpreted by Powershell as a comment.
Is there a way to retrieve everything that is on the command line?
If this makes a difference, I code in Go and get the arguments via os.Args[1:].
You can prevent PowerShell from interpreting # as a comment token by explicitly quoting the input arguments:
./prog.exe one two three '#four' five
A better way exists, though, especially if you don't control the input: split the arguments into individual strings then use the splatting operator # on the array containing them:
$paramArgs = -split 'one two three #four five'
./prog.exe #paramArgs
Finally, using the --% end-of-parsing token in a command context will cause the subsequent arguments on the same line to be passed as-is, no parsing of language syntax:
./prog.exe --% one two three #four five
I try to concatenate string to construct a path:
$SourceDirectoryPath = $(System.DefaultWorkingDirectory) + "/solution/project/bin/Debug"
$TargetFilePath = $(System.DefaultWorkingDirectory) + "/solution/project/bin/Debug/" + $(Release.ReleaseName) +$(Release.EnvironmentName)
but instead of getting string concatenated I get error for the second line:
d:\a\r1\a : The term 'd:\a\r1\a' is not recognized as the name of a
cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path
is correct and try again. At
D:\a_temp\9de874c9-3acd-4a19-a4dd-763074d38e40.ps1:2 char:25
where obviously d:\a\r1\a is a $(System.DefaultWorkingDirectory) but why it throws this error instead of just concatenating the string?
tl;dr
It is Azure that expands $(System.DefaultWorkingDirectory) before PowerShell sees the resulting commands; if the expanded $(...) value is to be seen as a string by PowerShell, it must be enclosed in quotes ('$(...)'):
Using $(...) (Azure macro syntax) embeds the Azure variable's verbatim value in the command text that PowerShell ends up interpreting.
Note: Azure's macro syntax - which is evaluated before PowerShell sees the resulting command text - is not to be confused with PowerShell's own subexpression operator, $(...).
For string values this means that you situationally have to surround the macro with quotes in order to make it work syntactically in PowerShell code, for which '...'-quoting (single-quoting) is best: '$(System.DefaultWorkingDirectory)'
Shayki Abramczyk's answer provides an effective solution, but let me provide some background information:
The variable expansion (substitution) that Azure performs via macro syntax ($(...)) functions like a preprocessor: it replaces the referenced variable with its verbatim value.
You need to make sure that this verbatim value works syntactically in the context of the target command.
As currently written:
$SourceDirectoryPath = $(System.DefaultWorkingDirectory) + "/solution/project/bin/Debug"
turns into the following command seen by PowerShell, assuming that the value of Azure property System.DefaultWorkingDirectory is d:\a\r1\a:
$SourceDirectoryPath = d:\a\r1\a + "/solution/project/bin/Debug"
This is a broken PowerShell command, because d:\a\r1\a - due to lack of quoting - is interpreted as a command name or path; that is, an attempt is made to execute putative executable d:\a\r1\a - see about_Parsing.
Therefore, in order for PowerShell to recognize the Azure-expanded value d:\a\r1\a as a string, you need to quote it - see about_Quoting_Rules.
Since the expanded-by-Azure value needs no further interpolation, single quotes are the best choice (for both operands, actually):
$SourceDirectoryPath = '$(System.DefaultWorkingDirectory)' + '/solution/project/bin/Debug'
In fact, you don't need string concatenation (+) at all in your case:
$SourceDirectoryPath = '$(System.DefaultWorkingDirectory)/solution/project/bin/Debug'
You could even combine that with expandable PowerShell strings ("..."), as long as the Azure-expanded value doesn't contain $-prefixed tokens that PowerShell could end up interpreting (unless that is your (unusual) intent).
One caveat re something like "$(System.DefaultWorkingDirectory)/$projectRoot/bin/Debug" (mixing an Azure-expanded value with a PowerShell variable reference) is that Azure's macro syntax ($(...)) looks the same as PowerShell's own subexpression operator, which is typically - but not exclusively - used in order to embed expressions in expandable strings (e.g., in pure PowerShell code, "1 + 1 equals $(1 + 1)").
As of this writing, the Define variables Azure help topic doesn't spell it out, but based on the official comment in a GitHub docs issue, ambiguity is avoided as follows:
There is no escape mechanism; instead, $(...) constructs that do not refer to Azure variables are left unchanged and therefore passed through to PowerShell.
In the typical case, PowerShell expressions will not look like an Azure variable reference (e.g, $($foo.bar) rather than $(foo.bar)), though hypothetically there can be ambiguity: $(hostname), which is a valid PowerShell subexpression, could be preempted by Azure if a hostname Azure variable were defined.
In such a corner case, the solution is to avoid use of an inline script and instead place the code in an external script file.
You need to add quotes " " in the variables:
$SourceDirectoryPath = "$(System.DefaultWorkingDirectory)" + "/solution/project/bin/Debug"
$TargetFilePath = "$(System.DefaultWorkingDirectory)" + "/solution/project/bin/Debug/" + "$(Release.ReleaseName)" + "$(Release.EnvironmentName)"
This should work as well. $( ) outside of doublequotes would only be used to combine two or more statements. Most people don't even know about it.
This is actually incorrect. I didn't know Azure Pipeline syntax. It just shows how confusing combining both Powershell and Azure Pipeline can be. This would work if $System were a Powershell object, not an Azure macro.
$SourceDirectoryPath = $System.DefaultWorkingDirectory + '/solution/project/bin/Debug'
I came across this and was wondering what this means and how it works?
What's the significance of using #regex here and how does it expand?
https://github.com/microsoft/azure-pipelines-tasks/blob/master/Tasks/DownloadPackageV0/task.json
"endpointUrl": "{{endpoint.url}}/{{ **#regex ([a-fA-F0-9\\-]+/)[a-fA-F0-9\\-]+ feed }}_apis**/Packaging/Feeds/{{ **#regex [a-fA-F0-9\\-]*/([a-fA-F0-9\\-]+) feed** }}{{#if view}}#{{{view}}}{{/if}}/Packages?includeUrls=false"
Also I would like to know how many packages will it return and display in the Task input UI dropdown if there are thousands of packages in the feed. Is there a known limit like first 100 or something?
#regex doesn't appear to actually be documented anywhere, but it takes two space-delimited arguments. The first is a regular expression and the second is a "path expression" identifying what value to match against, in this case the value of the feed input parameter. If the regex matches the value, it returns the first capturing subexpression, otherwise it returns the empty string.
In this particular context, the feed parameter is formatted as 'projectId/feedId', where projectId and feedId are GUIDs, and projectId and the / are eliminated for organization-scoped feeds (i.e. feeds that are not inside a project). The first regex therefore extracts the project ID and inserts it into the URL, and the second regex extracts the feed ID and inserts it into the URL.
As of this writing, the default limit on the API it's calling is 1000.
Regex stands for regular expression, which allows you to match any pattern rather than an exact string. You can find more info on how to use it in Azure Devops here
This regex is very specific. In this case, the regex ([a-fA-F0-9\\-]+/)[a-fA-F0-9\\-]+\ matches one or more of the following 1) letters a-f (small or capital) Or 2) \ Or 3) - followed by / and then again one or more of those characters.
You can copy the regex [a-fA-F0-9\\-]+/)[a-fA-F0-9\\-]+ into https://regexr.com/ to play around with it, to see what does and doesn't match the pattern.
Examples:
it matches: a/a a/b abcdef-\/dcba
but doesn't match: /a, abcdef, this-doesn't-match
Note that the full endpoint consists of concatenations of both regular expression and hardcoded strings!
I am able to escape double quote character in PowerShell however when this includes strings with space escaping does not work correctly.
For example:
I can translate the following ADUC to powershell
Name in ADUC: cn="Jim"
In powershell: "cn=\`"Jim\`""
How do I handle/escape the space between Jim and Carter as below ?
Name in ADUC: cn="Jim Carter"
In powershell: "cn=\`"Jim Carter\`""
The output I get is Jim, the space and string Carter are lost.
PowerShell has hidden re-quoting logic when arguments are passed to external utilities.
What you're seeing is bug in Windows PowerShell (that has since been fixed in PowerShell Core):
In short, "cn=\`"Jim Carter\`"" is passed to an external executable as cn=\"Jim Beam\", which unexpectedly turns into two arguments - note how the argument is not double-quoted as a whole, even though it needs to be.
Workarounds:
As part of a distinguished name in Active Directory, component values (such as Jim Beam for field cn) usually do not need double-quoting, even if they contain spaces. Therefore, perhaps the following will work (depending on the behavior of the executable you're invoking).
someExternalTool.exe "cn=Jim Beam"
If you do need the executable to ultimately see string literal cn="Jim Beam", you must use --%, the stop-parsing symbol:
someExternalTool.exe --% "cn=\"Jim Beam\""
If you want the executable to see cn=\"Jim Beam\", i.e., with the " chars. \-escaped, use someExternalTool.exe --% "cn=\\\"Jim Beam\\\""
Note that use of --% then precludes the use of PowerShell variables as part of the same command.
In PowerShell Core, your original argument, "cn=\`"Jim Carter\`"" is passed as "cn=\"Jim Carter\"" - i.e. with the necessary double-quoting as a whole - so the problem with the unexpected argument splitting wouldn't arise, and your target program would see cn="Jim Beam" after performing its own argument parsing.
If you need the target program to see cn=\"Jim Beam\", you'd have to use "cn=\\\`"Jim Beam\\\`"" - or, using single-quoting, 'cn=\\\"Jim Beam\\\"'
As an aside: The need to \-escape " chars. to pass to external programs - in addition to PowerShell's own escaping - should itself be considered a bug, but it's a longstanding one that probably won't be fixed so as to maintain backward compatibility: see this GitHub issue.
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.