我正在学习 PowerShell,我在 Windows 10 20H2 上使用 PSCore7.1,目前我可以这样做:
Get-ChildItem -Path "C:\" -Directory -Recurse -Depth 5 | Where-Object{$_.LastWriteTime.ToString("yyyy-MM-dd") -eq "2020-12-14"} | Sort-Object LastWriteTime
以递归方式获取指定目录(在本例中为 C:)的给定深度(在本例中为 5)内的子文件夹,然后查找在给定时间范围内(在本例中为今天或 2020 年 12 月 14 日)修改的对象,最后按时间戳对结果进行排序。
但是当我运行 get-childitem 来查看注册表时,如下所示:
Get-ChildItem -Path "HKLM:\SOFTWARE"
只有两个项目:名称和属性,没有时间戳,并且在 regedit.exe 中也没有时间戳,那么我如何才能像我上面发布的命令一样使用 PowerShell 按上次修改时间对注册表项进行排序?
编辑:我在超级用户中读到过,我可以将注册表项导出到注册表编辑器中的 txt 文件以查看它们的时间戳,虽然这很简单,但与这个问题无关,因为我想在控制台中按时间戳对注册表项进行排序。
重新编辑:
我已经运行了这个命令:
get-childitem -path "HKLM:\" | Get-Member
结果如下:
TypeName: Microsoft.Win32.RegistryKey
Name MemberType Definition
---- ---------- ----------
Close Method void Close()
CreateSubKey Method Microsoft.Win32.RegistryKey CreateSubKey(string subkey), Microsoft.Win32.RegistryKey CreateSubKey(string subkey, bool writable…
DeleteSubKey Method void DeleteSubKey(string subkey), void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
DeleteSubKeyTree Method void DeleteSubKeyTree(string subkey), void DeleteSubKeyTree(string subkey, bool throwOnMissingSubKey)
DeleteValue Method void DeleteValue(string name), void DeleteValue(string name, bool throwOnMissingValue)
Dispose Method void Dispose(), void IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
Flush Method void Flush()
GetAccessControl Method System.Security.AccessControl.RegistrySecurity GetAccessControl(), System.Security.AccessControl.RegistrySecurity GetAccessCon…
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetSubKeyNames Method string[] GetSubKeyNames()
GetType Method type GetType()
GetValue Method System.Object GetValue(string name), System.Object GetValue(string name, System.Object defaultValue), System.Object GetValue(s…
GetValueKind Method Microsoft.Win32.RegistryValueKind GetValueKind(string name)
GetValueNames Method string[] GetValueNames()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
OpenSubKey Method Microsoft.Win32.RegistryKey OpenSubKey(string name), Microsoft.Win32.RegistryKey OpenSubKey(string name, bool writable), Micro…
SetAccessControl Method void SetAccessControl(System.Security.AccessControl.RegistrySecurity registrySecurity)
SetValue Method void SetValue(string name, System.Object value), void SetValue(string name, System.Object value, Microsoft.Win32.RegistryValue…
ToString Method string ToString()
Property NoteProperty string[] Property=System.String[]
PSChildName NoteProperty string PSChildName=BCD00000000
PSDrive NoteProperty PSDriveInfo PSDrive=HKLM
PSIsContainer NoteProperty bool PSIsContainer=True
PSParentPath NoteProperty string PSParentPath=Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE
PSPath NoteProperty string PSPath=Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\BCD00000000
PSProvider NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\Registry
Handle Property Microsoft.Win32.SafeHandles.SafeRegistryHandle Handle {get;}
Name Property string Name {get;}
SubKeyCount Property int SubKeyCount {get;}
ValueCount Property int ValueCount {get;}
View Property Microsoft.Win32.RegistryView View {get;}
如您所见,没有时间戳......
引用:有没有办法查看 Windows 注册表项/值的更改日期?
证明:
Key Name: HKEY_CLASSES_ROOT\._bsln140
Class Name: <NO CLASS>
Last Write Time: 2020-12-11 - 14:54
Value 0
Name: <NO NAME>
Type: REG_SZ
Data: VisualStudio.Launcher._bsln140
答案1
不幸的是,由于 Windows 访问注册表项信息的方式,这可能会变得很复杂,但这是可能的。以下是 Dr Scripto 在 Microsoft devblog 上发布的一系列教程:
- 使用 powershell 访问注册表上次修改时间戳介绍如何在 powershell 中使用 Win32 函数
RegQueryInfoKey
获取时间戳。 - 重用 powershell 注册表时间戳代码介绍如何通过将代码包装在 Windows PowerShell 函数中来创建可重复使用的工具。
- 通过 powershell 利用注册表项时间戳涵盖一些现实世界的用法。
最终产品将如下所示,保存为 Add-RegKeyLastWriteTime.ps1:
#requires -version 3.0
function Add-RegKeyLastWriteTime {
[CmdletBinding()]
param(
[Parameter(Mandatory, ParameterSetName="ByKey", Position=0, ValueFromPipeline)]
# Registry key object returned from Get-ChildItem or Get-Item
[Microsoft.Win32.RegistryKey] $RegistryKey,
[Parameter(Mandatory, ParameterSetName="ByPath", Position=0)]
# Path to a registry key
[string] $Path
)
begin {
# Define the namespace (string array creates nested namespace):
$Namespace = "HeyScriptingGuy"
# Make sure type is loaded (this will only get loaded on first run):
Add-Type @"
using System;
using System.Text;
using System.Runtime.InteropServices;
$($Namespace | ForEach-Object {
"namespace $_ {"
})
public class advapi32 {
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern Int32 RegQueryInfoKey(
Microsoft.Win32.SafeHandles.SafeRegistryHandle hKey,
StringBuilder lpClass,
[In, Out] ref UInt32 lpcbClass,
UInt32 lpReserved,
out UInt32 lpcSubKeys,
out UInt32 lpcbMaxSubKeyLen,
out UInt32 lpcbMaxClassLen,
out UInt32 lpcValues,
out UInt32 lpcbMaxValueNameLen,
out UInt32 lpcbMaxValueLen,
out UInt32 lpcbSecurityDescriptor,
out System.Runtime.InteropServices.ComTypes.FILETIME lpftLastWriteTime
);
}
$($Namespace | ForEach-Object { "}" })
"@
# Get a shortcut to the type:
$RegTools = ("{0}.advapi32" -f ($Namespace -join ".")) -as [type]
}
process {
switch ($PSCmdlet.ParameterSetName) {
"ByKey" {
# Already have the key, no more work to be done