How to correctly concatenate string in Powershell inline script in Azure DevOps?

后端 未结 3 1874
旧巷少年郎
旧巷少年郎 2021-01-16 18:08

I try to concatenate string to construct a path:

$SourceDirectoryPath = $(System.DefaultWorkingDirectory) + \"/solution/project/bin/Debug\"
$TargetFilePath =         


        
相关标签:
3条回答
  • 2021-01-16 18:48

    Note: $(System.DefaultWorkingDirectory) in the question is an Azure Pipeline macro (variable), expanded by Azure before PowerShell sees the command - it is not to be confused with PowerShell's own subexpression operator, $(...).


    Shayki Abramczyk's answer provides an effective solution, but let me provide some background information:

    The value expansion (substitution) that Azure performs via macro $(...) functions like a preprocessor: it replaces the referenced property 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 bsed 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.
    0 讨论(0)
  • 2021-01-16 18:53

    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'
    
    0 讨论(0)
  • 2021-01-16 19:09

    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)"
    
    0 讨论(0)
提交回复
热议问题