PowerShell에서 마지막 쓰기 시간 / 마지막 수정 시간별로 레지스트리 항목을 정렬하는 방법
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
답변
불행히도 Windows가 레지스트리 키 정보에 액세스하는 방법으로 인해 복잡해질 수 있지만 가능합니다. 다음은 Microsoft devblog에서 Scripto 박사가 작성한 일련의 자습서입니다.
- 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 🙂 } "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 $_)"
}
}
}
}
마지막으로 사용 예 :
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
'