Comment trier les entrées de registre par heure de dernière écriture / heure de dernière modification dans PowerShell
J'apprends PowerShell, j'utilise PSCore7.1 sur Windows 10 20H2, actuellement je peux le faire:
Get-ChildItem -Path "C:\" -Directory -Recurse -Depth 5 | Where-Object{$_.LastWriteTime.ToString("yyyy-MM-dd") -eq "2020-12-14"} | Sort-Object LastWriteTime
Pour obtenir récursivement des sous-dossiers dans une profondeur donnée (dans ce cas 5) d'un répertoire spécifié (dans ce cas C :), puis trouver des objets modifiés dans une plage de temps donnée (dans ce cas aujourd'hui ou 14 décembre 2020), et enfin trier le résultats par horodatage.
Mais quand j'exécute get-childitem pour afficher le registre, comme ceci:
Get-ChildItem -Path "HKLM:\SOFTWARE"
Il n'y a que deux éléments: Nom et Propriété, pas d'horodatage et dans regedit.exe, il n'y a pas non plus d'horodatage, alors comment puis-je trier les clés de registre par heure de dernière modification comme la commande que j'ai publiée ci-dessus à l'aide de PowerShell?
Edit: J'ai lu ici dans Super User Je peux exporter les clés de registre vers des fichiers txt dans l'éditeur de registre pour afficher leurs horodatages, bien que ce soit simple, cela n'est pas pertinent pour cette question car je veux trier les clés de registre par horodatage dans la console.
Ré-éditer:
J'ai exécuté cette commande:
get-childitem -path "HKLM:\" | Get-Member
Et voici les résultats:
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;}
Comme vous pouvez le voir, il n'y a pas d'horodatage ...
Citer: Existe - t-il un moyen d'afficher les dates des modifications apportées aux clés / valeurs de registre Windows?
Preuve:
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
Réponses
Malheureusement, cela peut se compliquer en raison de la façon dont Windows accède aux informations de clé de registre, mais c'est possible. Vous trouverez ci-dessous une série de didacticiels du Dr Scripto sur le devblog Microsoft:
- utiliser PowerShell pour accéder à l'horodatage de la dernière modification du registre explique comment, dans PowerShell, utiliser la fonction Win32
RegQueryInfoKey
pour obtenir des horodatages. - la réutilisation du code d'horodatage du registre PowerShell couvre la création d'un outil réutilisable en enveloppant ce code dans une fonction Windows PowerShell.
- exploiter les horodatages des clés de registre via PowerShell couvre une utilisation dans le monde réel.
Le produit final va ressembler à ceci, enregistré sous 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 🙂 } "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 $_)"
}
}
}
}
Puis enfin, un exemple d'utilisation:
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
'