在Powershell中测试大量注册表值

在Powershell中测试大量注册表值,powershell,multidimensional-array,Powershell,Multidimensional Array,在Powershell中,使用Get Item和Get ItemProperty测试单个注册表值是否存在并检查它们是否有正确的数据并不太复杂。我希望能够做的是检查大量注册表值的存在以及数据 例如,给定以下注册表项: HKLM:\SOFTWARE\Breakfast\1001 = 3 [DWORD] HKLM:\SOFTWARE\Breakfast\1003 = 3 [DWORD] HKLM:\SOFTWARE\Breakfast\1004 = 3 [DWORD] HKLM:\SOFTWARE\B

在Powershell中,使用
Get Item
Get ItemProperty
测试单个注册表值是否存在并检查它们是否有正确的数据并不太复杂。我希望能够做的是检查大量注册表值的存在以及数据

例如,给定以下注册表项:

HKLM:\SOFTWARE\Breakfast\1001 = 3 [DWORD]
HKLM:\SOFTWARE\Breakfast\1003 = 3 [DWORD]
HKLM:\SOFTWARE\Breakfast\1004 = 3 [DWORD]
HKLM:\SOFTWARE\Breakfast\1005 = 1 [DWORD]
一个对每个值和数据分别执行测试的大而丑陋的脚本并不复杂,但我想看看是否有可能将一个友好的名称、注册表路径/值和所需的数据放入一个数组中,这样我们就可以拥有一个执行测试的函数

阵列的外观可能如下所示:

