以管理员身份从代理运行 Powershell 脚本

SEa*_*986 7 powershell windows-server sql-server-2014

当 SQL Server 服务启动时,我需要在我的服务器上的 IIS 中回收一个 AppPool。

我采取的路线是有一个启动存储过程,它运行具有 Powershell 作业步骤的代理作业。

我已经从互联网上创建/抓取了一个 Powershell 脚本来回收应用程序池:

# Load IIS module:
Import-Module WebAdministration
# Set a name of the site we want to recycle the pool for:
$site = "Default Web Site"
# Get pool name by the site name:
$pool = (Get-Item "IIS:\Sites\$site"| Select-Object applicationPool).applicationPool
# Recycle the application pool:
Restart-WebAppPool $pool
Run Code Online (Sandbox Code Playgroud)

这适用于操作系统级别,但仅当 Powershell 以管理员身份运行时才有效(即使我在 Admin 组中登录到 Windows 的帐户也是如此)

果然,如果我使用包含上述代码的 Powershell 步骤在代理中创建作业,则在执行时会出现错误

作业步骤在 PowerShell 脚本的第 6 行收到错误。对应的行是'$pool = (Get-Item "IIS:\Sites\$site"| Select-Object applicationPool).applicationPool'。更正脚本并重新安排作业。PowerShell 返回的错误信息是:'无法检索 cmdlet 的动态参数。文件名:redirection.config 错误:由于权限不足,无法读取配置文件'。进程退出代码 -1。步骤失败。

所以我需要一种从 SQL Server 代理“以管理员身份运行”的方法

我在操作系统级别成功创建了一个新脚本,该脚本以提升的权限运行原始脚本:

If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
  # Relaunch as an elevated process:
  Start-Process powershell.exe "-File",('"{0}"' -f $MyInvocation.MyCommand.Path) -Verb RunAs
  exit
}
# Now running elevated so launch the script:
& "d:\path\to\my\script.ps1"
Run Code Online (Sandbox Code Playgroud)

这允许我从非提升的 CMD 提示符或非提升的 Powershell 提示符运行新脚本。但是,当我尝试从代理作为 Powershell 步骤或 CMD 步骤运行时,我得到

机器默认权限设置不会将具有 CLSID {longguidhere} 和 APPID {longguidhere} 的 COM 服务器应用程序的本地激活权限授予来自在应用程序容器中运行的地址 LocalHost (Using LRPC) 的用户 NT SERVICE\SQLSERVERAGENT SID (longguidhere)不可用 SID(不可用)。可以使用组件服务管理工具修改此安全权限。

我也试过

Start-Process powershell -Verb runAs -FilePath "d:\path\to\my\script.ps1"
Run Code Online (Sandbox Code Playgroud)

再次,在操作系统级别工作但从代理运行时给我同样的错误。

我怎样才能得到

a:无需提升权限即可回收应用程序池

或者

b:运行脚本以从 SQL Server 代理回收具有提升权限的应用程序池?

Han*_*non 6

在通过 SQL Server 凭据使用特权 Windows 帐户的 SQL Server 代理中创建 PowerShell 代理。

创建凭证文档。

如何创建代理

这将允许您直接从 SQL Server 以管理员身份运行 PowerShell。

创建凭证是第一步,包括运行如下 T-SQL 语句:

CREATE CREDENTIAL MyPowerShellCredential   
WITH IDENTITY = 'DOMAIN\AdministratorAccount'  
    , SECRET = 'AdministratorAccountPassword'  
Run Code Online (Sandbox Code Playgroud)

创建凭据后,您需要创建 SQL Server PowerShell 代理。这应该有效:

USE msdb;
EXEC dbo.sp_add_proxy @proxy_name = N'MyPowerShellProxy'
    , @enabled=1
    , @description = N'Proxy used to run PowerShell as an administrator'
    , @credential_name = N'MyPowerShellCredential';
Run Code Online (Sandbox Code Playgroud)

创建代理后,您需要启用它以供 PowerShell 子系统使用。这段代码是这样做的:

USE msdb;
EXEC dbo.sp_grant_proxy_to_subsystem @proxy_name = N'MyPowerShellProxy'  
     , @subsystem_name = N'PowerShell'
