arrays - 通过通用函数更新不同的数组

标签 arrays function powershell

我目前正在制作一个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子句,使用的变量和数组中的列数。

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

提前致谢。

-更新-

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

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

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

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

Content of array

其他数组具有不同数量的列,我想这很难使它们具有通用功能来更新它们。

最佳答案

我发现自己处于一两次类似的情况。您必须重构代码,将不灵活的静态定义转换为参数变量。想法是将数据与程序逻辑分开,以便您可以执行一些操作,例如针对不同的情况将一组不同的属性名称和值传递给同一函数。

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

  • 参数化用于查找匹配记录的Where-Object表达式,因此您不必为列和值的每种组合编写相同的代码。请参阅下面的hasPropertyValues。它所做的只是对传递给它的每个名称/值对执行-and串联-contains操作。
  • 为每种情况参数化要更改的数据。您的代码在找到匹配的记录或找不到匹配的记录时会执行某些操作。将这些操作从脚本主体中拉出,并输入一个输入参数,当您完成加密数据集的处理后,该参数可以更改,并且必须移至另一个。 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的面向对象功能,并尝试围绕每个数据集构建类。这样可以以一种愉快的方式封装“更新”和"new" Action 。我还没有足够的Powershell OO功能知识来尝试。

    关于arrays - 通过通用函数更新不同的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51800997/

    相关文章:

    无法找出段错误

    c - 具有多个数组的结构,其大小在执行时定义

    javascript - 创建一个类似 jQuery(document).ready 的函数

    javascript - 函数、对象和匿名函数

    powershell - 如何使用 PowerShell 导入文件,并将所有现有的占位符变量替换为脚本中定义的变量?

    java - 使用简单的json,将包含json数组的json对象转换为字符串数组(在java中)

    c - 将返回的 cstring 分配给变量

    r - 在rstudio中查找函数值

    powershell - 重新启动PC并使用自定义消息写入事件日志

    Powershell跨模块访问调用者范围变量