是否可以使用模块功能来修改调用者脚本的参数值?

时间:2019-05-02 16:36:17

标签: function powershell module scope

动机

减少对Azure DevOps任务的维护,该任务调用具有很多参数(“很多”可能是5)的Powershell脚本。

该想法基于Azure DevOps生成环境变量以反映生成变量这一事实。因此,我设计了以下方案:

  1. 使用MyBuild.前缀所有非秘密Azure DevOps变量
  2. 任务powershell脚本将调用一个函数以根据MyBuild_环境变量检查脚本参数,并在以下情况下自动将MyBuild_xyz环境变量的值分配给脚本参数xyz后者没有价值。

这样,任务命令行将只包含秘密参数(不会在环境中反映出来)。通常,没有秘密参数,因此命令行保持为空。我们发现这种方案可以减少对Powershell脚本驱动的任务的维护。

示例

param(
    $DBUser,
    [ValidateNotNullOrEmpty()]$DBPassword,
    $DBServer,
    $Configuration,
    $Solutions,
    $ClientDB = $env:Build_DefinitionName,
    $RawBuildVersion = $env:Build_BuildNumber,
    $BuildDefinition = $env:Build_DefinitionName,
    $Changeset = $env:Build_SourceVersion,
    $OutDir = $env:Build_BinariesDirectory,
    $TempDir,
    [Switch]$EnforceNoMetadataStoreChanges
)

$ErrorActionPreference = "Stop"

. $PSScriptRoot\AutomationBootstrap.ps1
$AutomationScripts = GetToolPackage DevOpsAutomation

. "$AutomationScripts\vNext\DefaultParameterValueBinding.ps1" $PSCommandPath -Required 'ClientDB' -Props @{
    OutDir = @{ DefaultValue = [io.path]::GetFullPath("$PSScriptRoot\..\..\bin") }
    TempDir = @{ DefaultValue = 'D:\_gctemp' }
    DBUser = @{ DefaultValue = 'SomeUser' }
}

所描述的参数绑定逻辑在脚本 DefaultParameterValueBinding.ps1 中实现,该脚本发布在NuGet程序包中。该代码将安装软件包,从而可以访问脚本。

在上面的示例中,某些参数默认为预定义的Azure Devops变量,例如$RawBuildVersion = $env:Build_BuildNumber。有些未初始化,例如$DBServer,这意味着它将默认为$env:MyBuild_DBServer

我们可以不用特殊的功能来进行绑定,但是脚本作者必须编写如下代码:

$DBServer = $env:MyBuild_DBServer,
$Configuration = $env:MyBuild_Configuration,
$Solutions = $env:MyBuild_Solutions,

我想避免这种情况,因为可能会出现意外的名称不匹配的情况。

问题

当我将 DefaultParameterValueBinding.ps1 的逻辑打包到模块函数中时,该方法不起作用。这是因为模块作用域隔离-我只是不能修改调用者脚本的参数。

还有可能吗?是否可以更优雅地实现我的目标?记住,我想减少与在Azure DevOps中维护任务命令行相关的成本。

现在我倾向于退回到这个计划:

$xyz = $(Resolve-ParameterValue 'xyz' x y z ...)

Resolve-ParameterValue首先要检查$env:MyBuild_xyz的位置,如果找不到,请从x,y,z,...中选择第一个非空值。

但是,如果Resolve-ParameterValue方法来自某个模块,则该脚本必须假定该模块已经安装,因为在评估参数之前无法安装该模块。还是有?

编辑1

请注意,用于调用 DefaultParameterValueBinding.ps1 脚本的命令行不包含调用方脚本参数!它确实包含$PSCommandPath,用于获取PSBoundParameters集合。

1 个答案:

答案 0 :(得分:1)

是的,但是需要对调用脚本和函数进行修改。通过引用传递参数。亚当·B(Adam B.)在以下内容中很好地介绍了如何通过引用传递参数:

https://mcpmag.com/articles/2015/06/04/reference-variables-in-powershell.aspx

网络,下面是一个示例:

$age = 12;

function birthday {
  param([ref]$age)
  $age.value += 1
}

birthday -age ([ref]$age)

Write-Output $age

我已经12岁了,我将其作为参数传递给函数。该函数将$ age的值增加1。您可以对模块中的函数执行相同的操作。你让我流连忘返。