PowerShell: Running a command as Administrator
你知道如果你是一个系统的管理用户,你只需右键单击批处理脚本,然后以管理员身份运行它,而不需要输入管理员密码吗?
我想知道如何使用PowerShell脚本执行此操作。我不想输入密码;我只想模仿右键单击以管理员身份运行的方法。
到目前为止,我读到的所有内容都要求您提供管理员密码。
如果当前控制台未提升,并且您尝试执行的操作需要提升的权限,则可以使用"以管理员身份运行"选项启动PowerShell。
1 | PS> Start-Process powershell -Verb runAs |
下面是对Shay Levi建议的补充(只需在脚本开头添加这些行):
1 2 3 4 5 6 7 | If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) { $arguments ="& '" + $myinvocation.mycommand.definition +"'" Start-Process powershell -Verb runAs -ArgumentList $arguments Break } |
这将导致当前脚本以管理员模式传递给新的PowerShell进程(如果当前用户有权访问管理员模式,并且脚本不是以管理员身份启动)。
自提升PowerShell脚本
Windows 8.1/PowerShell 4.0+
一行:
1 2 3 | if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) { Start-Process powershell.exe"-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit } # Your script here |
本杰明阿姆斯特朗发表了一篇关于自我提升PowerShell脚本的优秀文章。他的代码有一些小问题;下面是根据注释中建议的修复程序修改的版本。
基本上,它获取与当前进程关联的标识,检查它是否是管理员,如果不是,则创建具有管理员权限的新PowerShell进程并终止旧进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | # Get the ID and security principal of the current user account $myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent(); $myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID); # Get the security principal for the administrator role $adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator; # Check to see if we are currently running as an administrator if ($myWindowsPrincipal.IsInRole($adminRole)) { # We are running as an administrator, so change the title and background colour to indicate this $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition +"(Elevated)"; $Host.UI.RawUI.BackgroundColor ="DarkBlue"; Clear-Host; } else { # We are not running as an administrator, so relaunch as administrator # Create a new process object that starts PowerShell $newProcess = New-Object System.Diagnostics.ProcessStartInfo"PowerShell"; # Specify the current script path and name as a parameter with added scope and support for scripts with spaces in it's path $newProcess.Arguments ="& '" + $script:MyInvocation.MyCommand.Path +"'" # Indicate that the process should be elevated $newProcess.Verb ="runas"; # Start the new process [System.Diagnostics.Process]::Start($newProcess); # Exit from the current, unelevated, process Exit; } # Run your code that needs to be elevated here... Write-Host -NoNewLine"Press any key to continue..."; $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown"); |
您可以创建一个批处理文件(
1 2 3 4 5 6 7 | @echo off set scriptFileName=%~n0 set scriptFolderPath=%~dp0 set powershellScriptFileName=%scriptFileName%.ps1 powershell -Command"Start-Process powershell "-ExecutionPolicy Bypass -NoProfile -NoExit -Command `"cd \`"%scriptFolderPath%\`"; & \`".\%powershellScriptFileName%\`"`"" -Verb RunAs" |
就是这样!
解释如下:
假设PowerShell脚本位于
命令将执行该命令
1 | powershell -Command"Start-Process powershell "-ExecutionPolicy Bypass -NoProfile -NoExit -Command `"cd \`"C:\Temp\`"; & \`".\ScriptTest.ps1\`"`"" -Verb RunAs" |
将打开新的PowerShell会话并执行以下命令:
1 | Start-Process powershell"-ExecutionPolicy Bypass -NoProfile -NoExit -Command `"cd \`"C:\Temp\`"; & \`".\ScriptTest.ps1\`"`"" -Verb RunAs |
将在
1 | -ExecutionPolicy Bypass -NoProfile -NoExit -Command"cd "C:\Temp"; & ".\ScriptTest.ps1"" |
将使用管理权限执行以下命令:
1 | cd"C:\Temp"; &".\ScriptTest.ps1" |
一旦脚本路径和名称参数被双引号引用,它们就可以包含空格或单引号字符(
当前文件夹将从
您可以轻松地添加一些注册表项,以获得用于
1 2 3 | New-Item -Path"Registry::HKEY_CLASSES_ROOT\Microsoft.PowershellScript.1\Shell unas\command" ` -Force -Name '' -Value '"c:\windows\system32\windowspowershell\v1.0\powershell.exe" -noexit"%1"' |
(从@shay更新为更简单的脚本)
基本上,在
unas\command
使用
还没有说明。似乎只有在PowerShell4.0之后才会出现。
http://technet.microsoft.com/en-us/library/hh847765.aspx
When this switch parameter is added to your requires statement,
it specifies that the Windows PowerShell session in which you are
running the script must be started with elevated user rights
(Run as Administrator).
对我来说,这似乎是一个很好的方法,但我还不确定现场经验。PowerShell3.0运行时可能会忽略这一点,甚至更糟的是,会给出一个错误。
当脚本以非管理员身份运行时,会出现以下错误:
The script 'StackOverflow.ps1' cannot be run because it contains a
"#requires" statement for running as Administrator. The current
Windows PowerShell session is not running as Administrator. Start
Windows PowerShell by using the Run as Administrator option, and then
try running the script again.
1
2 + CategoryInfo : PermissionDenied: (StackOverflow.ps1:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptRequiresElevation
乔纳森和肖伊·利维发布的密码对我不起作用。
请在下面找到工作代码:
1 2 3 4 5 6 7 8 9 10 11 | If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) { #"No Administrative rights, it will display a popup window asking user for Admin rights" $arguments ="& '" + $myinvocation.mycommand.definition +"'" Start-Process"$psHome\powershell.exe" -Verb runAs -ArgumentList $arguments break } #"After user clicked Yes on the popup, your file will be reopened with Admin rights" #"Put your code here" |
您需要使用管理权限重新运行该脚本,并检查该脚本是否在该模式下启动。下面我编写了一个脚本,它有两个功能:doelevatedOperations和dostandardOperations。您应该将需要管理权限的代码放在第一个代码中,将标准操作放在第二个代码中。isrunasadmin变量用于标识管理模式。
我的代码是从Microsoft脚本中简化的摘录,该脚本在您为Windows应用商店应用程序创建应用程序包时自动生成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | param( [switch]$IsRunAsAdmin = $false ) # Get our script path $ScriptPath = (Get-Variable MyInvocation).Value.MyCommand.Path # # Launches an elevated process running the current script to perform tasks # that require administrative privileges. This function waits until the # elevated process terminates. # function LaunchElevated { # Set up command line arguments to the elevated process $RelaunchArgs = '-ExecutionPolicy Unrestricted -file"' + $ScriptPath + '" -IsRunAsAdmin' # Launch the process and wait for it to finish try { $AdminProcess = Start-Process"$PsHome\PowerShell.exe" -Verb RunAs -ArgumentList $RelaunchArgs -PassThru } catch { $Error[0] # Dump details about the last error exit 1 } # Wait until the elevated process terminates while (!($AdminProcess.HasExited)) { Start-Sleep -Seconds 2 } } function DoElevatedOperations { Write-Host"Do elevated operations" } function DoStandardOperations { Write-Host"Do standard operations" LaunchElevated } # # Main script entry point # if ($IsRunAsAdmin) { DoElevatedOperations } else { DoStandardOperations } |
您还可以强制应用程序以管理员身份打开。当然,如果您有管理员帐户。
找到文件,右键单击>属性>快捷方式>高级并选中以管理员身份运行
然后单击确定。
加上我的2美分。我的基于网络会话的简单版本在Windows7/Windows10中一直有效。为什么过于复杂化?
1 | if (!(net session)) {$path = "& '" + $myinvocation.mycommand.definition +"'" ; Start-Process powershell -Verb runAs -ArgumentList $path ; exit} |
只需添加到脚本顶部,它将以管理员身份运行。
oaming\Microsoft\Windows\Start Menu\Programs\Windows PowerShell
由于PowerShell是在权限相关时由用户配置文件驱动的;如果您的用户名/配置文件具有执行某项操作的权限,那么在PowerShell中,您通常也可以执行该操作。也就是说,您可以更改位于用户配置文件下的快捷方式,例如
oaming\Microsoft\Windows\Start Menu\Programs\Windows PowerShell
右键单击并单击"属性"。单击"快捷方式"选项卡下的"高级"按钮,该选项卡位于其他两个按钮"打开文件位置"和"更改图标"右侧相邻的"注释"文本字段正下方。
选中"以管理员身份运行"复选框。单击ok,然后单击apply和ok。再次右键单击位于
oaming\Microsoft\Windows\Start Menu\Programs\Windows PowerShell
现在,无论何时单击该图标,它都会调用UAC进行升级。选择"是"后,您将注意到PowerShell控制台已打开,屏幕顶部将标记为"管理员"。
再往前走一步…您可以右键单击Windows PowerShell配置文件位置中的同一图标快捷方式,并指定一个键盘快捷方式,该快捷方式将执行与单击最近添加的图标完全相同的操作。因此,如果它说"快捷键",则输入键盘键/按钮组合,如:ctrl+alt+pp(用于PowerShell)。单击apply和ok。
现在,您所要做的就是按下您分配的按钮组合,您将看到UAC被调用,选择"是"后,您将看到一个PowerShell控制台出现,标题栏上显示"管理员"。
这种行为是设计出来的。由于Microsoft真的不希望.ps1文件成为最新的电子邮件病毒,因此存在多个安全层。有些人认为这与任务自动化的概念背道而驰,这是公平的。vista+安全模型是为了"去自动化"一些事情,从而使用户可以接受它们。
但是,我怀疑如果您以提升的方式启动PowerShell本身,它应该能够运行批处理文件,而无需再次请求密码,直到您关闭PowerShell。
这里的许多答案都很接近,但比需要的工作要多一些。
创建脚本的快捷方式并将其配置为"以管理员身份运行":
- 创建快捷方式。
- 右击快捷键,打开
Properties... 。 - 从
到powershell 编辑Target 。 - 单击avanced…并启用
Run as administrator 。
另一个更简单的解决方案是,您也可以右键单击"c:windowssystem32cmd.exe"并选择"以管理员身份运行",然后您可以以管理员身份运行任何应用程序,而无需提供任何密码。
@pgk和@andrew odri的答案的问题是,当您有脚本参数时,特别是当它们是必需的时。您可以使用以下方法解决此问题:
下面是如果脚本具有computername和port强制参数,代码将如何处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | [CmdletBinding(DefaultParametersetName='RunWithPowerShellContextMenu')] param ( [parameter(ParameterSetName='CallFromCommandLine')] [switch] $CallFromCommandLine, [parameter(Mandatory=$false, ParameterSetName='RunWithPowerShellContextMenu')] [parameter(Mandatory=$true, ParameterSetName='CallFromCommandLine')] [string] $ComputerName, [parameter(Mandatory=$false, ParameterSetName='RunWithPowerShellContextMenu')] [parameter(Mandatory=$true, ParameterSetName='CallFromCommandLine')] [UInt16] $Port ) function Assert-AdministrativePrivileges([bool] $CalledFromRunWithPowerShellMenu) { $isAdministrator = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if ($isAdministrator) { if (!$CalledFromRunWithPowerShellMenu -and !$CallFromCommandLine) { # Must call itself asking for obligatory parameters &"$PSCommandPath" @script:PSBoundParameters -CallFromCommandLine Exit } } else { if (!$CalledFromRunWithPowerShellMenu -and !$CallFromCommandLine) { $serializedParams = [Management.Automation.PSSerializer]::Serialize($script:PSBoundParameters) $scriptStr = @" `$serializedParams = '$($serializedParams -replace"'","''")' `$params = [Management.Automation.PSSerializer]::Deserialize(`$serializedParams) &"$PSCommandPath" @params -CallFromCommandLine "@ $scriptBytes = [System.Text.Encoding]::Unicode.GetBytes($scriptStr) $encodedCommand = [Convert]::ToBase64String($scriptBytes) # If this script is called from another one, the execution flow must wait for this script to finish. Start-Process -FilePath 'powershell' -ArgumentList"-ExecutionPolicy Bypass -NoProfile -EncodedCommand $encodedCommand" -Verb 'RunAs' -Wait } else { # When you use the"Run with PowerShell" feature, the Windows PowerShell console window appears only briefly. # The NoExit option makes the window stay visible, so the user can see the script result. Start-Process -FilePath 'powershell' -ArgumentList"-ExecutionPolicy Bypass -NoProfile -NoExit -File""$PSCommandPath""" -Verb 'RunAs' } Exit } } function Get-UserParameters() { [string] $script:ComputerName = [Microsoft.VisualBasic.Interaction]::InputBox('Enter a computer name:', 'Testing Network Connection') if ($script:ComputerName -eq '') { throw 'The computer name is required.' } [string] $inputPort = [Microsoft.VisualBasic.Interaction]::InputBox('Enter a TCP port:', 'Testing Network Connection') if ($inputPort -ne '') { if (-not [UInt16]::TryParse($inputPort, [ref]$script:Port)) { throw"The value '$inputPort' is invalid for a port number." } } else { throw 'The TCP port is required.' } } # $MyInvocation.Line is empty in the second script execution, when a new powershell session # is started for this script via Start-Process with the -File option. $calledFromRunWithPowerShellMenu = $MyInvocation.Line -eq '' -or $MyInvocation.Line.StartsWith('if((Get-ExecutionPolicy') Assert-AdministrativePrivileges $calledFromRunWithPowerShellMenu # Necessary for InputBox [System.Reflection.Assembly]::Load('Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') | Out-Null if ($calledFromRunWithPowerShellMenu) { Get-UserParameters } # ... script code Test-NetConnection -ComputerName $ComputerName -Port $Port |
我正在使用下面的解决方案。它通过转录功能处理stdout/stderr,并将退出代码正确传递给父进程。您需要调整转录路径/文件名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) { echo"* Respawning PowerShell child process with elevated privileges" $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName ="powershell" $pinfo.Arguments ="& '" + $myinvocation.mycommand.definition +"'" $pinfo.Verb ="RunAs" $pinfo.RedirectStandardError = $false $pinfo.RedirectStandardOutput = $false $pinfo.UseShellExecute = $true $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() echo"* Child process finished" type"C:/jenkins/transcript.txt" Remove-Item"C:/jenkins/transcript.txt" Exit $p.ExitCode } Else { echo"Child process starting with admin privileges" Start-Transcript -Path"C:/jenkins/transcript.txt" } # Rest of your script goes here, it will be executed with elevated privileges |
我找到了一种方法…
创建批处理文件以打开脚本:
1 2 | @echo off START"""C:\Scripts\ScriptName.ps1" |
然后在桌面上创建一个快捷方式,比如说(右键单击新建->快捷方式)。
然后将其粘贴到以下位置:
1 2 | C:\Windows\System32 unas.exe /savecred /user:*DOMAIN*\*ADMIN USERNAME* C:\Scripts\BatchFileName.bat |
第一次打开时,必须输入一次密码。然后将其保存在Windows凭据管理器中。
之后,您就可以以管理员身份运行,而无需输入管理员用户名或密码。
除Shay Levy的回答外,按照以下设置(仅一次)
安装后:
现在您可以在一个命令行中运行所有内容。上述功能适用于Windows 8基本64位。
我发现最可靠的方法是将它包装在一个自提升的.bat文件中:
1 2 3 4 5 6 7 8 9 10 11 12 | @echo off NET SESSION 1>NUL 2>NUL IF %ERRORLEVEL% EQU 0 GOTO ADMINTASKS CD %~dp0 MSHTA"javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', '', '', 'runas', 0); close();" EXIT :ADMINTASKS powershell -file"c:\users\joecoder\scripts\admin_tasks.ps1" EXIT |
.bat检查您是否已经是管理员,并在需要时以管理员身份重新启动脚本。它还可以防止外来的"cmd"窗口打开,并将
我以前没见过自己的方法,所以试试看。它更容易跟随,而且占地面积更小:
1 2 3 | if([bool]([Security.Principal.WindowsIdentity]::GetCurrent()).Groups -notcontains"S-1-5-32-544") { Start Powershell -ArgumentList"& '$MyInvocation.MyCommand.Path'" -Verb runas } |
很简单,如果使用管理员权限调用当前PowerShell会话,则获取当前标识时,组中会显示管理员组已知的SID。即使帐户是该组的成员,SID也不会出现,除非用提升的凭据调用该进程。
几乎所有这些答案都是微软本·阿姆斯特朗广受欢迎的方法的一个变种,即如何在不真正了解实际情况的情况下完成它,以及如何模仿相同的程序。
要将命令输出附加到包含当前日期的文本文件名中,可以执行以下操作:
1 2 | $winupdfile = 'Windows-Update-' + $(get-date -f MM-dd-yyyy) + '.txt' if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) { Start-Process powershell.exe"-NoProfile -ExecutionPolicy Bypass -Command `"Get-WUInstall -AcceptAll | Out-File $env:USERPROFILE\$winupdfile -Append`"" -Verb RunAs; exit } else { Start-Process powershell.exe"-NoProfile -ExecutionPolicy Bypass -Command `"Get-WUInstall -AcceptAll | Out-File $env:USERPROFILE\$winupdfile -Append`""; exit } |
这是一个澄清…
PowerShell runas/savecred凭据"不安全",已尝试,并将管理员标识和密码添加到凭据缓存中,可在其他地方使用oops!。如果您这样做了,我建议您检查并删除条目。
请检查您的程序或代码,因为Microsoft策略是,如果没有UAC(入口点)以管理员身份执行程序,则不能在同一代码blob中混合用户和管理代码。这将是Linux上的sudo(相同的东西)。
UAC有3种类型,看不见,一个提示或程序清单中生成的入口点。它不会提升程序,因此如果没有UAC,它需要管理员,它将失败。UAC虽然作为一个管理员的需求是好的,但是它可以防止代码在没有身份验证的情况下执行,并且可以防止混合代码场景在用户级别执行。
结果证明这太容易了。你所要做的就是以管理员的身份运行一个命令。然后键入
它可能会要求您启用策略以运行,键入y并按Enter。现在脚本将以管理员身份在PowerShell中运行。如果一切都是红色的,那意味着你的政策还没有生效。然后再试一次,它会工作得很好。