You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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无法正确识别大括号内的脚本块

此外还有两个隐藏问题:

  1. 事件触发的脚本块运行在独立子会话中,无法直接调用主会话定义的Get-RemovableDrives和Start-USBScan函数
  2. 通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 09:37:02