$registry_list = @()
$registry_list.gettype()
$registry_list += ,@('Poptarts','HKLM:\SOFTWARE\Breakfast\','1001','3')  
$registry_list += ,@('Toast','HKLM:\SOFTWARE\Breakfast\','1002','3') 
$registry_list += ,@('Muffins','HKLM:\SOFTWARE\Breakfast\','1003','3') 
$registry_list += ,@('Bagels','HKLM:\SOFTWARE\Breakfast\','1004','3')
$registry_list += ,@('Biscuits','HKLM:\SOFTWARE\Breakfast\','1005','3')
因为我是数组新手,所以我不知道如何将这些数组输入到一个只显示错误的函数中

Toast
  Value Missing (HKLM:\SOFTWARE\Breakfast\1002)
Biscuits
  Value Set Incorrectly (HKLM:\SOFTWARE\Breakfast\1005) Desired: 3. Actual: 1

如果有人能够参与进来,帮助找出一个函数或类似函数如何遍历每个注册表值,我们将不胜感激。这里的示例很短,但我确实希望能够通过此测试运行数百个注册表值。

我从来都不是PowerShell中多维数组的超级粉丝。他们最终感觉非常脆弱或不稳定。PowerShell中的数组也很糟糕,因为当您使用
+=
操作符时,系统必须使用新元素构建一个新数组,然后扔掉旧数组。这在计算上很昂贵

对于本例,我将创建一个ArrayList,并将数组添加到其中。我也可能会为每个项目使用哈希表,以便使用名称而不是索引号来引用项目:

$registry_list = New-Object System.Collections.ArrayList;

# Use the Add() function to add records.  The [void] type is here because the function 
# normally returns the number of records in the ArrayList, and we don't want that to go to output.
[void]$registry_list.Add(@{Value='Poptarts';Path='HKLM:\SOFTWARE\Breakfast';Key='1001';Data='3'});
[void]$registry_list.Add(@{Value='Toast';Path='HKLM:\SOFTWARE\Breakfast';Key='1002';Data='3'});

$registry_list | ForEach-Object {
    $RegistryPath = Join-Path -Path $_.Path -ChildPath $_.Key;
    if (Test-Path -Path $RegistryPath) {
        Write-Host "Path '$RegistryPath' exists."
        $RegistryData = (Get-ItemProperty -Path $RegistryPath).($_.Value)
        if ($RegistryData -eq $_.Data) {
            Write-Host "Check OK.  Value $($_.Value) data is set to '$RegistryData'.  Desired data is '$($_.Data)'."
        }
        else {
            Write-Host "Check Failed.  Value $($_.Value) data is set to '$RegistryData'.  Desired data is '$($_.Data)'."
        }
    }
    else {
        Write-Host "Path '$RegistryPath' does not exist."
    }
}

请注意,我没有严格测试这段代码。值得注意的是,我对($RegistryData-eq$\uData)在所有情况下的正确性有点怀疑。

我强烈建议使用大型数组来使用对象数组。通过创建对象,可以很容易地使用属性引用阵列的不同部分

然后,您还可以使用具有适当值的模板服务器来构建对象/对象数组,然后用于验证其他系统

下面是构建对象的基本示例。更有效的方法是创建一个简单的函数来为您构建这些对象,这样您就不会有太多的代码重复,但这是基本的方法。如果你想要一种更高级的创建对象的方法,请告诉我,我将发布一个示例

$registrySet = @()

$registryObj = New-Object -TypeName psobject
$registryObj | Add-Member -MemberType NoteProperty -Name Name -Value 'Toast'
$registryObj | Add-Member -MemberType NoteProperty -Name Key -Value 'HKLM:\SOFTWARE\Breakfast\'

$subKeySet = @()
$subKeyObj = New-Object -TypeName psobject
$subKeyObj | Add-Member -MemberType NoteProperty -Name Name -Value '1001'
$subKeyObj | Add-Member -MemberType NoteProperty -Name Type -Value 'DWORD'
$subKeyObj | Add-Member -MemberType NoteProperty -Name Value -Value '3'
$subKeySet += $subKeyObj

$subKeyObj = New-Object -TypeName psobject
$subKeyObj | Add-Member -MemberType NoteProperty -Name Name -Value '1002'
$subKeyObj | Add-Member -MemberType NoteProperty -Name Type -Value 'DWORD'
$subKeyObj | Add-Member -MemberType NoteProperty -Name Value -Value '3'
$subKeySet += $subKeyObj

$subKeyObj = New-Object -TypeName psobject
$subKeyObj | Add-Member -MemberType NoteProperty -Name Name -Value '1003'
$subKeyObj | Add-Member -MemberType NoteProperty -Name Type -Value 'DWORD'
$subKeyObj | Add-Member -MemberType NoteProperty -Name Value -Value '1'
$subKeySet += $subKeyObj

$registryObj | Add-Member -MemberType NoteProperty -Name SubKeySet -Value 
$subKeySet

$registrySet += $registryObj

$registrySet | Where {$_.Name -ieq 'toast'} | select SubKeySet

我会将数据存储在CSV文件中:

friendlyName,key,value,data
Poptarts,HKLM:\SOFTWARE\Breakfast\,1001,3
Toast,HKLM:\SOFTWARE\Breakfast\,1002,3
Muffins,HKLM:\SOFTWARE\Breakfast\,1003,3
Bagels,HKLM:\SOFTWARE\Breakfast\,1004,3
Biscuits,HKLM:\SOFTWARE\Breakfast\,1005,3
然后循环文件中的每一行

foreach($row in Import-Csv .\breakfast.csv)
{
    # retrieve key
    $key = Get-Item $row.key

    # retrieve value
    $value = $key |Get-ItemProperty -Name $row.value

    # compare data
    $valid = $value."$($row.value)" -eq $row.data

    # output result
    $outParams = @{
        Object = if($valid){"$($row.friendlyName) is correct"} else {"$($row.friendlyName) is incorrect"}
        ForegroundColor = @('Red','Green')[+$valid]
    }
    Write-Host @outParams
}

我将把错误处理和更好输出的实现留给OP:-)练习。

每个数组中第一个字符串的意义是什么?(PopStarts,Toast等)@MathiasR.Jessen这似乎是他们在指定数组内容时引用的友好名称:友好名称、注册表路径/值和所需数据非常接近,谢谢。我发现的唯一问题是:1)“testpath”语句仅对键测试有效,而不是对值的完整测试。换句话说,它返回的有效值适用于
HKLM:\SOFTWARE\breaken
,但不适用于
HKLM:\SOFTWARE\breaken\1001
。我对代码做了一些编辑,但我不能将它们准确地发布回注释中,因为我没有空间或格式-这是一个遗憾。在示例中,“1001”是一个值,而不是一个键,这就是问题所在。我必须更改
$RegistryPath=Join Path-Path$\路径.Path-ChildPath$\路径.Key行到
$RegistryPath=Join Path-Path$\路径-ChildPath'\否则每个测试都会失败。@Beems是的,您的数据解释得不是很好,所以我不得不猜测它描述了什么。很高兴你能弄明白。谢谢你深思熟虑的想法马蒂亚斯。我知道我在最初的评论中没有提到它,但唯一的缺点是我必须为每个客户端部署两个文件来完成验证。我目前很幸运地使用了@Bacon Bits提出的解决方案,但我也将其添加到了书签中,因为在其他情况下,这将非常方便。