如何使用PowerShell跟踪注册表中的更改?

时间:2018-02-26 06:09:55

标签: ruby powershell scripting registry

我有一个ruby脚本,基本上检查注册表中的几个键是我们的应用程序的标志。该脚本将检查标志是否为'开'(DWORD值1)超过14天,它将关闭它(0)并发送电子邮件。

要跟踪此情况,脚本在第一次运行期间执行的操作是,它会创建一个本地数据库并存储注册表中打开的每个标志的标志名称,日期时间等。在下次运行期间,它会检查此数据库以查找标志是否已打开超过14天。

我想知道是否有更好的方法来使用PowerShell来处理这个问题,还是应该创建一个本地数据库并遵循相同的流程?

更多信息:

所以我将在'\ HKEY_LOCAL_MACHINE \ SOFTWARE \ Company \ Clients'下有不同的帐户,每个客户端都有一个调试文件夹,其中包含如下所示的标志

HKEY_LOCAL_MACHINE\SOFTWARE\Company\Clients
                                        \Client1\Debug
                                                    IsEmail
                                                    IsShip
                                        \Client2\Debug
                                                    IsEmail
                                                    IsPack

所以我需要有效地遍历每个客户端,可能会创建一个XML / JSON或DB,其中包含客户端名称,标记定义和当前日期时间。然后在以后的运行中,我应该访问此信息,比较注册表项并关闭已经转换超过指定日期的标志。我将尽早使用保存的时间戳。

更新1:

根据我对powershell脚本工作原理的最新理解,很少有更新。我将有一个主数组或排序与我需要的标志列表。例如$ MasterFlagList = ['IsEmail','IsShip','IsNew']。现在,在我第一次运行应用程序时,我想在这个答案或xml文件中创建一个类似@tukan的json字符串,如下所示:

<xml>
<Client1>
    <IsEmail>
        <value>1</value>
        <time>*current time*</time>
    </IsEmail>
    <IsShip>
        <value>1</value>
        <time>*current time*</time>
    </IsShip>
    <IsPack>
        <value>0</value>
        <time>*current time*</time>
    </IsPack>
</Client1>
<Client2>
    <IsEmail>
        <value>0</value>
        <time>*current time*</time>
    </IsEmail>
    <IsShip>
        <value>0</value>
        <time>*current time*</time>
    </IsShip>
    <IsPack>
        <value>0</value>
        <time>*current time*</time>
    </IsPack>
</Client2>
</xml>

所以基本上这里发生的是XML字符串将包含来自masterlist的所有标志,但是如果注册表中有那些条目,那么该值将被加载(0或1),而对于那些在注册表中未提及的值,默认值为0。

下次我运行时,我会将这个XML从目录加载到一个对象中,对于每个客户端,我需要检查XML是否已经有一条记录,如果有,请检查日期时间并查看该标志是否已打开一段时间,如果是这样,请关闭旗帜。

欢迎实施这一想法的更好解决方案。我是powershell的新手,为什么我想到了这种方法。

1 个答案:

答案 0 :(得分:1)

这真是一个讨厌的黑客。为什么不将日期也存储在具有客户端记录的注册表中?

我认为Powershell在查询注册表方面比ruby做得更好。

从注册表路径获取值:

Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\company\Clients\Client1\Debug

这会产生结果:

IsEmail      : 0
IsShip       : 0
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\company\Clients\Client1\Debug
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\company\Clients\Client1
PSChildName  : Debug
PSProvider   : Microsoft.PowerShell.Core\Registry

替代方法是这样做:

Get-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\company\Clients\Client1\Debug

给出了:

    Hive: HKEY_LOCAL_MACHINE\SOFTWARE\company\Clients\Client1


Name                           Property
----                           --------
Debug                          IsEmail : 0
                               IsShip  : 0

如果你想直接得到这个值,你必须这样做:

(Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\company\Clients\Client1\Debug -Name IsEmail).IsEmail

设置一个值(不要忘记你可能需要管理员权限!):

Set-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\company\Clients\Client1\Debug -Name 'IsEmail' -Type Dword -Value '1'

现在问题的核心(可能还有问题)

我不得不测试它,因为我脑子里有不同的解决方案,所以花了很长时间。

# %Y ... year
# %m ... month
# %d ... day
# %R ... 24 hour time and minutes
# %S ... seconds
# example output: 20180226_10:38:23
$time_stamp= Get-Date -UFormat "%Y%m%d_%R:%S"
Write-Output $time_stamp

Get-ChildItem 'HKLM:\SOFTWARE\company\Clients' -Recurse | ForEach-Object {
    $regkey = (Get-ItemProperty $_.pspath)

    $regkey.PSObject.Properties | ForEach-Object {
      # you could filter it via -> If($_.Name -like 'Is*'){
        # $regkey is a HashTable
        # Printing some output so you can check
        Write-Output $regkey.PSParentPath
        Write-Output $regkey.PSPath
        Write-Output $_.Name ' = ' $_.Value
        Write-Output ''
        # convert to JSON - will contain more information than you need -> format it as you wish
        $convert_registry_to_json = $regkey | ConvertTo-Json
      #}
    }
}

