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

目录
相关文章
|
7月前
|
存储 安全 Windows
PowerShell系列(六):PowerShell脚本执行策略梳理
【2月更文挑战第1篇】PowerShell 脚本执行策略用于控制何时以及何种方式执行 PowerShell 脚
|
1月前
【Azure App Service】PowerShell脚本批量添加IP地址到Web App允许访问IP列表中
Web App取消公网访问后,只允许特定IP能访问Web App。需要写一下段PowerShell脚本,批量添加IP到Web App的允许访问IP列表里!
|
2月前
|
监控 关系型数据库 MySQL
PowerShell 脚本编写 :自动化Windows 开发工作流程
PowerShell 脚本编写 :自动化Windows 开发工作流程
56 0
|
2月前
|
数据安全/隐私保护
【Azure Entra ID】使用PowerShell脚本导出Entra ID中指定应用下的所有用户信息
在Azure Entra ID中,需要导出一个Application 下的用户信息, 包含User的创建时间。
|
4月前
【Azure Web Job】Azure Web Job执行Powershell脚本报错 The term 'Select-AzContext' is not recognized as the name
【Azure Web Job】Azure Web Job执行Powershell脚本报错 The term 'Select-AzContext' is not recognized as the name
|
4月前
|
Ubuntu Linux 测试技术
【Azure Function App】Python Function调用Powershell脚本在Azure上执行失败的案例
【Azure Function App】Python Function调用Powershell脚本在Azure上执行失败的案例
|
4月前
|
存储 Shell 容器
【Azure 存储服务】使用PowerShell脚本创建存储账号(Storage Account)的共享访问签名(SASToken) : New-AzStorageContainerSASToken
【Azure 存储服务】使用PowerShell脚本创建存储账号(Storage Account)的共享访问签名(SASToken) : New-AzStorageContainerSASToken
|
4月前
【Azure 应用服务】Azure Function 中运行Powershell 脚本,定位 -DefaultProfile 引发的错误
【Azure 应用服务】Azure Function 中运行Powershell 脚本,定位 -DefaultProfile 引发的错误
|
4月前
|
Java
【Azure 应用服务】使用PowerShell脚本上传文件至App Service目录  
【Azure 应用服务】使用PowerShell脚本上传文件至App Service目录  
|
4月前
|
Java 开发工具 Windows
【Azure Developer】调用SDK的runPowerShellScript方法,在Azure VM中执行PowerShell脚本示例
【Azure Developer】调用SDK的runPowerShellScript方法,在Azure VM中执行PowerShell脚本示例