在PowerShell中如何有条件地将参数的强制属性设置为$true?

huangapple go评论69阅读模式
英文:

How to set mandatory attribute of a parameter to $true conditionally in PowerShell?

问题

以下是您要翻译的内容:

"属性mandatory接受ScriptBlocks,但经过我的测试以及在其他答案中看到的情况,它总是返回$true

function Test-Function {
    param (
        [Parameter (Position = 0)]
        [string]$First,

        [Parameter (Position = 1, Mandatory = ({
            return $false
        }))]
        [string]$Second
    )
    Write-Host 'First: $First'
    Write-Host 'Second: $Second'
}
Test-Function -First 'boo'

我不想使用动态参数,因为Get-Help不显示它们(除非我漏掉了什么?),而且我已经在多个地方使用ParameterSets,所以不能破坏它们的逻辑。

有什么其他方法可以实现我想要的?

我的目标是首先从用户配置文件中读取数据,如果参数的值已经在该文件中可用,那么该参数应该从强制变为可选。"

英文:

The mandatory attribute accepts ScriptBlocks but as I've tested it and seen in other answers, it's always returning $true

function Test-Function {
    param (
        [Parameter (Position = 0)]
        [string]$First,

        [Parameter (Position = 1, Mandatory = ({
            return $false
        }))]
        [string]$Second
    )
    Write-Host "First: $First"
    Write-Host "Second: $Second"
}
Test-Function -First "boo"

