powershell 基于列表替换PSObj属性值

vwkv1x7d  于 2022-12-18  发布在  Shell
关注(0)|答案(2)|浏览(137)

我有以下PSObj,其中一些属性存储在$数组中:

ComputerName      : MyComputer
Time              : 08/11/2022 13:57:53
DetectionFile     : MyBadFile.exe
ThreatName        : WS.Reputation.1
Action            : 12

我尝试用相应的描述替换操作ID号。我有一个哈希表,其中包含操作ID背后的可能原因

$ActionId = @{
    0  = 'Unknown'
    1  = 'Blocked'
    2  = 'Allowed'
    3  = 'No Action'
    4  = 'Logged'
    5  = 'Command Script Run'
    6  = 'Corrected'
    7  = 'Partially Corrected'
    8  = 'Uncorrected'
    10 = 'Delayed   Requires reboot to finish the operation.'
    11 = 'Deleted'
    12 = 'Quarantined'
    13 = 'Restored'
    14 = 'Detected'
    15 = 'Exonerated    No longer suspicious (re-scored).'
    16 = 'Tagged    Marked with extended attributes.'
}

我尝试解析这个数组的每一项,以及reason ID的每一个值,以便用reason字符串替换ID

# parse array
    foreach ($Item in $array) {
        # parse possible values
        foreach ($value in $ActionId) {
            if ($value -eq $item.Action) {
                $Item.Action = $ActionId[$value]
                $Item.Action
            }
        }


据我所知,这里缺少正确的语法

$Item.Action = $ActionId[$value]

我没有得到任何错误,但是在调试器中,我用上面的代码替换了$null的action属性...

mi7gmzs6

mi7gmzs61#

立即解决的方法是循环$ActionIdhashtable的 * 键*(.Keys):

foreach ($Item in $array) {
  # parse possible values
  foreach ($value in $ActionId.Keys) {
      if ($value -eq $item.Action) {
          $Item.Action = $ActionId[$value]
          $Item.Action  # diagnostic output
      }
  }
}

注:

  • 为避免混淆,请考虑将$value重命名为$key
  • 一般来说,注意哈希表 * 没有 * 在PowerShell的管道/循环结构中枚举。
  • 也就是说,foreach ($value in $ActionId) ...实际上并不循环哈希表的条目,它与$value = $ActionID相同)
  • 如果你想枚举一个哈希表的 * 条目 * --作为类型System.RuntimeType的键-值对--你需要使用.GetEnumerator()方法;但是,在您的情况下,枚举 keys 就足够了。

然而,更简单和更有效的解决方案是测试$Item.Action值是否作为一个键存在于哈希表中,使用后者的.Contains()方法:[1]

foreach ($Item in $array) {
  if ($ActionId.Contains($Item.Action)) {
    $Item.Action = $ActionId[$Item.Action]
    $Item.Action  # diagnostic output
  }
}

您可以进一步简化这一过程,如下所示,尽管它在概念上有点模糊:

foreach ($Item in $array) {
  if ($null -ne ($value = $ActionId[$Item.Action])) {
    $Item.Action = $value
    $Item.Action  # diagnostic output
  }
}

  • =是PowerShell唯一的 * 赋值 * 运算符;对于相等/不相等 * 比较 *,需要-eq/-ne
  • 这里,对$value的赋值实际上正在执行,并且 * 赋值 * 然后充当-ne操作的RHS;换句话说:您可以在PowerShell中将赋值 * 用作表达式 *。
  • 如果哈希表$ActionId * 没有 * 值为$Item.Action的键,则$ActionId[$Item.Action]会安静地返回$null

最后(仅在PowerShell (Core) 7+中),可以使用空合并操作符**??实现甚至更简洁**(尽管不一定更快)的解决方案:

foreach ($Item in $array) {
  $Item.Action = $ActionId[$Item.Action] ?? $Item.Action
  $Item.Action # diagnostic output
}

也就是说,$ActionId[$Item.Action]的值仅在 * 它不是$null * 时才被使用;否则,使用$Item.Action,即当前值(这实际上是空操作)。
[1].ContainsKey()也可以使用,虽然这个名称在概念上比.Contains()更清晰,但不幸的是,PowerShell的[ordered]哈希表(System.Collections.Specialized.OrderedDictionary)不支持它,一般来说,其他字典(类似哈希表的类型)也不支持它,因为System.Collections.IDictionary接口只有.Contains()

zaq34kh6

zaq34kh62#

此外,**mklement0**的回答很有帮助,我只是在思考一些问题(也就是问题):
这是一种典型的情况,我会考虑使用enum,除了键不(容易)接受空格(如您的问题)。

Enum ActionTypes {
    Unknown
    Blocked
    Allowed
    NoAction
    Logged
    CommandScriptRun
    Corrected
    PartiallyCorrected
    Uncorrected
    Delayed
    Deleted
    Quarantined
    Restored
    Detected
    Exonerated
    Tagged
}

$PSObj = [PSCustomObject]@{
    ComputerName      = 'MyComputer'
    Time              = [DateTime]'08/11/2022 13:57:53'
    DetectionFile     = 'MyBadFile.exe'
    ThreatName        = 'WS.Reputation.1'
    Action            = 12
}
$PSObj.Action = [ActionTypes]$PSObj.Action
$PSObj

ComputerName  : MyComputer
Time          : 8/11/2022 1:57:53 PM
DetectionFile : MyBadFile.exe
ThreatName    : WS.Reputation.1
Action        : Restored

这样做的好处是不会丢失实际的action id,这意味着如果你把对象插回数据库,它会自动转换成原来的整型:

$PSObj.Action
Restored
[int]$PSObj.Action
12

相关问题