PowerShell,当有 2+ 个值时,从 [string[]] 参数剪裁的前导零

powershell, leading zero trimed from [string[]] parameters when there is 2+ values

提问人:Peyre 提问时间:11/17/2023 最后编辑:Peyre 更新时间:11/18/2023 访问量:67

问:

我有一个 cmdlet,它接受电话号码列表作为参数。某些电话号码的第一个字符为 0。当我只用一个数字调用函数时,字符串保持原样。当我用 2+ 数字调用函数时,前导零被修剪

function user {
    [CmdletBinding()]
    param (
        [Parameter(mandatory,position=0)]
        [string[]]
        $numbers
    )

    process {

        $numbers
        $users = @{
            '0600000001' = 'user1'
            '0600000002' = 'user2'
        }

        foreach($key in $users.keys) {
            if($numbers -contains $key) {
                write-host $users[$key]
            }
        }
    }
}

例如

[PS] D:\> user 0600000001
0600000001
user1

[PS] D:\> user 0600000002
0600000002
user2

[PS] D:> user 0600000001,0600000002
600000001
600000002

当然,如果我在数字周围加上引号,它会按预期工作

[PS] D:\> user '0600000001','0600000002'
0600000001
0600000002
user2
user1

但是该 cmdlet 不适合我的使用,用户非常热衷于忘记在参数周围加上引号。

我用谷歌搜索了一下,发现了很多关于 PS 修改字符串的帖子/文章,但找不到如何防止它的解决方案。

你有什么线索吗?

PowerShell的

评论

0赞 Olaf 11/17/2023
我会让它一次只接受一个号码,并根据需要重复拨打它。🤷🏼‍♂️
1赞 James Ruskin 11/17/2023
可悲的是,这在某种程度上取决于 PowerShell 处理和转换参数的方式。您可以通过添加参数并删除逗号来绕过它?ValueFromRemainingArguments

答:

1赞 mklement0 11/18/2023 #1

我认为您观察到的行为是一个错误,此后在 GitHub 问题 #20717 中报告了该错误:

  • 在参数(分析)模式下使用标量参数(单个值)时,当 PowerShell 的参数绑定器最初分析它可以分析为数字文本的内容时,它会这样做,即将参数转换为数字类型(如 [int]),同时还保留原始字符串表示形式,以防目标命令最终不需要数字

    • 示例包括 、 、 、 偶数 或(数字类型后缀)06000000012.30xA1e21l1d

      • 但是,与表达式模式不同的是,以数字开头或解析为数字的标记仍为字符串 ()。+-[string]
    • 此行为是通过将生成的数字实例(例如类型)包装在缓存原始字符串表示形式的不可见 [psobject] 包装器中来实现的;后者可以通过调用 - 来检索,但不能通过可扩展字符串中的字符串插值来检索 ([int].psobject.ToString().ToString()"...")

    • .psobject.ToString()在以下情况下隐式调用:

      • 调用外部程序时,因为传递原始字符串表示形式很重要,因为该上下文中没有类型概念,因此将原始参数(如 into)转换为是不合适的。0xA10

      • 在默认的显示格式设置期间。

      • 当投射到[string]

  • 数组参数中,即使没有充分的理由对每个元素执行相同的包装(这在技术上是可行的,因为 PowerShell 数组是类型化的,即其元素可以存储任何类型的值)。[object[]]

    • 请注意,在您的调用中,不会表达式(解析)模式下解析 - 它仍然在参数模式下解析,在该模式下,数组构造受支持(除非在调用外部程序时,其中不存在数组的概念),元素的解析方式与单个参数模式参数相同。user 0600000001,06000000020600000001,0600000002,

    • 例如,是 的全参数模式等价物
      ,即具有嵌套表达式的参数模式语句。
      Write-Output foo, barWrite-Output ('foo', 'bar')

要简明扼要地演示问题,请执行以下操作:

& {
  param($Value) # implicitly [object]-typed - see below for why
  foreach ($v in $Value) { 
    [pscustomobject] @{
      StringRepresentation = $v.ToString()
      OriginalStringRepresentation = $v.psobject.ToString()
      Type = $v.GetType()
      IsPSObjectWrapped = $Value -is [psobject]
    }
 }
} 042

这将输出以下内容,显示参数被解析为 with value ,但包装在具有缓存的原始字符串表示形式的实例中:042[int]42[psobject]

StringRepresentation OriginalStringRepresentation Type         IsPSObjectWrapped
-------------------- ---------------------------- ----         -----------------
42                   042                          System.Int32              True

转换到此类参数的数组表明此包装已丢失
传递而不是产生:
042, 043, +44, -45042

StringRepresentation OriginalStringRepresentation Type          IsPSObjectWrapped
-------------------- ---------------------------- ----          -----------------
42                   42                           System.Int32              False
43                   43                           System.Int32              False
+44                  +44                          System.String             False
-45                  -45                          System.String             False

请注意 and 的原始字符串表示形式是如何丢失的,而 and 由于其前缀而被解析为字符串042043+44-45

注意:

  • 示例脚本块使用非类型(即隐式类型化参数),该参数可以在没有显式类型转换的情况下检查行为。[object]

    • 如果参数已声明为 (aka ),即使在参数情况下,原始字符串表示也会丢失,这本身可以被视为一个错误。[object[]][Array]
  • 使用类型化参数,如您的问题所示,它确实适用于参数情况,但在多参数情况下会失败,因为在构造数组时原始字符串表示形式已经丢失,因为丢失发生在初始的幕后,必要的基于数组解析。[string[]][string[]][object]

评论

0赞 mklement0 11/18/2023
@Mathias:我认为你不需要删除你的答案 - 通过适当的框架,它会显示出一个有效的替代解决方案。
1赞 Peyre 11/21/2023
我在其原始生态系统 (PS v2) 中测试了该 cmdlet,但该错误不存在。在 v4 和 v5.1 中,它存在。因此,这不仅仅是一个错误,更是一个回归:(
0赞 mklement0 11/21/2023
我明白了,@Peyre。虽然我的感觉是这不会很快得到解决,但如果你 - 以及任何有兴趣看到这个问题修复的人 - 给链接的 GitHub 问题竖起大拇指,它会有所帮助。
0赞 Peyre 11/24/2023
我想用一个示例为 GitHub 做出贡献,就像我添加到这篇文章的编辑中的示例一样,但我没有 PS > 5.1 来测试这是否也会发生在上一个版本中。ValidatePattern 是否也会在 PS v7.x 中抛出错误?
0赞 mklement0 11/28/2023
@Peyre,是的,它也未能通过 PS v7+ 中的验证(看到的值已经从其原始字符串表示中剥离)。[ValidatePattern()]