I don't want to use Dynamic parameters because Get-Help doesn't show them (unless I'm missing something?), and I'm already using ParameterSets a lot, so can't break their logic.

What are some other ways I can achieve what I want?

my goal is to first read from a user configuration file and if a value for a parameter is already available in that file then the parameter should turn from mandatory to optional.

答案1

得分: 1

以下是您要翻译的内容:

The Mandatory attribute accepts ScriptBlocks

It technically accepts a script block, but passing one is pointless, given that the property's type is [bool]: [bool] { &lt;# whatever #&gt; } is always $true, as with any non-primitive object cast to [bool].<sup>[1]</sup>

Only attributes explicitly designed to accept script blocks support them meaningfully, typically via the attribute constructor rather than (only) via one of its properties (e.g. [ValidateScript({ &lt;# whatever #&gt; })])

我已经完成对上述内容的翻译。如果您需要更多翻译或其他帮助,请告诉我。

英文:

<!-- language-all: sh -->

Note:

  • The next two sections make general observations.

  • The bottom section shows an alternative solution to your own.


> The Mandatory attribute accepts ScriptBlocks

It technically accepts a script block, but passing one is pointless, given that the property's type is [bool]: [bool] { &lt;# whatever #&gt; } is always $true, as with any non-primitive object cast to [bool].<sup>[1]</sup>

Only attributes explicitly designed to accept script blocks support them meaningfully, typically via the attribute constructor rather than (only) via one of its properties (e.g. [ValidateScript({ &lt;# whatever #&gt; })])


> I don't want to use dynamic parameters because Get-Help doesn't show them

Get-Help (and the -? parameter) do show them, but only if the runtime conditions for their addition are met.

Therefore, the only way to always make a dynamic implementation of your -Second parameter show would be to add it unconditionally inside the DynamicParam block used to implement dynamic parameters, and to only make its Mandatory property dynamic, depending on runtime conditions.

However:

  • Dynamic parameters are generally nontrivial to implement.

  • Assigning a default value to a dynamic parameter - which is what you want - appears to be unsupported (assigning to the .Value property of a dynamic parameter is in effect quietly ignored).


The following alternative to your solution moves all processing into the $(...) subexpression:

function Test-Function {
  param (
      [Parameter(Position = 0)]
      [string] $First
      ,
      [Parameter(Position = 1)]
      [ValidatePattern(&#39;^[a-zA-Z0-9 ]+$&#39;)]
      [string] $Second = $(            
          # Try to obtain a default value and make sure one is available.
          $val = (Get-Content -Path &quot;$env:USERPROFILE\.WDACConfig\UserConfigurations.json&quot; | ConvertFrom-Json).policyname
          if ($null -eq $val) { 
            throw &quot;A -Second argument is required or must be preconfigured.&quot;
          }
          # A default value is available:
          # Validate it based on the [ValidatePattern()] attribute.
          $validatePatternAttrib = $MyInvocation.MyCommand.Parameters[&#39;Second&#39;].Attributes.Where({ $_ -is [System.Management.Automation.ValidatePatternAttribute]})
          if (-not [regex]::Match($val, $validatePatternAttrib.RegexPattern, $validatePatternAttrib.Options).Success) {
            throw (&quot;The argument `&quot;$val`&quot; does not match the `&quot;$($validatePatternAttrib.RegexPattern)`&quot; pattern.&quot;, ($validatePatternAttrib.ErrorMessage -f $val))[[bool] $validatePatternAttrib.ErrorMessage]
          }
          $val # Output the default value to assign it to the parameter var.
      )
  )
  process {
      Write-Host &quot;First: $First&quot;
      Write-Host &quot;Second: $Second&quot;
  }
}
Test-Function -First &quot;boo&quot;

Note:

  • While scoping the solution to the default-value code inside $(...) is desirable, there is added complexity due to having to dynamically apply the [ValidatePattern()] attribute to the default value (the code could be simplified; as shown it fully emulates what the [ValidatePattern()] does).

  • Arguably, this added complexity shouldn't be necessary, as even a default value should automatically be subject to the same validation as an explicitly passed one. GitHub issue #8795 proposes just that.


<sup>[1] PowerShell allows implicit conversion to [bool] from any type. See the bottom section of this answer for a summary of the rules.</sup>

答案2

得分: 0

So, I came up with this solution and seems to be working, haven't validated it with every possible scenario I have in mind but for now seems to be working, will update if I find any shortcoming.

function Test-Function {
    param (
        [string]$First,        
        [string]$Second = $(            
            ((Get-Content -Path "$env:USERPROFILE\.WDACConfig\UserConfigurations.json" | ConvertFrom-Json).policyname)                   
        )       
    )
    begin {
        if (!$Second) {
            throw "Variable Second was empty"
        }

    }
    process {
        Write-Host "First: $First"
        Write-Host "Second: $Second"
    }
}
Test-Function -First "boo"

Caveat 1: ValidatePattern attribute doesn't work with this method and fails to validate the default values assigned to the parameter from the file, but this will take care of it.

$UserConfig = (Get-Content -Path "$env:USERPROFILE\.WDACConfig\UserConfigurations.json" | ConvertFrom-Json)
function Test-Function {
    param (
        [parameter(ParameterSetName = "Installed AppXPackages", ValueFromPipelineByPropertyName = $true)]
        [string]$First,
        
        [parameter(ParameterSetName = "Installed AppXPackages", ValueFromPipelineByPropertyName = $true)]
        [string]$Second = $(            
            ($UserConfig.policyname)                   
        )       
    )
    begin {
        if (!$Second) {
            throw "Variable Second was empty"
        }
        elseif ($Second -notmatch '^[a-zA-Z0-9 ]+$') {
            throw "The Supplemental Policy Name can only contain alphanumeric characters and spaces."
        }

    }
    process {
        Write-Host "First: $First"
        Write-Host "Second: $Second"
    }
}
Test-Function -First "boo" -Second "fdsf"
英文:

So, I came up with this solution and seems to be working, haven't validated it with every possible scenario I have in mind but for now seems to be working, will update if I find any shortcoming.

function Test-Function {
    param (
        [string]$First,        
        [string]$Second = $(            
            ((Get-Content -Path &quot;$env:USERPROFILE\.WDACConfig\UserConfigurations.json&quot; | ConvertFrom-Json).policyname)                   
        )       
    )
    begin {
        if (!$Second) {
            throw &quot;Variable Second was empty&quot;
        }

    }
    process {
        Write-Host &quot;First: $First&quot;
        Write-Host &quot;Second: $Second&quot;
    }
}
Test-Function -First &quot;boo&quot;

Caveat 1: ValidatePattern attribute doesn't work with this method and fails to validate the default values assigned to the parameter from the file, but this will take care of it.

$UserConfig = (Get-Content -Path &quot;$env:USERPROFILE\.WDACConfig\UserConfigurations.json&quot; | ConvertFrom-Json)
function Test-Function {
    param (
        [parameter(ParameterSetName = &quot;Installed AppXPackages&quot;, ValueFromPipelineByPropertyName = $true)]
        [string]$First,
        
        [parameter(ParameterSetName = &quot;Installed AppXPackages&quot;, ValueFromPipelineByPropertyName = $true)]
        [string]$Second = $(            
            ($UserConfig.policyname)                   
        )       
    )
    begin {
        if (!$Second) {
            throw &quot;Variable Second was empty&quot;
        }
        elseif ($Second -notmatch &#39;^[a-zA-Z0-9 ]+$&#39;) {
            throw &quot;The Supplemental Policy Name can only contain alphanumeric characters and spaces.&quot;
        }

    }
    process {
        Write-Host &quot;First: $First&quot;
        Write-Host &quot;Second: $Second&quot;
    }
}
Test-Function -First &quot;boo&quot; -Second &quot;fdsf&quot;

huangapple
  • 本文由 发表于 2023年5月21日 19:16:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76299627.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定