# Printing JSON output
Write-Output $convert_registry_to_json

我自行决定进一步过滤或格式化。

修改 - 已编辑的问题 这让我想起了为什么我讨厌XML :)。我为您的格式创建了一个简单的解决方案。这段代码只是一个概念验证,我建议使用函数来缩短代码(也避免重复)

$time_stamp= Get-Date -UFormat "%Y%m%d_%R:%S"

$result_hash = @{}
$result_array= @()
$first_level_hash = @{}
$second_level_hash = @{}

Get-ChildItem 'HKLM:\SOFTWARE\company\Clients' -Recurse | ForEach-Object {
    $regkey = (Get-ItemProperty $_.pspath)

    $regkey.PSObject.Properties | ForEach-Object {
        # a HashTable
        #Write-host $regkey.PSParentPath
        $parent_key = $regkey.PSParentPath -Match '\w+$'
        #Write-host "Found Parent:" $matches[0]
        $parent_value = $matches[0]
        #Write-Host $regkey.PSPath

        #Write-Host $_.Name ' = ' $_.Value
        #Write-host ''
        $hash_key = $_.Name
        $hash_value = $_.Value

        If ($hash_key -like 'IsEmail'){
            $second_level_hash.Add('value',$hash_value)
            $second_level_hash.Add('time',$time_stamp)
            $first_level_hash.Add($hash_key,$second_level_hash)
            $result_hash.Add($parent_value,$first_level_hash)
            $result_array += ($result_hash)

            $second_level_hash=@{}
            $first_level_hash=@{}
            $result_hash=@{}
        } ElseIf ($hash_key -like 'IsShip'){
            $second_level_hash.Add('value',$hash_value)
            $second_level_hash.Add('time',$time_stamp)
            $first_level_hash.Add($hash_key,$second_level_hash)
            $result_hash.Add($parent_value,$first_level_hash)
            $result_array += ($result_hash)

            $second_level_hash=@{}
            $first_level_hash=@{}
            $result_hash=@{}

        } ElseIf ($hash_key -like 'IsPack'){
            $second_level_hash.Add('value',$hash_value)
            $second_level_hash.Add('time',$time_stamp)
            $first_level_hash.Add($hash_key,$second_level_hash)
            $result_hash.Add($parent_value,$first_level_hash)
            $result_array += ($result_hash)

            $second_level_hash=@{}
            $first_level_hash=@{}
            $result_hash=@{}

        }
        #$convert_registry_to_json = $regkey | ConvertTo-Json
      #}
    }
}
#Write-Output $result_hash
#Write-Output $result_hash.Item('IsEmail').Keys
#Write-Output $result_hash.Item('Client1').item('IsEmail')

Write-Output $result_array

ForEach ($result in $result_array) {
    ForEach ($entry in $result.GetEnumerator()) {
        $first_level_name = $($entry.Value)
        ForEach ($second_level in $first_level_name.GetEnumerator()) {
            $second_level_name = $($second_level.Value)
            ForEach ($third_level in $second_level_name.GetEnumerator()) {
                Write-Host "$($entry.Name) -> $($second_level.Name) -> $($third_level.Name): $($third_level.Value)"
            }
        }
    }
}

# You can convert it to JSON
# FSpecifies how many levels of contained objects are included in the JSON representation. The default value is 2.
$convert_result_to_json = $result_array | ConvertTo-Json -Depth 3

Write-Output $convert_result_to_json

现在输出,如果您愿意,可以轻松转换为JSONXML

现在它产生结果:

Name                           Value
----                           -----
Client1                        {IsEmail}
Client1                        {IsShip}
Client2                        {IsEmail}
Client2                        {IsPack}
Client1 -> IsEmail -> time: 20180226_13:31:58
Client1 -> IsEmail -> value: 1
Client1 -> IsShip -> time: 20180226_13:31:58
Client1 -> IsShip -> value: 0
Client2 -> IsEmail -> time: 20180226_13:31:58
Client2 -> IsEmail -> value: 1
Client2 -> IsPack -> time: 20180226_13:31:58
Client2 -> IsPack -> value: 0

使用JSON格式:

[
    {
        "Client1":  {
                        "IsEmail":  {
                                        "time":  "20180226_14:40:02",
                                        "value":  1
                                    }
                    }
    },
    {
        "Client1":  {
                        "IsShip":  {
                                       "time":  "20180226_14:40:02",
                                       "value":  0
                                   }
                    }
    },
    {
        "Client2":  {
                        "IsEmail":  {
                                        "time":  "20180226_14:40:02",
                                        "value":  1
                                    }
                    }
    },
    {
        "Client2":  {
                        "IsPack":  {
                                       "time":  "20180226_14:40:02",
                                       "value":  0
                                   }
                    }
    }
]

第二次修改

至于DB。也许最好的解决方案是使用Sqlite,查看关于它的technet wiki PowerShell: Accessing SQLite databases