我有一个可以手动运行的脚本,也可以由计划任务运行。我需要以编程方式确定我是否在非交互模式(通过计划任务运行时设置)或正常模式运行。我已经google了,我能找到的最好的是添加命令行参数,但我没有任何可行的方法来执行计划任务,也不能合理地期望用户在运行时添加参数手动。 非交互模式是否设置了某种变量或我可以在我的脚本中检查的内容?
编辑: 我实际上无意中回答了我自己的问题,但是我将它留在这里作为后代。
我在脚本中插入了一个读取主机,要求用户提供一些东西,当它以非交互模式运行时,繁荣,终止错误。把它放在try / catch块中,根据我所处的模式做事。
不是最漂亮的代码结构,但它有效。如果其他人有更好的方法请添加它!
答案 0 :(得分: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
}
注意:此代码无需冗长,运行时间为3.5毫秒(平均而言),但可以很好地说明功能。我有一个更简洁的解决方案,在my GitHub上以2.7毫秒(平均)运行。 使用Measure-Command
评估的执行时间;性能取决于系统性能。
答案 1 :(得分:14)
您可以使用wmi检查powershell的调用方式:
(gwmi win32_process | ? { $_.processname -eq "powershell.exe" }) | select commandline
提供:
commandline
-----------
"C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe" -noprofile -NonInteractive
答案 2 :(得分:2)
我想在这里提供一个更新的答案,因为似乎[Environment]::UserInteractive
在.NET Core(运行microsoft/nanoserver
的容器)和.NET Full(容器运行{{1}之间的行为不一样}})。
虽然microsoft/windowsservercore
会在“常规”Windows中返回[Environment]::UserInteractive
或True
,但它会在'nanoserver'中返回False
。
如果您想要检查交互模式而不考虑值,请将此检查添加到您的脚本中:
$null
编辑:要回答为何不仅仅检查真实性的评论,请考虑以下真值表:
($null -eq [Environment]::UserInteractive -or [Environment]::UserInteractive)
答案 3 :(得分:1)
C:\> powershell -NoProfile -NoLogo -NonInteractive -Command "[Environment]::GetCommandLineArgs()"
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
-NoProfile
-NoLogo
-NonInteractive
-Command
[Environment]::GetCommandLineArgs()
答案 4 :(得分:1)
我想出了一个现有且经过验证的C#代码的豪华端口,该代码使用相当多的P / Invoke来确定所有极端情况。此代码用于PowerShell Build Script,用于协调围绕Visual Studio项目的几个构建任务。
{{1}}
答案 5 :(得分:1)
测试交互性应该考虑到流程和用户。寻找-NonInteractive
(最小-noni
)powershell开关来确定进程交互性(非常类似于@ VertigoRay的脚本)可以使用具有轻量级-like
条件的简单过滤器来完成:
function Test-Interactive
{
<#
.Synopsis
Determines whether both the user and process are interactive.
#>
[CmdletBinding()] Param()
[Environment]::UserInteractive -and
!([Environment]::GetCommandLineArgs() |? {$_ -ilike '-NonI*'})
}
这避免了WMI的开销,进程探索,命令性混乱,双重否定命名,甚至是完整的正则表达式。
答案 6 :(得分:1)
我认为这个问题需要更彻底的评估。
“交互式”表示外壳程序以REPL运行-连续的读取-执行-打印循环。
“非交互式”表示外壳程序正在执行脚本,命令或脚本块,并且在执行后终止。
如果PowerShell在运行时使用任何选项-Command
,-EncodedCommand
或-File
,则它是非交互式的。不幸的是,您还可以运行没有 选项(pwsh script.ps1
)的脚本,因此没有防弹方法来检测外壳是否是交互式的。
那我们是不是很幸运?否,幸运的是,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})
}
现在在PowerShell配置文件中测试它是否处于交互模式,因此在执行脚本,命令或脚本块时该配置文件不会运行(您仍然必须记住运行pwsh -f script.ps1
-而不是{{1 }})
pwsh script.ps1
答案 7 :(得分:0)
实现两个脚本,一个core.ps1要手动启动,一个scheduled.ps1用一个参数启动core.ps1。
答案 8 :(得分:0)
powerShell -NonInteractive { Get-WmiObject Win32_Process -Filter "Name like '%powershell%'" | select-Object CommandLine }
powershell -Command { Get-WmiObject Win32_Process -Filter "Name like '%powershell%'" | select-Object CommandLine }
在第一种情况下,您将获得&#34; -NonInteractive&#34; PARAM。在后者中你赢了。
答案 9 :(得分:0)
脚本:IsNonInteractive.ps1
function Test-IsNonInteractive()
{
#ref: http://www.powershellmagazine.com/2013/05/13/pstip-detecting-if-the-console-is-in-interactive-mode/
#powershell -NoProfile -NoLogo -NonInteractive -File .\IsNonInteractive.ps1
return [bool]([Environment]::GetCommandLineArgs() -Contains '-NonInteractive')
}
Test-IsNonInteractive
示例用法(来自命令提示符)
pushd c:\My\Powershell\Scripts\Directory
::run in non-interactive mode
powershell -NoProfile -NoLogo -NonInteractive -File .\IsNonInteractive.ps1
::run in interactive mode
powershell -File .\IsNonInteractive.ps1
popd
更多参与示例Powershell脚本
#script options
$promptForCredentialsInInteractive = $true
#script starts here
function Test-IsNonInteractive()
{
#ref: http://www.powershellmagazine.com/2013/05/13/pstip-detecting-if-the-console-is-in-interactive-mode/
#powershell -NoProfile -NoLogo -NonInteractive -File .\IsNonInteractive.ps1
return [bool]([Environment]::GetCommandLineArgs() -Contains '-NonInteractive')
}
function Get-CurrentUserCredentials()
{
return [System.Net.CredentialCache]::DefaultCredentials
}
function Get-CurrentUserName()
{
return ("{0}\{1}" -f $env:USERDOMAIN,$env:USERNAME)
}
$cred = $null
$user = Get-CurrentUserName
if (Test-IsNonInteractive)
{
$msg = 'non interactive'
$cred = Get-CurrentUserCredentials
}
else
{
$msg = 'interactive'
if ($promptForCredentialsInInteractive)
{
$cred = (get-credential -UserName $user -Message "Please enter the credentials you wish this script to use when accessing network resources")
$user = $cred.UserName
}
else
{
$cred = Get-CurrentUserCredentials
}
}
$msg = ("Running as user '{0}' in '{1}' mode" -f $user,$msg)
write-output $msg
答案 10 :(得分:0)
使用-Noninteractive
开关启动PowerShell提示符时,它将返回一个布尔值。
[Environment]::GetCommandLineArgs().Contains('-NonInteractive')