通过常用功能更新不同的阵列

问题描述 投票:2回答:1

我目前正在制作一个Powershell脚本,它将分析来自邮件服务器的多个日志文件,以收集将存储在许多不同阵列中的各种统计信息。

我有以下代码片段作为更新其中一个数组的示例。

#Update arrays
#Overall array
$objNewValue = New-Object -TypeName PSObject
$objNewValue = $PSOSSLOverall | Where-Object {($_.Version -contains $strVersion -and $_.Cipher -contains $strCipher -and $_.Bits -contains $strBits)}
If ($objNewValue -ne $null) {
  try {
    Write-Verbose "$strVersion $strCipher $strBits is already in the array, so we'll update TimeSeen value"
    $objNewValue.TimesSeen++
    $objNewValue.LastSeen = $dtTimestamp
  } #try
  catch {
    Write-Host "Something whent wrong while attempting to update an existing object in the overall array" -BackgroundColor DarkRed
    Write-Host "Current line: $strtemp[$i]"
    Write-Host "Current values: $dtTimestamp <-> $strVersion <-> $strCipher <-> $strBits"
    Write-Host "Current array:"
    $PSOSSLOverall | Sort-Object -Property Version, Cipher -Descending | Format-Table -AutoSize
    Write-Host "Exception object:"
    $_
  } #catch
} #If Check for existence in Overall array
Else {
  try {
    Write-Verbose "$strVersion $strCipher $strBits is not in the array, so it will be added "
    $objNewValue = New-Object -TypeName PSObject
    Add-Member -InputObject $objNewValue -MemberType 'NoteProperty' -Name 'Version' -Value $strVersion
    Add-Member -InputObject $objNewValue -MemberType 'NoteProperty' -Name 'Cipher' -Value $strCipher
    Add-Member -InputObject $objNewValue -MemberType 'NoteProperty' -Name 'Bits' -Value $strBits
    Add-Member -InputObject $objNewValue -MemberType 'NoteProperty' -Name 'TimesSeen' -Value 1
    Add-Member -InputObject $objNewValue -MemberType 'NoteProperty' -Name 'Percentage' -Value 0
    Add-Member -InputObject $objNewValue -MemberType 'NoteProperty' -Name 'FirstSeen' -Value $dtTimestamp
    Add-Member -InputObject $objNewValue -MemberType 'NoteProperty' -Name 'LastSeen' -Value $dtTimestamp
    $PSOSSLOverall += $objNewValue
  } #try
  catch {
    Write-Host "Something whent wrong while attempting to add a new object to the overall array"
    Write-Host "Current line: $strtemp[$i]"
    Write-Host "Current values: $dtTimestamp <-> $strVersion <-> $strCipher <-> $strBits"
    Write-Host "Exception object:"
    $_
  } #catch
} #Else Check for existence in Overall array

但是,当我需要更新多达10个或更多数组时,结果将是很多类似的代码,因为每次只更改相对较少的行 - 比如正在更新的数组,where子句,使用的变量和数组中的列数。

是否可以创建一个可以处理更新不同阵列的函数?

提前致谢。

-Update-

要解释上面的代码片段:在运行此部分脚本之前已经设置了所有变量。 $ strtemp [$ i]实际上是所有数据来自于日志文件中的当前行,然后我从中提取所需数据并将其放入各种变量中。

首先,我搜索有问题的数组,在本例中是$ PSOSSLOverall,以查看当前行中的数据是否已经在数组中。如果$ objNewValue不为null,那么数据已经存在,然后我递增一个计数器并更新该数据“行”的日期戳。如果$ objNewValue为null,则数据尚未存在,然后我们使用各种变量的数据向数组添加了一个now对象(行)。

每次尝试都配备了try / catch部分以进行错误处理。

最终结果将是一个看起来像这样的数组(百分比列在别处计算):

Content of array

其他数组有不同数量的列,我想我很难做出更新它们的常用功能。

arrays function powershell
1个回答
0
投票

我发现自己处于类似情况一两次。您必须重构代码,将不灵活的静态定义转换为参数变量。我们的想法是将数据与程序逻辑分开,这样您就可以执行诸如将不同的属性名称和值集合传递到同一函数中以适应不同情况的操作。

