So sortieren Sie Registrierungseinträge nach der letzten Schreibzeit / der letzten Änderungszeit in PowerShell
Ich lerne PowerShell und verwende PSCore7.1 unter Windows 10 20H2. Derzeit kann ich Folgendes tun:
Get-ChildItem -Path "C:\" -Directory -Recurse -Depth 5 | Where-Object{$_.LastWriteTime.ToString("yyyy-MM-dd") -eq "2020-12-14"} | Sort-Object LastWriteTime
Um rekursiv Unterordner innerhalb einer bestimmten Tiefe (in diesem Fall 5) eines angegebenen Verzeichnisses (in diesem Fall C :) abzurufen, suchen Sie nach Objekten, die in einem bestimmten Zeitbereich (in diesem Fall heute oder am 14. Dezember 2020) geändert wurden, und sortieren Sie schließlich die Ergebnisse nach Zeitstempel.
Aber wenn ich get-childitem starte, um die Registrierung wie folgt anzuzeigen:
Get-ChildItem -Path "HKLM:\SOFTWARE"
Es gibt nur zwei Elemente: Name und Eigenschaft, kein Zeitstempel, und in regedit.exe gibt es auch keinen Zeitstempel. Wie kann ich Registrierungsschlüssel nach der zuletzt geänderten Zeit sortieren, wie mit dem Befehl, den ich oben mit PowerShell gepostet habe?
Bearbeiten: Ich habe hier in Super User gelesen, dass ich Registrierungsschlüssel in TXT-Dateien im Registrierungseditor exportieren kann, um deren Zeitstempel anzuzeigen. Obwohl dies einfach ist, ist es für diese Frage irrelevant, da ich Registrierungsschlüssel nach Zeitstempel in der Konsole sortieren möchte.
Erneut bearbeiten:
Ich habe diesen Befehl ausgeführt:
get-childitem -path "HKLM:\" | Get-Member
Und hier sind die Ergebnisse:
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;}
Wie Sie sehen können, gibt es keinen Zeitstempel ...
Zitieren: Gibt es eine Möglichkeit, Änderungsdaten für Windows-Registrierungsschlüssel / -werte anzuzeigen?
Beweis:
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
Antworten
Leider kann dies aufgrund des Zugriffs von Windows auf Registrierungsschlüsselinformationen kompliziert werden, aber es ist möglich. Im Folgenden finden Sie eine Reihe von Tutorials von Dr. Scripto im Microsoft-Devblog:
- Verwenden Sie Powershell, um auf den zuletzt geänderten Zeitstempel der Registrierung zuzugreifen. Hier erfahren Sie, wie Sie in Powershell die Win32-Funktion verwenden
RegQueryInfoKey
, um Zeitstempel abzurufen . - Die Wiederverwendung des Zeitstempelcodes für die Powershell-Registrierung umfasst das Erstellen eines wiederverwendbaren Tools durch Umschließen dieses Codes in eine Windows PowerShell-Funktion.
- Die Nutzung von Zeitstempeln für Registrierungsschlüssel über Powershell deckt einige reale Verwendungszwecke ab.
Das Endprodukt wird folgendermaßen aussehen und als Add-RegKeyLastWriteTime.ps1 gespeichert:
#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 🙂 } "ByPath" { # We need a RegistryKey object (Get-Item should return that) $Item = Get-Item -Path $Path -ErrorAction Stop # Make sure this is of type [Microsoft.Win32.RegistryKey] if ($Item -isnot [Microsoft.Win32.RegistryKey]) {
throw "'$Path' is not a path to a registry key!" } $RegistryKey = $Item } } # Initialize variables that will be populated: $ClassLength = 255 # Buffer size (class name is rarely used, and when it is, I've never seen
# it more than 8 characters. Buffer can be increased here, though.
$ClassName = New-Object System.Text.StringBuilder $ClassLength # Will hold the class name
$LastWriteTime = New-Object System.Runtime.InteropServices.ComTypes.FILETIME switch ($RegTools::RegQueryInfoKey($RegistryKey.Handle, $ClassName,
[ref] $ClassLength, $null, # Reserved
[ref] $null, # SubKeyCount [ref] $null, # MaxSubKeyNameLength
[ref] $null, # MaxClassLength [ref] $null, # ValueCount
[ref] $null, # MaxValueNameLength [ref] $null, # MaxValueValueLength
[ref] $null, # SecurityDescriptorSize [ref] $LastWriteTime
)) {
0 { # Success
# Convert to DateTime object:
$UnsignedLow = [System.BitConverter]::ToUInt32([System.BitConverter]::GetBytes($LastWriteTime.dwLowDateTime), 0)
$UnsignedHigh = [System.BitConverter]::ToUInt32([System.BitConverter]::GetBytes($LastWriteTime.dwHighDateTime), 0)
# Shift high part so it is most significant 32 bits, then copy low part into 64-bit int:
$FileTimeInt64 = ([Int64] $UnsignedHigh -shl 32) -bor $UnsignedLow # Create datetime object $LastWriteTime = [datetime]::FromFileTime($FileTimeInt64) # Add properties to object and output them to pipeline $RegistryKey | Add-Member -NotePropertyMembers @{
LastWriteTime = $LastWriteTime ClassName = $ClassName.ToString()
} -PassThru -Force
}
122 { # ERROR_INSUFFICIENT_BUFFER (0x7a)
throw "Class name buffer too small"
# function could be recalled with a larger buffer, but for
# now, just exit
}
default {
throw "Unknown error encountered (error code $_)"
}
}
}
}
Dann endlich ein Anwendungsbeispiel:
Get-ChildItem HKCU:\ | Add-RegKeyLastWriteTime | Select Name,LastWriteTime
'
Name LastWriteTime
---- -------------
HKEY_CURRENT_USER\AppEvents 7/6/2020 8:56:11 AM
HKEY_CURRENT_USER\Console 7/6/2020 8:56:11 AM
HKEY_CURRENT_USER\Control Panel 7/6/2020 1:04:53 PM
'