我正在使用 PowerShell 生成可移动媒体报告。我拥有所有高级审核设置,除了我无法弄清楚的一项之外,它按预期工作。
我插入了拇指驱动器,然后创建了一个新文件夹。当我收集 4656(和 4663)事件时,会为“新文件夹”生成一个 4656 事件,但是,对象名称不包含实际创建的文件夹的名称,它只是指出“新文件夹”。我正在寻找创建的实际文件夹。以下是创建对象的事件中返回的示例:
Object Name: \Device\HarddiskVolume3\Temp\New folder
没有生成包含实际文件夹名称(我可以找到)的事件,它们只是简单地指出“新文件夹”。我需要将其与其他事件关联起来吗?我已将返回的事件转换为 XML,但仍然无法在任何地方找到实际的文件夹名称。预先感谢您提供的任何帮助。
我不知道有任何设置可以使事件日志服务在日志条目中呈现卷标,但您可以通过解析与分区
X
关联的卷标来转换对象路径,其中 X
是数字以下\Device\HarddiskVolume
:
注意:下面的示例代码使用 PowerShell 6.1 中引入的
-replace '...', {...}
语法 - 对于 PowerShell 5.1 及更早版本,请参阅本答案底部的替代语法
$objectNameData = $eventXml.SelectSingleNode('//Event/EventData/Data[@Name="ObjectName"]')
# yields "\Device\HarddiskVolume3\Temp\New Folder"
$objectNameData.InnerText
# yields "C:\Temp\New Folder"
$objectNameData.InnerText -replace '^\\Device\\HarddiskVolume(\d+)\\',{
(Get-Partition -PartitionNumber $_.Groups[1].Value).AccessPaths.Where({$_ -like '?:\*'}, 'First')[0]
}
为了避免一遍又一遍地重复查询同一分区的 WMI,请使用哈希表来缓存已解析的路径:
$volumeLabelCache = @{}
foreach ($eventXml in $events) {
$objectPath = $eventXml.SelectSingleNode('//Event/EventData/Data[@Name="ObjectName"]').InnerText
$resolvedPath = $objectPath -replace '^\\Device\\HarddiskVolume(\d+)\\',{
$partitionID = $_.Groups[1].Value
if (-not $volumeLabelCache.Contains($partitionID)) {
# cache volume label so we don't need to query the same partition id again
$volumeLabelCache[$partitionID] = (Get-Partition -PartitionNumber $partitionID).AccessPaths.Where({$_ -like '?:\*'}, 'First')[0]
if (-not $volumeLabelCache[$partitionID]){
# looks like we failed to resolve mount point from partition id, return original path
return $_.Value
}
}
# ... otherwise replace partition part of the object path with volume label
return $volumeLabelCache[$partitionID]
}
Write-Host "Resolved path '$resolvedPath' from '$objectPath'"
}
对于 6.1 之前的 PowerShell 版本,您可以直接调用
[regex]::Replace
来访问内联回调:
'input' -replace 'pattern', { substitution code <# over $_ #> }
# becomes
[regex]::Replace('input', 'pattern', {param($m) substitution code <# over $m #> })
使用上面的示例代码,将是这样的:
[regex]::Replace($objectPath, '^\\Device\\HarddiskVolume(\d+)\\', {
param($m)
$partitionID = $m.Groups[1].Value
if (-not $volumeLabelCache.Contains($partitionID)) {
# cache volume label so we don't need to query the same partition id again
$volumeLabelCache[$partitionID] = (Get-Partition -PartitionNumber $partitionID).AccessPaths.Where({$_ -like '?:\*'}, 'First')[0]
if (-not $volumeLabelCache[$partitionID]){
# looks like we failed to resolve mount point from partition id, return original path
return $m.Value
}
}
# ... otherwise replace partition part of the object path with volume label
return $volumeLabelCache[$partitionID]
}