以下是我发现的几个可以提高灵活性的地方:

  1. 参数化用于查找匹配记录的Where-Object表达式,这样就不会为每个列和值组合编写相同的代码。见下面的hasPropertyValues。它所做的只是对传递给它的每个名称 - 值对执行-and连接的-contains操作。
  2. 参数化要为每个可能性更改的数据。当您的代码找到匹配的记录并且找不到匹配的记录时,它会执行某些操作。将这些操作从脚本主体中拉出并输入到输入参数中,该参数可以在您使用加密数据集时更改,并且必须移动到另一个上。 UpdateRecords函数采用哈希表参数,用于在添加新记录和找到匹配记录时定义数据的形状。

请参阅下面的示例。我认为你可以将这里的一些想法适应你的代码。

# this is a convenience function allowing us to test multiple name-value pairs against an object
function hasPropertyValues {
    Param(
        [object] $inputObject,
        [hashtable] $properties
    )
    $result = $true
    foreach($name in $properties.Keys){
        $result = $result -and ($inputObject.$name -contains $properties[$name])
    }
    Write-Output $result
}

# this function evaluates each object in $inputDataset
# if an object matches the name-values defined in $matchProperties
# it updates the records according to $updateRecordProperties
# if no records are found which match $matchProperties
# a new object is created with the properties in both $matchProperties
# and $newRecordProperties
# All results are written to the pipeline, including unmodified objects
function UpdateRecords{
    Param (
        [object[]] $inputDataset,
        [hashtable] $matchProperties,
        [hashtable] $updateRecordProperties, 
        [hashtable] $newRecordProperties
    )

    $numberOfMatchingRecords = 0
    foreach ($record in $inputDataset){
        if ( hasPropertyValues -inputObject $record -properties $matchProperties) {
            # a record with matching property values found. 
            # Update required attributes
            $numberOfMatchingRecords++
            foreach($name in $updateRecordProperties.Keys){
                if ($updateRecordProperties[$name] -is 'ScriptBlock'){
                    # if the update is a scriptblock, we invoke the scriptblock
                    # passing the record as input. The result of the invocation
                    # will be set as the new attribute value
                    $newValue = & $updateRecordProperties[$name] $record
                } else {
                    $newValue = $updateRecordProperties[$name]
                }
                $record | Add-Member -Force -MemberType NoteProperty -Name $name -Value $newValue
            }
        }
        Write-Output $record
    }
    if ($numberOfMatchingRecords -eq 0) {
        # no records found with the search parameters
        $newRecord = New-Object -TypeName psobject -Property $newRecordProperties
        foreach($key in $matchProperties.Keys){
            $newRecord | Add-Member -MemberType NoteProperty -Name $key -Value $matchProperties[$key] -Force
        }
        Write-Output $newRecord
    }
}

[object[]] $TestDataset= @(New-Object psobject -Property @{
        version='TLSv1.2'
        cipher='ECDHE-RSA-AES256-GCM-SHA384'
        Bits=256
        TimesSeen = 1833
        Percentage = 87578
        FirstSeen = [DateTime]::Now
        LastSeen = [DateTime]::Now
    })

function TestUpdateRecords{

    $encryptionNewRecordDefaults = @{
        TimesSeen = 1
        Percentage = 0
        FirstSeen = [DateTime]::Now
        LastSeen = [DateTime]::Now
    }

    $encryptionUpdateAttributes = @{
            LastSeen = [DateTime]::Now
            TimesSeen = {$ARGS[0].TimesSeen + 1}
    }

    # test adding a new record
    UpdateRecords -inputDataset $TestDataset `
        -matchProperties @{ Version='TLSv1.0';cipher='unbreakable';bits=720} `
        -updateRecordProperties $encryptionUpdateAttributes `
        -newRecordProperties  $encryptionNewRecordDefaults

    # test modifying a matching record
    UpdateRecords -inputDataset $things `
        -matchProperties @{Version='TLSv1.2';cipher='ECDHE-RSA-AES256-GCM-SHA384';bits=256} `
        -updateRecordProperties $encryptionUpdateAttributes `
        -newRecordProperties $encryptionNewRecordDefaults
}

TestUpdateRecords

实现这种重构有很多不同的方法。例如,您可以将特定于数据集的逻辑提取到脚本块中,并将它们传递给主循环函数。

另一种可能性是深入研究PowerShell的面向对象特性,并尝试围绕每个数据集构建类。这可以以愉快的方式封装“更新”和“新”操作。我还没有足够的知识来使用PowerShell OO功能来尝试。

© www.soinside.com 2019 - 2024. All rights reserved.