我试图获取一个旧的PowerShell脚本来显示以前连接的USB设备的时间。在阅读了blogs之类的一些取证this后,我从this script找到了this blog。 (杰森沃克的剧本。)
不幸的是,它没有显示任何时间戳或有关设备的任何其他有用的详细信息。所以我希望there should be a way to get that too。只有我没有看到如何融入这一点。
Function Get-USBHistory {
[CmdletBinding()]
Param
(
[parameter(ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[alias("CN","Computer")]
[String[]]$ComputerName=$Env:COMPUTERNAME,
[Switch]$Ping
)
Begin {
$TempErrorAction = $ErrorActionPreference
$ErrorActionPreference = "Stop"
$Hive = "LocalMachine"
$Key = "SYSTEM\CurrentControlSet\Enum\USBSTOR"
}
Process
{
$USBDevices = @()
$ComputerCounter = 0
ForEach($Computer in $ComputerName)
{
$USBSTORSubKeys1 = @()
$ChildSubkeys = @()
$ChildSubkeys1 = @()
$ComputerCounter++
$Computer = $Computer.Trim().ToUpper()
Write-Progress -Activity "Collecting USB history" -Status "Retrieving USB history from $Computer" -PercentComplete (($ComputerCounter/($ComputerName.Count)*100))
If($Ping)
{
If(-not (Test-Connection -ComputerName $Computer -Count 1 -Quiet))
{
Write-Warning "Ping failed on $Computer"
Continue
}
}#end if ping
Try
{
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Hive,$Computer)
$USBSTORKey = $Reg.OpenSubKey($Key)
$USBSTORSubKeys1 = $USBSTORKey.GetSubKeyNames()
}#end try
Catch
{
Write-Warning "There was an error connecting to the registry on $Computer or USBSTOR key not found. Ensure the remote registry service is running on the remote machine."
}#end catch
ForEach($SubKey1 in $USBSTORSubKeys1)
{
$ErrorActionPreference = "Continue"
$Key2 = "SYSTEM\CurrentControlSet\Enum\USBSTOR\$SubKey1"
$RegSubKey2 = $Reg.OpenSubKey($Key2)
$SubkeyName2 = $RegSubKey2.GetSubKeyNames()
$ChildSubkeys += "$Key2\$SubKeyName2"
$RegSubKey2.Close()
}#end foreach SubKey1
ForEach($Child in $ChildSubkeys)
{
If($Child -match " ")
{
$BabySubkey = $null
$ChildSubkey1 = ($Child.split(" "))[0]
$SplitChildSubkey1 = $ChildSubkey1.split("\")
0..4 | Foreach{ [String]$BabySubkey += ($SplitChildSubkey1[$_]) + "\"}
$ChildSubkeys1 += $BabySubkey + ($Child.split(" ")[-1])
$ChildSubkeys1 += $ChildSubkey1
}
Else
{
$ChildSubkeys1 += $Child
}
$ChildSubKeys1.count
}#end foreach ChildSubkeys
ForEach($ChildSubkey1 in $ChildSubkeys1)
{
$USBKey = $Reg.OpenSubKey($ChildSubkey1)
$USBDevice = $USBKey.GetValue('FriendlyName')
If($USBDevice)
{
$USBDevices += New-Object -TypeName PSObject -Property @{
USBDevice = $USBDevice
Computer = $Computer
Serial = $ChildSubkey1.Split("\")[-1]
}
}
$USBKey.Close()
}#end foreach ChildSubKey2
$USBSTORKey.Close()
#Display results
$USBDevices | Select Computer,USBDevice,Serial
}#end foreach computer
}#end process
End
{
#Set error action preference back to original setting
$ErrorActionPreference = $TempErrorAction
}
}#end function
和C#代码:
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
class Program
{
static void Main(string[] args)
{
string usbStor = @"SYSTEM\ControlSet001\Enum\USBSTOR";
using (var keyUsbStor = Registry.LocalMachine.OpenSubKey(usbStor))
{
var usbDevices = from className in keyUsbStor.GetSubKeyNames()
let keyUsbClass = keyUsbStor.OpenSubKey(className)
from instanceName in keyUsbClass.GetSubKeyNames()
let keyUsbInstance = new RegistryKeyEx(keyUsbClass.OpenSubKey(instanceName))
select new
{
UsbName = keyUsbInstance.Key.GetValue("FriendlyName"),
ConnectTime = keyUsbInstance.LastWriteTime
};
foreach (var usbDevice in usbDevices.OrderBy(x => x.ConnectTime))
{
Console.WriteLine("({0}) -- '{1}'", usbDevice.ConnectTime, usbDevice.UsbName);
}
}
}
}
/// <summary>
/// Wraps a RegistryKey object and corresponding last write time.
/// </summary>
/// <remarks>
/// .NET doesn't expose the last write time for a registry key
/// in the RegistryKey class, so P/Invoke is required.
/// </remarks>
public class RegistryKeyEx
{
#region P/Invoke Declarations
// This declaration is intended to be used for the last write time only. int is used
// instead of more convenient types so that dummy values of 0 reduce verbosity.
[DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
extern private static int RegQueryInfoKey(
SafeRegistryHandle hkey,
int lpClass,
int lpcbClass,
int lpReserved,
int lpcSubKeys,
int lpcbMaxSubKeyLen,
int lpcbMaxClassLen,
int lpcValues,
int lpcbMaxValueNameLen,
int lpcbMaxValueLen,
int lpcbSecurityDescriptor,
IntPtr lpftLastWriteTime);
#endregion
#region Public Poperties
/// <summary>
/// Gets the registry key owned by the info object.
/// </summary>
public RegistryKey Key { get; private set; }
/// <summary>
/// Gets the last write time for the corresponding registry key.
/// </summary>
public DateTime LastWriteTime { get; private set; }
#endregion
/// <summary>
/// Creates and initializes a new RegistryKeyInfo object from the provided RegistryKey object.
/// </summary>
/// <param name="key">RegistryKey component providing a handle to the key.</param>
public RegistryKeyEx(RegistryKey key)
{
Key = key;
SetLastWriteTime();
}
/// <summary>
/// Creates and initializes a new RegistryKeyInfo object from a registry key path string.
/// </summary>
/// <param name="parent">Parent key for the key being loaded.</param>
/// <param name="keyName">Path to the registry key.</param>
public RegistryKeyEx(RegistryKey parent, string keyName)
: this(parent.OpenSubKey(keyName))
{ }
/// <summary>
/// Queries the currently set registry key through P/Invoke for the last write time.
/// </summary>
private void SetLastWriteTime()
{
Debug.Assert(Key != null, "RegistryKey component must be initialized");
GCHandle pin = new GCHandle();
long lastWriteTime = 0;
try
{
pin = GCHandle.Alloc(lastWriteTime, GCHandleType.Pinned);
if (RegQueryInfoKey(Key.Handle, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pin.AddrOfPinnedObject()) == 0)
{
LastWriteTime = DateTime.FromFileTime((long)pin.Target);
}
else
{
LastWriteTime = DateTime.MinValue;
}
}
finally
{
if (pin.IsAllocated)
{
pin.Free();
}
}
}
}
(抱歉,我无法正确显示PSH代码。)
如何使用它来改进脚本?
更新:2017-11-06
根据@ iRon的建议,我尝试使用RegEdit直接访问注册表路径HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR\<drive>\Properties
,但后来我收到了权限错误,这很奇怪,因为我的用户帐户是Admin。 (这是在Win8.1上)
我发现的其他一些选项是:
...\Windows\inf\setupapi.dev.log
中的日志文件以获取第一个连接日期,但如何获取最后一个连接则更加明确。 (据说通过比较\NTUSER\<username>\Software\Microsoft\Windows\Explorer\MountPoints2
数据,但我找不到它。)可能有用的PS单线程:
Get-WinEvent -LogName Microsoft-Windows-DriverFrameworks-UserMode/Operational | where {$_.Id -eq "2003" -or $_.Id -eq "2102"} | Format-Table –Property TimeCreated, Id, Message -AutoSize -Wrap
这为事件(2003,2102)提供了可以进一步解析的消息内容的时间戳。
TimeCreated Id Message
----------- -- -------
2017-11-09 13:37:04 2102 Forwarded a finished Pnp or Power operation (27, 2) to the lower driver for device
SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_KINGSTON&PROD_DATATRAVELER_G2&REV_PMAP#YYYYY&0#{XXXXX} with status 0x0.
2017-11-09 13:37:04 2102 Forwarded a finished Pnp or Power operation (27, 23) to the lower driver for device
SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_KINGSTON&PROD_DATATRAVELER_G2&REV_PMAP#YYYYY&0#{XXXXX} with status 0x0.
2017-11-09 13:34:38 2003 The UMDF Host Process ({XXXXX}) has been asked to load drivers for device
SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_KINGSTON&PROD_DATATRAVELER_G2&REV_PMAP#YYYYY&0#{XXXXX}.
2017-11-06 15:18:41 2102 Forwarded a finished Pnp or Power operation (27, 2) to the lower driver for device SWD\WPDBUSENUM\{XXXXX}#0000000000007E00 with status 0x0.
2017-11-06 15:18:41 2102 Forwarded a finished Pnp or Power operation (27, 23) to the lower driver for device SWD\WPDBUSENUM\{XXXXX}#0000000000007E00 with status 0x0.
2017-11-06 15:18:13 2003 The UMDF Host Process ({XXXXX}) has been asked to load drivers for device SWD\WPDBUSENUM\{XXXXX}#0000000000007E00.
答案 0 :(得分:1)
这还没有完成但是应该让你入门?
$code = @"
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
/// <summary>
/// Wraps a RegistryKey object and corresponding last write time.
/// </summary>
/// <remarks>
/// .NET doesn't expose the last write time for a registry key
/// in the RegistryKey class, so P/Invoke is required.
/// </remarks>
public class RegistryKeyEx
{
#region P/Invoke Declarations
// This declaration is intended to be used for the last write time only. int is used
// instead of more convenient types so that dummy values of 0 reduce verbosity.
[DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
extern private static int RegQueryInfoKey(
SafeRegistryHandle hkey,
int lpClass,
int lpcbClass,
int lpReserved,
int lpcSubKeys,
int lpcbMaxSubKeyLen,
int lpcbMaxClassLen,
int lpcValues,
int lpcbMaxValueNameLen,
int lpcbMaxValueLen,
int lpcbSecurityDescriptor,
IntPtr lpftLastWriteTime);
#endregion
#region Public Poperties
/// <summary>
/// Gets the registry key owned by the info object.
/// </summary>
public RegistryKey Key { get; private set; }
/// <summary>
/// Gets the last write time for the corresponding registry key.
/// </summary>
public DateTime LastWriteTime { get; private set; }
#endregion
/// <summary>
/// Creates and initializes a new RegistryKeyInfo object from the provided RegistryKey object.
/// </summary>
/// <param name="key">RegistryKey component providing a handle to the key.</param>
public RegistryKeyEx(RegistryKey key)
{
Key = key;
SetLastWriteTime();
}
/// <summary>
/// Creates and initializes a new RegistryKeyInfo object from a registry key path string.
/// </summary>
/// <param name="parent">Parent key for the key being loaded.</param>
/// <param name="keyName">Path to the registry key.</param>
public RegistryKeyEx(RegistryKey parent, string keyName)
: this(parent.OpenSubKey(keyName))
{ }
/// <summary>
/// Queries the currently set registry key through P/Invoke for the last write time.
/// </summary>
private void SetLastWriteTime()
{
Debug.Assert(Key != null, "RegistryKey component must be initialized");
GCHandle pin = new GCHandle();
long lastWriteTime = 0;
try
{
pin = GCHandle.Alloc(lastWriteTime, GCHandleType.Pinned);
if (RegQueryInfoKey(Key.Handle, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pin.AddrOfPinnedObject()) == 0)
{
LastWriteTime = DateTime.FromFileTime((long)pin.Target);
}
else
{
LastWriteTime = DateTime.MinValue;
}
}
finally
{
if (pin.IsAllocated)
{
pin.Free();
}
}
}
}
"@
$type = Add-Type -TypeDefinition $code -Language CSharp
$devices = Get-Item HKLM:\SYSTEM\ControlSet001\Enum\USBSTOR\*
$result = foreach($device in $devices) {
Write-Verbose -Verbose "New device: $($device.PSPath)"
Write-Verbose -Verbose "GetClass"
foreach($classname in $device.GetSubKeyNames()) {
$class = $device.OpenSubKey($class)
if($class -eq $null) {
Write-Verbose -Verbose "Class is null"
continue
}
Write-Verbose -Verbose "GetInstance"
foreach($instancename in $class.GetSubKeyNames()) {
$instance = $class.OpenSubKey($instancename)
if($instance -eq $null) {
Write-Verbose -Verbose "Instance is null"
continue
}
Write-Verbose -Verbose "RegistryKeyEx"
$keyEx = New-Object RegistryKeyEx $instance
[pscustomobject]@{
FriendlyName = $keyEx.key.GetValue('FriendlyName')
DevicePath = $device.PSPath
LastWriteTime = $keyEx.LastWriteTime
}
}
}
}
编辑:(通过not2qubit)
这个脚本是内嵌的C#sharp。当前版本提供以下输出:
VERBOSE: New device: Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Disk&Ven_Kingston&Prod_DataTraveler_G2&Rev_PMAP
VERBOSE: GetClass
VERBOSE: GetInstance
VERBOSE: RegistryKeyEx
VERBOSE: New device: Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Disk&Ven_WD&Prod_My_Passport_0730&Rev_1015
VERBOSE: GetClass
VERBOSE: Class is null
VERBOSE: New device: Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Other&Ven_WD&Prod_SES_Device&Rev_1015
VERBOSE: GetClass
VERBOSE: GetInstance
VERBOSE: RegistryKeyEx
因此缺少时间戳......
编辑:
除非您查看$result
变量。
PS C:\> $result
FriendlyName DevicePath LastWriteTime
------------ ---------- -------------
Corsair Survivor 3.0 USB Device Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Disk&Ven_Corsair&Prod_Survivor_3.0&Rev_1.00 2017-11-05 21:08:25
PS C:\> get-date
November 11, 2017 17:02:09
这将为您提供C#代码示例中的内容。这些信息是否足以满足您的需求,我无法说出来。