PowerShell脚本中实现限时读取用户输入

简介: 突然想到之前倒腾PowerShell的时候实现了一个限时读取用户输入的函数

问题描述

在PowerShell脚本编写的时候,我们会使用Read-Host函数来接收用户的输入,但是很多时候我们想要在这个函数上附加一个超时效果,即等待用户在一段时间输入内容,如果超过时间脚本便不再等待。

解决方案概述

由于PowerShell可以调用C#代码,所以如果有C#的大佬的话,可能会有一些其他的实现思路,同时也欢迎分享。由于我对于C#了解不多,所以还是从PowerShell的角度来实现。我的实现方式我自认为具有以下特点:

  • 支持Window PowerShell和.Net PowerShell
    PowerShell有Window PowerShell版本,也就是Window自带的PowerShell。还有一种可以跨平台的.Net Core版本,官方仓库在这里Window PowerShell基本上都没有怎么维护了,所以现在的Window 10/11自带的都是Window PowerShell的5.1版本。开发时使用的是Widnow PowerShell版本,然后写好之后对于.Net Core版本做了一个适配。
  • 性能不是很好
    本函数为了做到超时终端读取效果,会开启一个进程来读取用户输入,超时再杀死进程,所以性能不高。之前我也试过一些底层的控制IO输入输入的C++接口,使用下来有一些Bug,所以最终才使用这种方式实现。
  • 效果完美(自认为)
    用户如果在限定时间输入,结果就会返回用户输入,如果超时会有提示,同时返回NULL。这个逻辑在调试的时候依旧不存在任何异常情况(这里直接指出是因为之前用了一个C#的方案,在调试的时候会出现一个Bug)。当然,你也可以在理解原理之后自行根据需求修改

源码及分析

PowerShell生态本身就不是很好,如果你只是想要在PowerShell中实现这个效果而已,那你完全可以拷贝这个函数直接用即可,不用花时间分析原理。

FunctionRead-HostWithTimeout{param([string]$Prompt="请输入内容: ",[System.ConsoleColor]$PromptBackGroundColor=$Host.UI.RawUI.BackgroundColor,[System.ConsoleColor]$PromptForeGroundColor=$Host.UI.RawUI.ForegroundColor,[int]$Timeout=5000,[string]$TimeoutHint="输入超时",[System.ConsoleColor]$HintBackgroundColor=$Host.UI.RawUI.BackgroundColor,[System.ConsoleColor]$HintForeGroundColor=[System.ConsoleColor]::Yellow)# 在这里调用输出提示的内容而不是在新进程里面提示是因为新进程提示的内容会被计入返回值,这里就不会Write-Host$Prompt-ForegroundColor$PromptForeGroundColor-BackgroundColor$PromptBackGroundColor-NoNewline$res=try{# Windows PowerShell会在超时结束抛出异常,所以这里需要定义异常可捕捉$ErrorActionPreference='Stop'# 新开线程执行超时读取的逻辑,注意,这里跟了一个timeout的参数,这个参数内部可以读取到powershell.exe-Command{param($Timeout)# 在这个进程里面新开一个Powershell线程,线程之间共享控制台对象$InitialSessionState=[initialsessionstate]::CreateDefault()$InitialSessionState.Variables.Add([System.Management.Automation.Runspaces.SessionStateVariableEntry]::new("ThreadContext",@{Host=$Host},"share host between threads"))$PSThread=[powershell]::Create($InitialSessionState)$null=$PSThread.AddScript{$ThreadContext.Host.UI.ReadLine()# 执行读取控制台操作}# 开始异步执行创建好的对象,并等待timeout秒无结果之后杀死本进程$Job=$PSThread.BeginInvoke()if(-not$Job.AsyncWaitHandle.WaitOne($Timeout)){Get-Process-Id$PID|Stop-Process}else{return$PSThread.EndInvoke($Job)}}-args$Timeout}catch{# Windows PowerShell超时会执行这里的代码Write-Host$TimeoutHint-ForegroundColor$HintForeGroundColor-BackgroundColor$HintBackGroundColor}# .Net Core PowerShell超时会执行这里的代码if($null-eq$res-and$PSVersionTable.PSEdition-eq"Core"){Write-Host$TimeoutHint-ForegroundColor$HintForeGroundColor-BackgroundColor$HintBackGroundColor}return$res}


调用示例


$res = Read-HostWithTimeout -Timeout 3000

# 超时$res的值就为null

# 有输入$res的值就为用户输入

Write-Host $res

目录
相关文章
|
3月前
|
存储 安全 Windows
PowerShell系列(六):PowerShell脚本执行策略梳理
【2月更文挑战第1篇】PowerShell 脚本执行策略用于控制何时以及何种方式执行 PowerShell 脚
|
6月前
|
安全 API
Powershell脚本分析
Powershell脚本分析
|
4月前
|
运维 开发工具 Windows
PowerShell系列(五):PowerShell通过脚本方式运行笔记
【1月更文挑战第7天】方便迁移,比如在之前工作经验积累下来的运维脚本,可以保存下来。如果业务场景用的到的话,直接文件拷贝过来就可以运行。
|
5月前
|
前端开发 微服务 Windows
PowerShell 命令窗口执行 pnpm 命令报错 无法加载文件 pnpm.ps1,因为在此系统上禁止运行脚本
PowerShell 命令窗口执行 pnpm 命令报错 无法加载文件 pnpm.ps1,因为在此系统上禁止运行脚本
|
8月前
|
SQL 数据库
PowerShell 脚本必备命令
PowerShell 脚本必备命令
|
Windows
powershell配置anaconda及解决【无法加载文件C:\Users\xxx\Documents\WindowsPowerShell\profile.ps1,因为在此系统上禁止运行脚本】的问题
powershell配置anaconda及解决【无法加载文件C:\Users\xxx\Documents\WindowsPowerShell\profile.ps1,因为在此系统上禁止运行脚本】的问题
1553 0
|
资源调度
关于vscode,powershell运行yarn报错禁止运行脚本解决办法
关于vscode,powershell运行yarn报错禁止运行脚本解决办法
154 0
关于vscode,powershell运行yarn报错禁止运行脚本解决办法
|
资源调度
PowerShell yarn : 无法加载文件 C:\Users\Admin\AppData\Roaming\npm\yarn.ps1,因为在此系统因为在此系统上禁止运行脚本。
PowerShell yarn : 无法加载文件 C:\Users\Admin\AppData\Roaming\npm\yarn.ps1,因为在此系统因为在此系统上禁止运行脚本。
178 0
PowerShell yarn : 无法加载文件 C:\Users\Admin\AppData\Roaming\npm\yarn.ps1,因为在此系统因为在此系统上禁止运行脚本。
|
监控 Windows
Windows Server端口监控之powershell脚本
powershell检测端口并重启程序
603 0