使用内置系统变量创建 Powershell 环境变量

Posted

技术标签:

【中文标题】使用内置系统变量创建 Powershell 环境变量【英文标题】:Create Powershell env variables using built in System variables 【发布时间】:2021-11-01 03:58:44 【问题描述】:

我有一个 Powershell 脚本,它将向 SonarQube 的 REST API 发出 GET 请求,以检查质量门是通过还是失败。如果质量门失败,管道将失败。我可以在只查看主分支时完成这项工作,但是,我正在尝试查看所有分支并拉取请求。

我的管道 Powershell 脚本:

  - job:
  
    pool:
      name: 'POEM-GBT-Agent'

    variables:
    - group: SonarQube

    displayName: 'SonarQube API'
    
    steps:
    - checkout: none
    - powershell: |
        $token = [System.Text.Encoding]::UTF8.GetBytes("$(SONARQUBE_API_TOKEN)" + ":")
        $base64 = [System.Convert]::ToBase64String($token)
        
        $basicAuth = [string]::Format("Basic 0", $base64)
        $headers = @ Authorization = $basicAuth 

        if ($(System.PullRequest.PullRequestId)) 
           $param = "pullRequest=$(System.PullRequest.PullRequestId)"
        
        else 
          $param = "branch=$env:$BRANCH_NAME"
        
        
        $result = Invoke-RestMethod -Method Get -Uri https://sonarqube.tjx.com/api/qualitygates/project_status?projectKey=$(sonarProjectKey)"&"$param -Headers $headers
        $result | ConvertTo-Json | Write-Host
        
        if ($result.projectStatus.status -ne "OK") 
          Write-Host "##vso[task.logissue type=error]Quality Gate Failed"
          Write-Host "##vso[task.complete result=Failed]"
        

        env:
          BRANCH_NAME: replace('$(Build.SourceBranch)', 'refs/heads/', '')

这会导致错误提示:

+   $param = "branch=$env:$BRANCH_NAME"
+                    ~~~~~
Variable reference is not valid. ':' was not followed by a valid variable name 
character. Consider using $ to delimit the name.
    + CategoryInfo          : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : InvalidVariableReferenceWithDrive

收到此错误后,我将条件语句更改为:

        if ($(System.PullRequest.PullRequestId)) 
           $param = "pullRequest=$(System.PullRequest.PullRequestId)"
        
        else 
          $param = "branch=$env:$BRANCH_NAME"
        

更改条件后出现此错误:

System.PullRequest.PullRequestId : The term 'System.PullRequest.PullRequestId' 
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:\GBT\agent\Workspace\_temp\0a756446-474a-4d58-94ff-ad25e38c3c7a.ps1:9 
char:7
+ if ($(System.PullRequest.PullRequestId)) 
+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (System.PullRequest.PullRequestI 
   d:String) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : CommandNotFoundException

如果 Git PR 受到影响,我将尝试将 $param 设置为 pullRequest=1234,否则,我想将 $param 设置为 branch=feature/my-branch-name 之类的东西。

【问题讨论】:

您可能已经知道这一点,但 Sonarqube 扩展已将其作为任务实现。 【参考方案1】:

这里有两个问题。我将深入研究下面的每一个。


无法识别术语“System.PullRequest.PullRequestId”

在你的工作step 下,定义一些环境变量。我在 Azure DevOps 方面的经验有限(从这里开始称为 ADO),但您需要在 powershell 环境变量定义下使用两个(您已经有 BRANCH_NAME,但我将在下面包含它):

- job:
  steps:
  - powershell: |
      YOUR
      CODE
      HERE

    env:
      BRANCH_NAME: replace('$(Build.SourceBranch)', 'refs/heads/', '')
      PULL_REQUEST_ID: $(System.PullRequest.PullRequestId)

您需要将 PULL_REQUEST_ID 定义为 env var,因为您渲染的 PowerShell 脚本不会将 $() 渲染为来自 ADO 的插入值。这很可能是设计使然,因为$() 是其他编程语言including PowerShell 中使用的语法。这是您问题的症结所在,无法将System.PullRequest.PullRequestId 作为命令找到; PowerShell 从字面上尝试将其用作无法找到的程序名称。

然后,您可以在脚本中引用拉取请求 ID:

$env:PULL_REQUEST_ID

变量引用无效。 ':' 后面没有有效的变量名字符

该问题与上述问题不同,但解决方案是相同的。只需将环境变量引用为:

$env:BRANCH_NAME

您不需要额外的$,因为这只会混淆解析器。

现在,您不是要求这个,但是如果您需要一个条件环境变量名称(例如,环境变量的名称来自某个其他 ADO 变量),您需要使用不同的语法来访问环境变量,因为$ 在通过$env: 语法访问时会混淆解析器。 如果您对此感到好奇,请继续阅读


如果您确实需要访问名称为条件的环境变量

PowerShell 不允许在未将变量名指定为字符串的情况下在变量名中使用特殊字符。值得注意的例外是_(无特殊含义)和:,后者用作PSDrive 中定义的变量的分隔符。环境变量可通过Environment 提供程序访问,该提供程序可在EnvPSDrive 下访问。您可以通过运行Get-PSDrive 看到这一点,Env 驱动器下暴露了一个Environment 提供程序。

你可以通过几种方式引用PSProvider变量,最常见的方式是$drive:path(变量名在技术上被认为是提供者下的路径节点)。所以要引用UserProfile 变量,你可以使用:

$env:UserProfile # ====> Returns the path to your user profile directory

您的代码存在以下问题:

$env:$VariableName

在这种情况下,目的是获取一个环境变量值,其名称基于另一个变量的值,但这会使该语法的解析器感到困惑,因为 $ 现在被翻译为变量名称的文字部分,这是无效的。通常你会使用$ 语法来避免这种情况......但你不能在这里,因为混淆的部分应该呈现为同一个变量的一部分。在这种情况下,您需要使用另一种方法来访问环境变量,直接通过提供程序。

再次以UserProfile为例:

$envVarName = 'UserProfile'
$envVarValue = (Get-ChildItem Env:/$envVarName).Value

这是从PSProvider 获取值的另一种方法;将其内容作为驱动器遍历。这有点像文件系统,尽管Get-ChildItem 将针对不同的提供者类型返回不同的属性,而不是您可能习惯于来自Filesystem 提供者的FileInfoDirectoryInfo 对象。这有点麻烦,但幸运的是,这不是人们经常需要考虑的情况。

【讨论】:

这非常有帮助,非常感谢!我将我的$param 更改为$param = 'pullRequest"&"branch=$(( Get-ChildItem Env:/$BRANCH_NAME ).Value)',这完全符合我的要求。 $env:PULL_REQUEST_ID 有一些问题,正如它所说:"errors":["msg":"An error has occurred. Please contact your administrator"] 这让我觉得我在听 PR 不正确 根据the docs,System.PullRequest.PullRequestId 仅在“由于Git PR affected by a branch policy 而运行构建”时才会初始化。 如果您对此行为还有其他问题,我建议您提出一个新问题,因为这个问题专注于解决 PowerShell 语法错误,但您现在遇到了一个与执行上下文相关的新问题你的 ADO 管道。

以上是关于使用内置系统变量创建 Powershell 环境变量的主要内容,如果未能解决你的问题,请参考以下文章

(23)Powershell中的首选项变量

Shell变量

Powershell中的内置变量

使用PowerShell修改操作系统“环境变量”

如何在配置文件中定义的 PowerShell 脚本中设置环境变量?

Shell之环境变量、局部变量