1

I'm started a query for our infrastructure to see how SNMP Service is configured on the servers. I managed to find a function that would extract just the relevant keys and values (without the PS* properties) from the 3 Registry paths :

  • HKLM:\SYSTEM\CurrentControlSet\services\SNMP\Parameters\RFC1156Agent
  • HKLM:\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ValidCommunities
  • HKLM:\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\PermittedManagers

Edit 1: I've copied the wrong Function initially. Also added the missing part where the function is called. I hope this clears out the confusion

Function Get-HashedProperty {
  [CmdletBinding()]
  Param(    
    [Parameter(Mandatory=$True)]
    [ValidateScript({Test-Path $_})]
    [String]$RegPath,
    [Parameter(Mandatory=$False)]
    [ValidateSet("Json","HashTable")]
    [String]$As
  )
  $Hash = @{}
  Get-ItemProperty "$RegPath" | 
    Get-Member -MemberType NoteProperty |
      Where-Object {$_.Name -notlike "PS*"} | Foreach {
        $_ | Select-Object -ExpandProperty Name | Foreach {
          $Value = Get-ItemProperty "$RegPath" -Name "$_"
          $Hash.Add("$_","$($Value."$_")")
        }
      }
   If($As -eq "Json"){
     $Hash = $Hash | ConvertTo-Json
   }
   Return $Hash
}

$mypaths = @("HKLM:\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ValidCommunities","HKLM:\SYSTEM\CurrentControlSet\services\SNMP\Parameters\RFC1156Agent","HKLM:\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\PermittedManagers")

$all = $mypaths | foreach { Get-HashedProperty $_ }

The output of $all variable is below.

Name Value
BO@CA_w3Ad 8
BO@CA_r3Ad 4
sysLocation
sysContact
sysServices 76
one hp-sim-ap
three hp-sim-ap
1 localhost
two hp-sim-ap

What i'm struggling is to get this values in a separate hashtable or PSObject where i have to add also the ServerName and the InstallState of the SNMP Service. Whatever i do i still get the registry values as array.

Server SNMP-Service Col1 Col2
MyTestServer Installed {BO@CA_w3Ad, BO@CA_r3Ad, sysLocation, sysContact...} {8, 4, , ...}

I tried in few different ways, but i assume my lack of knowledge makes it hard to understand where i'm doing wrong.

For example

$a = @()
$item = New-Object PSObject -Property @{
    Server = $ENV:ComputerName
    'SNMP-Service' = (Get-WindowsFeature -Name SNMP-Service | Select InstallState).InstallState
    Col1 = @($All.Keys)
    Col2 = @($all.Values)
        }

$a += $item
$a
}

Expected output should be

Server SNMP-Service Name Value
MyTestServer Installed BO@CA_w3Ad 8
MyTestServer Installed BO@CA_r3Ad 4
MyTestServer Installed sysLocation
MyTestServer Installed sysContact
MyTestServer Installed sysServices 76
MyTestServer Installed one hp-sim-ap
MyTestServer Installed three hp-sim-ap
MyTestServer Installed 1 localhost
MyTestServer Installed two hp-sim-ap

Would highly appreciate a bit of help here :(

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 4
    It's not quite clear to me what you want to achieve. Please add an example of what the output should look like. Also, your 2nd code sample seems to be unrelated to the first one. It would be more helpful if you show how you use function `Get-KeyProperty`. – zett42 Aug 24 '22 at 19:58
  • Are you wanting the same PSCustomObject with more members? If so, take a look at [Add-Member](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/add-member). – Darin Aug 24 '22 at 20:13
  • Is `$a` supposed to be an array or a hashtable? You is uisng `$a = @()`, declaring an array. If you want a hashtable, use `$a = @{}`. – Keith Miller Aug 24 '22 at 20:36
  • The initial function added in the post was wrong. I've adjusted that one, sorry for confusion @zett42. Darin, i tried to use the add-member but it does the same thing. it adds the array in one "cell" instead of each value on a new row. Seems to have something to do with the way the output is collected from the function. – Milotin Alexandru Aug 26 '22 at 05:34

1 Answers1

0

I suggest refactoring your approach:

  • Use the intrinsic psobject property to reflect on the properties of the Get-ItemProperty output objects, which allows you to eliminate the PS-prefixed properties.

  • Then, for each remaining property, construct a [pscustomobject] instance with Name and Value properties, which you can supplement with the desired Server and SNMP-Service properties.

$mypaths | 
  Get-ItemProperty | 
  ForEach-Object {
    foreach ($prop in $_.psobject.Properties.Where({ $_.Name -notlike 'PS*'})) {
      # Construct and output an object with the desired properties.
      [pscustomobject] @{
        Server = $ENV:ComputerName
        # Note: Better to move this call out of the loop and use a cached value.
        'SNMP-Service' = (Get-WindowsOptionalFeature -Name SNMP-Service).InstallState
        Name = $prop.Name
        Value = $prop.Value
      }
    }
  }

This outputs a stream of objects with the desired structure and values, which you can capture in an array by simple assignment ($a = ...).

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I have to say this looks far more easy than my solution, there is one issue though. Seems like if i have a REG_MULTI_SZ on export is not casted as a string and i get the result as : "MyTestServer","Installed","Test","System.String[]" – Milotin Alexandru Aug 26 '22 at 11:46
  • Best way i found was to use the -join " ", but its is not very helpful when 1 line of my multi string also has a space in between. But i guess i can live with that :) – Milotin Alexandru Aug 26 '22 at 12:03
  • @MilotinAlexandru, I wasn't sure if you wanted the explicit stringification of all data, but `Value = [string] $prop.Value` would give you that. But there, too, the `REG_MULTI_SZ` data that PowerShell returns as an _array_ would end up as a space-separated concatenation of its elements, the same as `-join ' '`. You could choose a different separator, however, one that you know not to be part of the array elements themselves. For instance, if all elements are _single-line_ strings, you could use ``-join "`n"`` – mklement0 Aug 26 '22 at 12:56