Run Code Online (Sandbox Code Playgroud)

创建代理后,您需要配置 SQL Server 代理作业步骤以运行 PowerShell,它将自动使用 PowerShell 代理。

这是将运行您的代码的示例 SQL Server 代理作业:

USE [msdb]
GO
DECLARE @jobId binary(16);

EXEC  msdb.dbo.sp_add_job @job_name = N'ResetAppPool'
        , @enabled = 1
        , @notify_level_eventlog = 0
        , @notify_level_email = 2
        , @notify_level_page = 2
        , @delete_level = 0
        , @category_name = N'[Uncategorized (Local)]'
        , @owner_login_name = N'sa'
        , @job_id = @jobId OUTPUT;

EXEC msdb.dbo.sp_add_jobserver @job_name = N'ResetAppPool'
    , @server_name = N'(LOCAL)';

EXEC msdb.dbo.sp_add_jobstep @job_name = N'ResetAppPool'
    , @step_name = N'Step1'
    , @step_id = 1
    , @cmdexec_success_code = 0
    , @on_success_action = 1
    , @on_fail_action = 2
    , @retry_attempts = 0
    , @retry_interval = 0
    , @os_run_priority = 0
    , @subsystem = N'PowerShell'
    , @command = N'# Load IIS module:
Import-Module WebAdministration
# Set a name of the site we want to recycle the pool for:
$site = "Default Web Site"
# Get pool name by the site name:
$pool = (Get-Item "IIS:\Sites\$site"| Select-Object applicationPool).applicationPool
# Recycle the application pool:
Restart-WebAppPool $pool'
    , @database_name = N'master'
    , @flags = 0;

EXEC msdb.dbo.sp_update_job @job_name = N'ResetAppPool'
    , @enabled = 1
    , @start_step_id = 1
    , @notify_level_eventlog = 0
    , @notify_level_email = 2
    , @notify_level_page = 2
    , @delete_level = 0
    , @description = N''
    , @category_name = N'[Uncategorized (Local)]'
    , @owner_login_name = N'sa'
    , @notify_email_operator_name = N''
    , @notify_page_operator_name = N''
GO
Run Code Online (Sandbox Code Playgroud)

您可以修改作业以在它运行时向您发送电子邮件,以便您知道它有效。

关于您看到的此错误:

机器默认权限设置不会将具有 CLSID {longguidhere} 和 APPID {longguidhere} 的 COM 服务器应用程序的本地激活权限授予来自在应用程序容器中运行的地址 LocalHost (Using LRPC) 的用户 NT SERVICE\SQLSERVERAGENT SID (longguidhere)不可用 SID(不可用)。可以使用组件服务管理工具修改此安全权限。

这表明用户帐户控制正在管理员批准模式下运行,要求每个需要提升权限的操作都需要征得用户同意。由于 SQL Server 代理作为服务运行,提升提示没有机会运行,因此失败。您可以NT SERVICE\SQLSERVERAGENT通过控制面板中的组件服务小程序分配帐户权限以在提升模式下本地激活 PowerShell,而无需提示。

或者,您可以配置 Windows,使其永远不需要本地管理员组成员的提升。通过本地安全策略小程序执行此操作。设置以下设置:

  1. 打开Security Settings\Local Policies\Security Options文件夹。
  2. 将“用户帐户控制:内置管理员帐户的管理员批准模式”设置为“已禁用”
  3. 将“用户帐户控制:管理员批准模式下管理员提升提示的行为”设置为“不提示提升”
  4. 将“用户帐户控制:以管理员批准模式运行所有管理员”设置为“已禁用”


SEa*_*986 4

这是一个有点冗长的工作,但我设法做到了如下:

  • 在 Windows 任务计划程序中创建计划任务以运行回收应用程序池的 Powershell 脚本文件。确保其标记为“以最高权限运行”
  • 使用管理员凭据创建凭据
  • 创建代理账户并关联CMD子系统
  • 创建运行计划任务的 CMD 代理作业(确保作业步骤作为代理帐户运行)
  • 创建执行作业的启动过程。我必须添加一个 while 循环来检查代理是否正在运行,如果没有,则等待 5 秒,然后再次尝试启动作业