0

I've been working on this a while and have realised the issue is mainly down to how to manipulate data.

I have a command, which retrieves data from remote registries for a list of servers

$RegData = Get-RegValue -ComputerName $($Target.ComputerName) -Hive $RegHive -Key $KeyName -ping -ErrorAction Stop -WarningAction Stop

Problem here is obvious to me now that I've taken a look at the data - the number of keys/values returned from the registry query is variable.

ComputerName Hive            Key                  Value                     Data
------------ ----            ---                  -----                     ----
SERVER1      LocalMachine    SOFTWARE\NSS\Serv... AssetNumber               987412
SERVER1      LocalMachine    SOFTWARE\NSS\Serv... BuildDate                 02/02/2017
SERVER1      LocalMachine    SOFTWARE\NSS\Serv... iLODefaultPwd             NA    
ComputerName Hive            Key                  Value                     Data
------------ ----            ---                  -----                     ----
SERVER2      LocalMachine    SOFTWARE\Serv...     AssetNumber               984213
SERVER2      LocalMachine    SOFTWARE\Serv...     BuildDate                 02/02/2017
SERVER2      LocalMachine    SOFTWARE\Serv...     iLODefaultPwd             NA  
SERVER2      LocalMachine    SOFTWARE\Serv...     ContactTel                8237  

The registry key name is constant but there can be many Data and Value pairs within:

This means that feeding it into an array/arraylist like this won't work:

Function GetRegistryData {
ForEach ($Target in $ImportData) {
        $RegData = Get-RegValue -ComputerName $($Target.ComputerName) -Hive $RegHive -Key $KeyName -ping -ErrorAction Stop -WarningAction Stop
        $NewObject = New-Object PSObject
        $NewObject | Add-Member -NotePropertyName 'ComputerName' -NotePropertyValue $Target.ComputerName
        $NewObject | Add-Member -NotePropertyName 'Key' -NotePropertyValue $KeyName
        $RegData | ForEach {
            $NewObject | Add-Member -NotePropertyName $_.Value -NotePropertyValue $_.Data
        }
        $NewObject | Add-Member -NotePropertyName 'Hive' -NotePropertyValue $RegHive
        $NewObject | Add-Member -NotePropertyName 'Type' -NotePropertyValue $RegData[0].Type
        $NewObject
}
}

The array will be defined by the first set of values I send (or if there's an error in collecting data it'll default to the 4 specific properties I've set) and I'll lose additional values on subsequent entries with more values. In this example it won't append "SERVER2" values because there is a new field and if there's an error in retrieving it'll set ComputerName, Key, Hive, Type as object fields and ignore any others

Any pointers as to how I can collate this data easily into an object - I'm trying to get a per server entry with Value, Data fields as below:

ComputerName Hive            Key                  AssetNumber               BuildDate
------------ ----            ---                  -----                     ----
SERVER1      LocalMachine    SOFTWARE\Serv...     987412                    02/02/2017
SERVER2      LocalMachine    SOFTWARE\Serv...     984123                    02/02/2017

The fact that I don't know all the noteproperty names beforehand is giving me a block on this right now. I could scan ALL the server registries beforehand and get all the unique names but it seems a pretty wasteful solution.

1
  • Do you want to list data about computers you could not contact? Commented May 25, 2018 at 18:41

1 Answer 1

2

I could scan ALL the server registries beforehand and get all the unique names but it seems a pretty wasteful solution.

Yep, That would be odd since you are already querying this data once. However what you should do is delay making your objects until you have all the answers. Collect of the the registry values and data you can. Use those to get you unique list and then create your object properties for each computer your queried.

# Registry specific variables
$hive = 'LocalMachine'
$key = 'software\somekey'

# List of target computers
$computers = "comp1","comp2","comp7635","bagel"

# Cycle each of those 
$gatheredData = $computers | ForEach-Object{
    # Attempt to get registry values. Store what we find in one property
    [pscustomobject]@{
        ComputerName = $_
        RegistryValues = Get-RegValue -Hive $hive  -Key $key -Ping -ComputerName $_ -WarningAction SilentlyContinue
    }
}

# Determine the distinct value data pairs we have based on queried data
$uniqueValues = $gatheredData.registryvalues.Value | Select-Object -Unique

# Extend the current objects to add off the columns and populate with data where found
foreach($result in $gatheredData){
    foreach($value in $uniqueValues){
        # If exists, get the data of the value in the collected registry values
        $ValueData = ($result.RegistryValues | Where-Object{$_.value -eq $value}).Data
        Add-Member -InputObject $result -MemberType NoteProperty -Name $value  -Value $ValueData
    }
}

# Display the new object minus the collected values property
$gatheredData | Select-Object * -ExcludeProperty RegistryValues
Sign up to request clarification or add additional context in comments.

2 Comments

Great thanks, needed a little tweaking for the output of Get-RegData but this is the logical step that was evading my brain on Friday! Just have to wrap the error handling into it now which shouldn't be too hard.
One little change if anyone is doing the same thing - I used Sort-Object here: # Determine the distinct value data pairs we have based on queried data $uniqueValues = $gatheredData.registryvalues.Value | Sort-Object -Unique Select-Object is case senstiive and was producing issues where registry keys used a mixtre of cases for the same name

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.