Register-WmiEvent报错:无法将字符串转换为ScriptBlock求助
问题描述
编写了一段监控USB插入并自动扫描的PowerShell脚本,运行时触发错误:
Register-WmiEvent: Cannot bind parameter 'Action'. Cannot convert the value of type "System.String" to type "System.Management.Automation.ScriptBlock"
脚本代码如下:
$logPath = "C:\USBScanLogs" if (-not (Test-Path $logPath)) { New-Item -Path $logPath -ItemType Directory } function Start-USBScan { param ( [string[]]$DriveLetters ) foreach ($DriveLetter in $DriveLetters) { Write-Host "Scanning USB Drive: $DriveLetter" if (Get-Command -Name Start-MpScan -ErrorAction SilentlyContinue) { # Start scanning the drive Start-MpScan -ScanType CustomScan -ScanPath "$DriveLetter\" -ErrorAction Stop Write-Host "Scanning drive $DriveLetter with Windows Defender..." } else { Write-Host "Windows Defender not available. Please ensure it is installed." } # Log results $timeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Add-Content -Path "$logPath\scan_log.txt" -Value "$timeStamp - Scanned drive $DriveLetter" } } function Get-RemovableDrives { # Get all drives except C:\ $drives = Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Name -ne 'C' -and $_.Used -ge 0 } return $drives.Name } # Monitor the event log for Event ID 6416 (USB device inserted) Write-Host "Monitoring for Event ID 6416 (USB devices)..." Register-WmiEvent -Query "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_NTLogEvent' AND TargetInstance.EventCode = '6416'" -SourceIdentifier 'USBDetection' -Action { # This is the ScriptBlock to be executed when the event is triggered # Get the event details $eventData = $Event.SourceEventArgs.NewEvent.TargetInstance.InsertionStrings $usbDetails = $eventData[0] Write-Host "USB device connected: $usbDetails" # Retrieve all available drives except C:\ $drivesToScan = Get-RemovableDrives # Start scan on each drive Start-USBScan -DriveLetters $drivesToScan } Write-Host "USB Scan Monitor started. Waiting for a USB device to be inserted..."
问题原因与修复方案
核心原因
Register-WmiEvent的-Action参数要求传入脚本块(ScriptBlock),但你的代码可能因以下原因被解析为字符串:
- 脚本文件采用无BOM的UTF-8编码,PowerShell对这种编码的脚本块识别存在兼容性问题
- 脚本块的换行符格式异常(比如使用了Unix格式而非Windows格式)
- 隐藏的语法错误导致PowerShell无法正确识别大括号内的脚本块
此外还有两个隐藏问题:
- 事件触发的脚本块运行在独立子会话中,无法直接调用主会话定义的
Get-RemovableDrives和Start-USBScan函数 - 通过
Win32_NTLogEvent监控USB插入的延迟较高,不如直接监控设备卷事件高效
修复步骤
1. 确保脚本块被正确识别
将脚本保存为UTF-8 with BOM格式,这是PowerShell对UTF-8编码脚本的兼容格式。同时检查脚本块大括号周围没有多余引号或语法错误。
2. 解决跨会话函数访问问题
将所需函数直接嵌入到-Action脚本块中,或通过$using:作用域引用主会话变量,确保子会话能访问必要的逻辑和数据。
3. 优化USB监控方式(推荐)
改用Win32_VolumeChangeEvent直接监控卷挂载事件,相比监控事件日志,能更及时触发扫描且无需依赖事件日志记录。
修复后的完整脚本
$logPath = "C:\USBScanLogs" if (-not (Test-Path $logPath)) { New-Item -Path $logPath -ItemType Directory -Force | Out-Null } # 监控USB卷挂载事件(替代原事件日志监控) Write-Host "Monitoring for USB drive connections..." Register-WmiEvent -Query "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2" -SourceIdentifier 'USBDetection' -Action { # 在脚本块内定义所需函数,确保子会话可访问 function Start-USBScan { param ( [string[]]$DriveLetters ) $logPath = $using:logPath foreach ($DriveLetter in $DriveLetters) { Write-Host "Scanning USB Drive: $DriveLetter" if (Get-Command -Name Start-MpScan -ErrorAction SilentlyContinue) { Start-MpScan -ScanType CustomScan -ScanPath "$DriveLetter\" -ErrorAction Stop Write-Host "Scanning drive $DriveLetter with Windows Defender..." } else { Write-Host "Windows Defender not available. Please ensure it is installed." } $timeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Add-Content -Path "$logPath\scan_log.txt" -Value "$timeStamp - Scanned drive $DriveLetter" } } function Get-RemovableDrives { Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Name -ne 'C' -and $_.DriveType -eq 'Removable' } | Select-Object -ExpandProperty Name } # 获取当前挂载的USB驱动器号 $driveLetter = $Event.SourceEventArgs.NewEvent.DriveName.TrimEnd('\') Write-Host "USB device connected: $driveLetter" Start-USBScan -DriveLetters $driveLetter } | Out-Null Write-Host "USB Scan Monitor started. Waiting for a USB device to be inserted..." # 保持会话运行,避免脚本退出后终止事件监控 Wait-Event -SourceIdentifier 'USBDetection'
额外说明
- 修复后的脚本直接监控卷挂载事件,触发扫描的响应速度更快
- 通过
$using:logPath引用主会话的日志路径变量,解决跨会话数据访问问题 - 在脚本块内定义函数,避免了跨会话作用域的限制
- 最后添加
Wait-Event命令,确保脚本运行后保持事件监控状态
内容的提问来源于stack exchange,提问作者GregSemedo
相关产品推荐
相关产品推荐

