【问题标题】:No error when selecting non-existing property选择不存在的属性时没有错误
【发布时间】:2015-12-30 13:45:36
【问题描述】:

我希望 PowerShell 在尝试选择不存在的属性时抛出错误,但我得到的是空列作为输出。示例:

$ErrorActionPreference=[System.Management.Automation.ActionPreference]::Stop;
Set-StrictMode -Version 'Latest'
Get-Process *ex* | Select-Object Id,ProcessName,xxx

   Id ProcessName   xxx
   -- -----------   ---
 9084 explorer
11404 procexp

我编写了一个脚本,该脚本通过Import-Csv 导入多个文本文件,但这些文件中的标题可能会更改,并且我最终会将空列加载到系统中。

编辑: 这就是我检查标题是否匹配的方式:

$csv = Import-Csv -Delimiter ';' -Path $file.FullName 
$FileHeaders = @(($csv | Get-Member -MemberType NoteProperty).Name) 
if (Compare-Object $ProperHeaders $FileHeaders) {'err'} else {'ok'}

我知道这就是 PowerShell 的工作方式,但正如 @Matt 所提到的,Set-StrictMode 文档对我来说确实有点误导。我只希望Select-Object 有某种“-NoNewImplicitProps”或“-ReadOnlyPipeline”开关可以为我完成这项工作:)。感谢您的回答。

【问题讨论】:

  • 不要认为你可以这样做,因为这就是 Powershell 的设计方式。如果这成为可能,那么这将打破$newobj = '' | Select-Object prop1,prop2

标签: powershell powershell-4.0 select-object


【解决方案1】:

您实际上正在使用some people would call a feature。这是在所有数组成员上使用Add-Member 以添加空列的更简单的演绎。

Import-CSV 的情况下,您在这种情况下所做的是检查属性名称​​之前您调用它们的Select

$data = Import-csv C:\Temp\file.csv 
$props = $data | Get-member -MemberType 'NoteProperty'  | Select-Object -ExpandProperty Name

我可以看到文档有点misleading when it says for Set-StrictMode:

禁止引用对象不存在的属性。

但在这种情况下,您不是试图获取属性引用,而是使用Select-Object cmdlet 的函数。但是以下会产生错误

PS C:\Users\mcameron> Set-StrictMode -Version 'Latest'
(Get-Process *ex*).Bagels
The property 'Bagels' cannot be found on this object. Verify that the property exists.
At line:2 char:1
+ (Get-Process *ex*).Bagels
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], PropertyNotFoundException
    + FullyQualifiedErrorId : PropertyNotFoundStrict

【讨论】:

    【解决方案2】:

    PowerShell 将不存在的属性扩展到 $null 的行为符合设计。 AFAICS 唯一能做的就是明确检查所有属性是否存在:

    $props = 'Id', 'ProcessName', 'xxx'
    
    $p = Get-Process *ex*
    $missing = $p | Get-Member -Type *property |
               Select-Object -Expand Name |
               Compare-Object -Reference $props |
               Where-Object { $_.SideIndicator -eq '<=' } |
               Select-Object -Expand InputObject
    
    if ($missing) {
      throw "missing property $missing."
    } else {
      $p | Select-Object $props
    }
    

    当然,您可以将其包装在自定义函数中:

    function Select-ObjectStrict {
      [CmdletBinding()]
      Param(
        [Parameter(
          Position=0,
          Mandatory=$true,
          ValueFromPipeline=$true,
          ValueFromPipelineByPropertyName=$true
        )]$InputObject,
    
        [Parameter(
          Position=1,
          Mandatory=$true
        )][string[]]$Property
      )
    
      Process {
        $missing = $InputObject | Get-Member -Type *property |
                   Select-Object -Expand Name |
                   Compare-Object -Reference $Property |
                   Where-Object { $_.SideIndicator -eq '<=' } |
                   Select-Object -Expand InputObject
    
        if ($missing) {
          throw "missing property $missing."
        } else {
          $InputObject | Select-Object $Property
        }
      }
    }
    

    所以可以这样使用:

    Get-Process *ex* | Select-ObjectStrict -Property 'Id', 'ProcessName', 'xxx'
    

    【讨论】:

      【解决方案3】:

      像这样...?

      $props = 'Id','ProcessName','xxx'
      $availableProps = Get-Process *ex*|Get-Member -MemberType Properties | Select -ExpandProperty Name
      $missingProps = $props | Where-Object {-not ($availableProps -contains $_)}
      if ($missingProps) {
        Write-Error "invalid property(s) $missingProps"
        throw { [System.Management.Automation.PropertyNotFoundException] }
      }
      
      Get-Process *ex* | Select-Object $props
      

      【讨论】:

        【解决方案4】:

        如果您希望在选择不存在的属性时收到错误消息
        使用:

        Set-StrictMode -Version Latest<br>
        $Global:ErrorActionPreference = 'Stop'<br>
        

        【讨论】:

        • 这与接受的以I can see the documentation be a little misleading when it says for Set-StrictMode: 开头的答案片段有何不同?
        猜你喜欢
        • 2019-09-25
        • 2018-09-29
        • 2023-01-19
        • 2017-09-20
        • 2012-12-07
        • 1970-01-01
        • 2015-10-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多