非交互模式的Powershell测试

mat*_*hew 18 powershell

我有一个可以手动运行的脚本,也可以由计划任务运行.我需要以编程方式确定我是否在非交互模式(通过计划任务运行时设置)或正常模式运行.我已经google了,我能找到的最好的是添加命令行参数,但我没有任何可行的方法来执行计划任务,也不能合理地期望用户在运行时添加参数手动.非交互模式是否设置了某种变量或我可以在脚本中检查的内容?

编辑:我实际上无意中回答了我自己的问题,但我将它留在这里为后代.

我在脚本中插入了一个读取主机,要求用户提供一些东西,当它以非交互模式运行时,繁荣,终止错误.把它放在try/catch块中,根据我所处的模式做事.

不是最漂亮的代码结构,但它的工作原理.如果其他人有更好的方法请添加它!

Ver*_*Ray 21

作为一个完整的解决方案,我不喜欢任何其他答案.[Environment]::UserInteractive报告用户是否是交互式的,而不是特定的过程是否是交互式的.api对于检测您是否在服务中运行非常有用.这是我处理这两种情况的解决方案:

function Test-IsNonInteractiveShell {
    if ([Environment]::UserInteractive) {
        foreach ($arg in [Environment]::GetCommandLineArgs()) {
            # Test each Arg for match of abbreviated '-NonInteractive' command.
            if ($arg -like '-NonI*') {
                return $true
            }
        }
    }

    return $false
}
Run Code Online (Sandbox Code Playgroud)

注意:此代码是不必要的冗长,运行时间为3.5毫秒(平均而言),但可以很好地说明功能.我有一个更简洁的解决方案,在我的GitHub上运行2.7毫秒(平均).评估执行时间Measure-Command; 性能取决于系统性能.

  • [环境] :: UserInteractive完全符合我的预期和要求.在ISE和Powershell控制台下,它返回true,作为计划任务,它返回false.谢谢. (3认同)

CB.*_*CB. 14

您可以使用wmi检查powershell的调用方式:

 (gwmi win32_process | ? { $_.processname -eq "powershell.exe" }) | select commandline
Run Code Online (Sandbox Code Playgroud)

规定:

commandline
-----------

"C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe"  -noprofile -NonInteractive
Run Code Online (Sandbox Code Playgroud)

  • 如果有多个PowerShell.exe实例在运行,请避免误报:`gwmi -Class Win32_Process -Filter"ProcessID = $ PID"| 选择-Expand CommandLine` (11认同)
  • WMI 是一种非常昂贵的方法来实现这一点,使用 PowerShell 过滤进程而不是 WMI 会增加成本。总的来说,这有点像跑到外面看窗户以确定灯是否亮着。 (3认同)

Tho*_*ten 5

我认为这个问题需要更彻底的评估。

  • “交互式”意味着 shell 作为 REPL 运行——连续的读取-执行-打印循环。

  • “非交互式”意味着 shell 正在执行脚本、命令或脚本块,并在执行后终止。

如果 PowerShell 使用任何选项-Command-EncodedCommand、 或运行-File,则它是非交互式的。不幸的是,您也可以运行不带选项 ( ) 的脚本pwsh script.ps1,因此没有可靠的方法来检测 shell 是否是交互式的。

那么我们运气不好吗?不会,幸运的是 PowerShell 会自动添加选项,我们可以测试 PowerShell 是否运行脚本块或通过 ssh 运行来执行命令 ( ssh user@host command)。

function IsInteractive {
    # not including `-NonInteractive` since it apparently does nothing
    # "Does not present an interactive prompt to the user" - no, it does present!
    $non_interactive = '-command', '-c', '-encodedcommand', '-e', '-ec', '-file', '-f'

    # alternatively `$non_interactive [-contains|-eq] $PSItem`
    -not ([Environment]::GetCommandLineArgs() | Where-Object -FilterScript {$PSItem -in $non_interactive})
}

Run Code Online (Sandbox Code Playgroud)

现在在您的 PowerShell 配置文件中测试这是否处于交互模式,因此当您执行脚本、命令或脚本块时,配置文件不会运行(您仍然必须记住运行pwsh -f script.ps1- 不是pwsh script.ps1

if (-not (IsInteractive)) {
    exit
}
Run Code Online (Sandbox Code Playgroud)