gpt4 book ai didi

Make elevated powershell, started from a script, execute a command - and wait for the user to answer related prompt?(从脚本开始提升PowerShell,执行命令,然后等待用户回答相关提示?)

转载 作者:bug小助手 更新时间:2023-10-28 13:45:43 26 4
gpt4 key购买 nike



I want to have a Powershell script in Windows 10, that will inspect if a TCP port is in use by some program/process, and if so, ask for elevated administrative privileges, and then kill that process.

我想在Windows 10中有一个PowerShell脚本,它将检查某个程序/进程是否正在使用一个TCP端口,如果是,则请求提升管理权限,然后终止该进程。


After a ton of searching, I finally found a case simple enough to be used as a minimal example. First of all, install "Simple TCP/IP Services" from "Turn Windows Features on or off" (see also https://techgenix.com/windows-7-simple-tcpip-services-what-how/). It seems this service does not start immediately, so to start it, do from Administrator command prompt:

经过大量的搜索,我终于找到了一个足够简单的案例,可以作为一个最小的例子。首先,安装“打开或关闭Windows功能”中的“简单的tcp/IP服务”(另见https://techgenix.com/windows-7-simple-tcpip-services-what-how/).此服务似乎不会立即启动,因此要启动它,请从管理员命令提示符执行以下操作:


C:\>sc start simptcp

SERVICE_NAME: simptcp
TYPE : 20 WIN32_SHARE_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
PID : 22508
FLAGS :

With the "Simple TCP/IP Services", one can get a quote of the day via telnet localhost 17 - so, it listens on port 17.

使用“简单的TCP/IP服务”,用户可以通过telnet本地主机17获取当天的报价-因此,它在端口17上监听。


Typically, this is what I would do, if I'd want to scan for port 17, and kill the corresponding process, in Administrator PowerShell; first, if the service is inactive, we get an error:

通常,如果我想在管理员PowerShell中扫描端口17并终止相应的进程,我会这样做;首先,如果服务处于非活动状态,我们会收到一个错误:


PS C:\WINDOWS\system32> $portProcessID = ( Get-NetTCPConnection -LocalPort 17 ).OwningProcess
Get-NetTCPConnection : No MSFT_NetTCPConnection objects found with property 'LocalPort' equal to '17'. Verify the value of
the property and retry.
At line:1 char:20
+ $portProcessID = ( Get-NetTCPConnection -LocalPort 17 ).OwningProcess
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (17:UInt16) [Get-NetTCPConnection], CimJobException
+ FullyQualifiedErrorId : CmdletizationQuery_NotFound_LocalPort,Get-NetTCPConnection

... but if the service is started, the procedure would look like this:

..。但如果启动该服务,过程将如下所示:


PS C:\WINDOWS\system32> $portProcessID = ( Get-NetTCPConnection -LocalPort 17 ).OwningProcess
PS C:\WINDOWS\system32> $portProcessID
22508
22508
PS C:\WINDOWS\system32> # note, there are two process id above! can extract the first with $portProcessID[0]
PS C:\WINDOWS\system32> ( Get-WmiObject win32_process | Where-Object {$_.ProcessID -eq $portProcessID[0] } ).ProcessName
TCPSVCS.EXE
PS C:\WINDOWS\system32> Stop-Process -id $portProcessID[0]

Confirm
Are you sure you want to perform the Stop-Process operation on the following item: TCPSVCS(22508)?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y

To make sure it is shut down - again from Administrator Command Prompt:

要确保它已关闭-同样是从管理员命令提示符:


C:\>sc queryex simptcp

SERVICE_NAME: simptcp
TYPE : 20 WIN32_SHARE_PROCESS
STATE : 1 STOPPED
WIN32_EXIT_CODE : 1067 (0x42b)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 0
FLAGS :

So far, so good - now I'd like to have this scripted ...

到目前为止,一切都很好-现在我想把这个写成脚本……


So, after some research I came up with the following Powershell script, check_and_free_port.ps1:

因此,在进行了一些研究之后,我想出了以下PowerShell脚本:check_and_free_port.ps1:


Add-Type -AssemblyName PresentationFramework

[int] $portNum = 65535

function Check-Port-Kill-Process {
[bool] $portNumUsed = $true

# cannot try/catch errors below;
# as per https://stackoverflow.com/q/62346135, use -ErrorAction SilentlyContinue
if ( Get-NetTCPConnection -LocalPort $portNum -ErrorAction SilentlyContinue ) {
#"portNum $portNum in use"
$portNumUsed = $true
# note, we may end up with two process id above! can extract the first with $portProcessID[0]
# (and that should work also even in the case when $portProcessID has a single entry)
$portProcessID = ( Get-NetTCPConnection -LocalPort $portNum ).OwningProcess
} else {
$portNumUsed = $false
}

if ($portNumUsed) {
$portProcessName = ( Get-WmiObject win32_process | Where-Object {$_.ProcessID -eq $portProcessID[0] } ).ProcessName
"Port $portNum is in use by another process ($portProcessName, pid: $portProcessID)!"
} else {
"Port $portNum is unused"
}

if ($portNumUsed) {
# ask for elevated administrative privilege, to be able to run `Stop-Process -id $portProcessID`
$Msg = @"
NOTE: You will be asked next for administrative permission,
to kill the process ($portProcessName, pid: $portProcessID).
"@
[System.Windows.MessageBox]::Show($Msg)

# the below just shows powershell window and exits without waiting for the prompt, in spite of -Wait
#Start-Process powershell -Wait -ArgumentList 'Stop-Process -id $portProcessID' -verb RunAs
# https://stackoverflow.com/q/1741490/
$proc = Start-Process powershell -ArgumentList 'Stop-Process -id $portProcessID[0]' -verb RunAs -PassThru
$proc.WaitForExit()
}
} # end function

$portNum = 17 # set actual port to test
Check-Port-Kill-Process

If the service is NOT started, and I run this script from a normal (non-elevated/non-Administrator) Command Prompt, I get this:

如果服务未启动,并且我从普通(非提升/非管理员)命令提示符运行此脚本,则会得到以下结果:


C:\>powershell .\check_and_free_port.ps1
Port 17 is unused

Great, that works as intended; however, let's start the service again (if you want to use the command line, you have to go back to Administrator Command Prompt, and then do sc start simptcp again) - and try the script again thereafter (in normal Command Prompt):

很好,它按预期工作;但是,让我们再次启动该服务(如果要使用命令行,您必须返回到管理员命令提示符,然后再次执行sc start simptcp)-然后在之后再次尝试该脚本(在正常的命令提示符中):


C:\>powershell .\check_and_free_port.ps1
Port 17 is in use by another process (TCPSVCS.EXE, pid: 25128 25128)!

... and I get a message box with:

...我收到一个留言框


---------------------------

---------------------------
NOTE: You will be asked next for administrative permission,
to kill the process (TCPSVCS.EXE, pid: 25128 25128).
---------------------------
OK
---------------------------

... as intended; but then, I click OK here - and:

..。如预期的那样;但随后,我在此处单击确定-然后:



  • I get the "Do you want to allow this app to make changes to your device" privilege elevation prompt - great, exactly as intended

  • I click Yes here; thereafter:

  • I can see a PowerShell window get started for about a second, but then it disappears


... and since I did not get the "Are you sure you want to perform the Stop-Process..." prompt, and could not answer Y(es) to it, and the task has not been killed either.

..。而且由于我没有得到“您确定要执行停止进程吗?”提示,并且无法回答是,该任务也没有被终止。


So, basically, I've tried running Stop-Process -id $portProcessID in the elevated prompt above, but it did not work.

因此,基本上,我尝试在上面提升的提示符中运行Stop-Process-id$portProcessID,但不起作用。


What changes need to be done to the script above, so that when the elevated Powershell process is started, it actually runs the Stop-Process -id $portProcessID command - and asks the resulting "Are you sure you want to perform the Stop-Process..." prompt, and waits for me to enter Y(es) there, before finally killing the required process (and then exiting)?

需要对上面的脚本进行哪些更改,以便在启动提升的PowerShell进程时,它实际上运行Stop-Process-id$portProcessID命令-并询问结果“是否确实要执行Stop-Process...”提示,并等待我在那里输入Y(ES),最后终止所需的进程(然后退出)?


更多回答

Run script As Admin by right click PS shortcut and select Run As Admin.

以管理员身份运行脚本,方法是右键单击PS快捷方式,然后选择以管理员身份运行。

Thanks @jdweng but that is not the answer - as mentioned, I already do get the elevated permission prompt no problem, it's just that nothing executed in it. However, I think I found my errors, see my answer below.

谢谢@jdweng,但这不是答案-正如前面提到的,我已经得到了提升的权限提示没有问题,只是里面没有执行任何东西。但是,我想我找到了我的错误,请看下面我的回答。

优秀答案推荐

To offer some improvements and general tips regarding your own solution:

提供有关您自己的解决方案的一些改进和一般提示:


Your code:

您的代码:



$portProcessIDsingle = $portProcessID[0]
$proc = Start-Process powershell -ArgumentList "-Command `"& {Stop-Process -id $portProcessIDsingle}`"" -verb RunAs -PassThru
$proc.WaitForExit()


can be simplified to:

可以简化为:


Start-Process -Wait -Verb RunAs powershell -ArgumentList "Stop-Process -Id $($portProcessID[0])"


  • When using powershell.exe, the Windows PowerShell CLI, the -Command (-c) parameter is implied when you pass a command to execute.

    使用Powershell.exe(Windows PowerShell CLI)时,当您传递要执行的命令时,会隐含-Command(-c)参数。



    • However, with pwsh.exe, the PowerShell (Core) CLI, you must specify it, because -File is now the default.

      但是,对于PowerShell(核心)CLI pwsh.exe,您必须指定它,因为-文件现在是缺省设置。



    • For better or worse, the command can be passed either enclosed in (embedded) "..." as a whole, or as individual arguments that are joined to form the PowerShell code to execute after command-line parsing. While using overall "..." quoting is preferable when calling from shells (such as cmd.exe, to avoid potentially up-front interpretation of arguments, this isn't necessary in no-shell invocations such as with Start-Process.

      不管是好是坏,该命令可以用(嵌入的)“...”括起来传递作为一个整体,或作为连接成PowerShell代码的单个参数在命令行分析后执行。同时使用整体的“...”当从外壳(如cmd.exe)调用时,最好使用引号,以避免可能预先解释参数,这在无外壳调用(如使用Start-Process)中不是必需的。





  • Start-Process's -Wait switch is effective in combination with -Verb RunAs too.

    Start-Process的-Wait开关与-Verb RunAs结合使用也很有效。



  • There's no reason to use "& { ... }" in order to invoke code passed to PowerShell's CLI via the (possibly implied) -Command (-c) parameter - just use "..." directly. Older versions of the CLI documentation erroneously suggested that & { ... } is required, but this has since been corrected.

    没有理由使用“&{...}”来调用通过(可能隐含的)-Command(-c)参数传递到PowerShell的CLI的代码-只需使用“...”直接去吧。较早版本的CLI文档错误地建议&{...}是必需的,但后来更正了这一点。



  • In order to embed an expression - such as indexed access to a variable's value ($portProcessID[0]) inside "...", an expandable (interpolating) string, you must enclose it in $(...), the subexpression operator.

    为了嵌入一个表达式--比如对变量值($portProcessID[0])的索引访问,“.“,一个可扩展(插值)字符串,必须将其括在$(...)中,子表达式操作符。



    • For a comprehensive but concise summary of PowerShell's expandable strings (string-interpolation rules), see this answer.





Got it: first problem was not having -Command in the argument list passed to PowerShell (see https://github.com/juanpablojofre/About/blob/master/v3/Topic/PowerShell.exe-Command-Line-Help.md)

明白了:第一个问题是没有将参数列表中的-Command传递给PowerShell(请参阅https://github.com/juanpablojofre/About/blob/master/v3/Topic/PowerShell.exe-Command-Line-Help.md)


Second problem became visible only when I added -NoExit to the argument list; then I could see that the newly started elevated PowerShell dumps this error:

第二个问题只有在我将-noexit添加到参数列表中时才可见;然后我可以看到新启动的提升PowerShell转储此错误:


Stop-Process : A positional parameter cannot be found that accepts argument '25128[0]'

... which means something got messed up with the quoting there.

..。这意味着那里的引用有些地方搞砸了。


After some tinkering, I finally arrived to this snippet, that works as intended:

经过一番修修补补,我终于找到了这段代码,它的工作方式与预期相符:


  if ($portNumUsed) {
# ask for elevated administrative privilege, to be able to run `Stop-Process -id $portProcessID`
$Msg = @"
NOTE: You will be asked next for administrative permission,
to kill the process ($portProcessName, pid: $portProcessID).
"@
[System.Windows.MessageBox]::Show($Msg)

# the below just shows powershell window and exits without waiting for the prompt, in spite of -Wait
#Start-Process powershell -Wait -ArgumentList 'Stop-Process -id $portProcessID' -verb RunAs
# https://stackoverflow.com/q/1741490/
# add -NoExit before -Command in -ArgumentList to debug;
# might get something like below for -Command `"& {Stop-Process -id $portProcessID[0]}`":
# "Stop-Process : A positional parameter cannot be found that accepts argument '25128[0]'."
# the below invocation seems to work fine:
$portProcessIDsingle = $portProcessID[0]
$proc = Start-Process powershell -ArgumentList "-Command `"& {Stop-Process -id $portProcessIDsingle}`"" -verb RunAs -PassThru
$proc.WaitForExit()
}

Note finally, that when the elevated Powershell terminal starts, it will not print the command itself, only it's output - and once you answer Y (or N), the elevated Powershell terminal will close itself (exactly as I wanted it to in this case).

最后,请注意,当提升的PowerShell终端启动时,它不会打印命令本身,而只是输出-一旦您回答Y(或N),提升的PowerShell终端将自动关闭(就像我在本例中希望它关闭的那样)。


更多回答

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com