Lỗi chính sách thực thi khi chạy Powershell Script trong SQL Server Agent


7

Chạy tập lệnh powershell từ SQL Server Agent vào năm 2014 bằng tài khoản AD của tôi thông qua thông tin xác thực. Tôi nhận được lỗi sau.

Một bước công việc đã nhận được lỗi ở dòng 1 trong tập lệnh PowerShell. Dòng tương ứng là 'set-execpolicy RemoteSign -scope process -Force'. Sửa lỗi kịch bản và sắp xếp lại công việc. Thông tin lỗi được PowerShell trả về là: 'Lỗi bảo mật.

Các tìm kiếm của tôi trên Google, không tìm thấy bất cứ điều gì hữu ích. Tôi có thể chạy tập lệnh từ bảng điều khiển Powershell qua SSMS tại máy trạm của mình mà không gặp vấn đề gì.

Chính sách thực thi được đặt ở mức không giới hạn

PS C:\WINDOWS\system32> Get-ExecutionPolicy
Unrestricted

Dòng được đề cập trong đầu ra lỗi phải được SQL Server tự động thêm vào vì RemoteSigned -scope process -Forcekhông có chỗ nào trong mã.

Có bất cứ điều gì khác tôi cần để thiết lập trong SQL Server Agent, ngoài việc tôi sử dụng tài khoản AD để chạy công việc không?

Đây là hàng powershell từ msdb.dbo.syssubsystems

C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\SQLPS.exe

Cập nhật

Đây là phiên bản

PS SQLSERVER:\SQL\CD000023\CEF_2014_1> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
2      0      -1     -1

Cập nhật ngày 01/03/2015

Kịch bản lệnh này tạo một danh sách máy chủ bảng dựa trên các máy chủ đã đăng ký của máy chủ quản lý trung tâm. Sau đó, nó kết nối với từng máy chủ đó và xác định cổng mà nó đang nghe.

# connection parameters
 Param ( 
      [string] $CMSServer="someuser\someinstance",  # CMS server that stores serverlist
      [string] $CMSDatabase="msdb",                 # database where the serverlist is stored
      [string] $CMSUser="someuser",         # username to connect to the cms server
      [string] $CMSPassword="somepassword",     # password to connect with the cmsuser
      [string] $CMSTable="dbo.serverlist",          # name of table that stores instances
      [string] $CMSTableNoSchema="serverlist",      # name of table that stores instances
      [string] $UserName="remoteuser",              # username to connect to each instance
      [string] $Password="remotepassword",      # password to connect to each instance
      [string] $SrcDatabase="tempdb",               # database where listening ports are stored
      [string] $SrcTable="#listeningport"           # table where listening ports are stored


 )

 # load in the SQL Server Powershell Module
 [System.Reflection.Assembly]::LoadWithPartialName( `
  "Microsoft.SqlServer.Smo");


 # log file function
 $logfile = "c:\temp\get_server_ports_$(get-date -format `"yyyy_MM_ddtt`").txt"
 # initalize log file
 $logfile | out-file -Filepath $logfile 

  function log($string, $color)
{
   if ($Color -eq $null) {$color = "white"}
   write-host $string -foregroundcolor $color
   $string | out-file -Filepath $logfile -append
}

# CMS Server connection 
$CMSServerConnectionString = "Data Source=$CMSServer;Initial Catalog=$CMSDatabase;User Id=$CMSUser;PWD=$CMSPassword;"
$CMSServerConnection = new-object system.data.SqlClient.SqlConnection($CMSServerConnectionString);
$CMSServerConnection.Open() 

# create SMO objects so that tables can be created and dropped
$srv = new-Object Microsoft.SqlServer.Management.Smo.Server($CMSServerConnection)
$db = New-Object Microsoft.SqlServer.Management.Smo.Database
$db = $srv.Databases.Item($CMSDatabase)

# drop and recreate the serverlist Table on the CMS server
$tb = $db.Tables[$CMSTableNoSchema]
IF ($tb)
    {$tb.Drop()}

# Create the serverlist Table on the cms server
$tb = new-object Microsoft.SqlServer.Management.Smo.Table($db, $CMSTableNoSchema)
$col1 = new-object Microsoft.SqlServer.Management.Smo.Column($tb, "server_name", [Microsoft.SqlServer.Management.Smo.DataType]::NChar(255))
$col2 = new-object Microsoft.SqlServer.Management.Smo.Column($tb, "server_port", [Microsoft.SqlServer.Management.Smo.DataType]::Int)
$tb.Columns.Add($col1)
$tb.Columns.Add($col2)
$tb.Create()

# collect the list of servers
$cmd4 = new-object System.Data.SQLClient.SQLCommand
$cmd4.CommandText = "
    insert into msdb.dbo.serverlist (server_name, server_port)
    select server_name, 1 from msdb.dbo.sysmanagement_shared_registered_servers_internal
"
$cmd4.Connection = $CMSServerConnection
$rowsInserted = $cmd4.ExecuteNonQuery()


# Create a Dataset to hold the DataTable from server_list
$dataSet = new-object "System.Data.DataSet" "ServerListDataSet"
$query = "SET NOCOUNT ON;"
$query = $query + "SELECT server_name "
$query = $query + "FROM   $CMSDatabase.$CMSTable where server_name not in(
    select server_name from $CMSDatabase.dbo.excludeServerList 
  )"

# Create a DataAdapter which you'll use to populate the DataSet with the results
$dataAdapter = new-object "System.Data.SqlClient.SqlDataAdapter" ($query, $CMSServerConnection)
$dataAdapter.Fill($dataSet) | Out-Null

$dataTable = new-object "System.Data.DataTable" "ServerList"
$dataTable = $dataSet.Tables[0]


# for each server
$dataTable | FOREACH-OBJECT {
 Try 
    {   #write-host "server_name: " $_.server_name
        log "server_name : $ServerBConnectionString" yellow
        $ServerBConnectionString = "Data Source="+$_.server_name+";Initial Catalog=$SrcDatabase;User Id=$UserName;PWD=$Password" 
        #write-host "ServerBConnection: " $ServerBConnectionString
        $ServerBConnection = new-object system.data.SqlClient.SqlConnection($ServerBConnectionString);
        $ServerBConnection.Open()

        # create SMO objects so that tables can be created and dropped
        $srv = new-Object Microsoft.SqlServer.Management.Smo.Server($ServerBConnection)
        $db = New-Object Microsoft.SqlServer.Management.Smo.Database
        $db = $srv.Databases.Item($SrcDatabase)

        # collect port number from server
        $cmd3 = new-object System.Data.SQLClient.SQLCommand
        $cmd3.CommandText = "
            SELECT
            @@SERVERNAME as servername,
            cast(CONNECTIONPROPERTY('local_tcp_port') as int) AS port
            INTO $SrcTable
        "
        $cmd3.Connection = $ServerBConnection
        $rowsInserted = $cmd3.ExecuteNonQuery()


        # get port number from table
        $cmd2 = new-object System.Data.SQLClient.SQLCommand
        $cmd2.CommandText = "SELECT port FROM $SrcTable"
        $cmd2.Connection = $ServerBConnection
        $port = [Int32]$cmd2.ExecuteScalar()

        #write-host "port: " $port
        log "port:  $port" yellow

        # update cms table
          $cmd = new-object System.Data.SQLClient.SQLCommand
          $cmd.CommandText = "UPDATE $CMSDatabase.$CMSTable SET server_port = $port WHERE server_name = '"+$_.server_name+"'"
          #write-host "success: " $cmd.CommandText
          $cmd.Connection = $CMSServerConnection
          $rowsUpdated = $cmd.ExecuteNonQuery()

        log "success:  $_.server_name" green        
        #write-host "success: " $_.server_name
        $ServerBConnection.Close()

    } Catch [System.Exception] 
  { 
    $ex = $_.Exception 
    #write-host "failure: " $ex.Message " on server " $_.server_name
    log "failure: $ex.Message on server $_.server_name" red 
    #Write-Host $ex.Message 
  } 
  Finally 
  { 
    #write-host "server_name: " $_.server_name
  } 


}

$CMSServerConnection.Close()

Câu trả lời:


3

Lỗi bạn đang nhận thực sự được ghi nhận trong một mục kết nối nhưng Microsoft hiển thị nó là closed won't fix. Điều bị bỏ lỡ trong mục kết nối này là thực tế là hệ thống con SQLPSđược đặt thông qua khóa đăng ký. Khi nào và những gì thực sự thiết lập điều này tôi không biết.

Khóa đăng ký này được tìm thấy ở đường dẫn bên dưới và trên hộp cục bộ của tôi được đặt thành RemoteSigned. Bây giờ tôi thường không khuyên thay đổi khoá đăng ký nhưng bạn có thể thử thay đổi mã này thành RemoteSignedvà bạn có thể thấy các tập lệnh của mình sẽ chạy mà không gặp lỗi. Nó có thể yêu cầu khởi động lại dịch vụ SQL Agent, không biết.

nhập mô tả hình ảnh ở đây HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.SqlServer.Management.PowerShell.sqlps120

Giờ đây, với việc sử dụng, Unrestrictedbạn thực sự có thể khiến các tập lệnh nhận được lời nhắc khi thực thi tập lệnh PowerShell. Đây có thể là những gì thực sự tạo ra lỗi vì Tác nhân SQL không thể phản hồi lời nhắc hoặc không biết cách xử lý. Thực sự không có lý do để sử dụng cài đặt chính sách đó vì đây RemoteSignedlà một chính sách đủ để cho phép các tập lệnh bạn đã viết và thiết lập trên máy chủ thực thi mà không được nhắc.

Tôi sẽ ngoại trừ nếu bạn nhận được toàn bộ lỗi được trả về, nó có thể chứa văn bản tương tự như thông báo dưới đây. Đây là lời nhắc bạn có thể nhận được khi đặt chính sách thực thi thành Unrestricted:

Cảnh báo an ninh

Chỉ chạy các tập lệnh mà bạn tin tưởng. Mặc dù các tập lệnh từ Internet có thể hữu ích, tập lệnh này có khả năng gây hại cho máy tính của bạn. Bạn có muốn chạy

[D] Không chạy [R] Chạy một lần [S] Tạm dừng [?] Trợ giúp (mặc định là "D"):


Xin chào Shawn, cảm ơn câu trả lời. Chạy tập lệnh thông qua Trình lập lịch tác vụ thực thi mà không gặp lỗi. Kịch bản lệnh thực thi các lệnh SQL trên các máy chủ ở xa khác, vì vậy có lẽ tôi đang gặp vấn đề về quyền trên các máy khác? Không có ý tưởng, nhưng tôi đã tìm thấy một giải pháp.
Craig Efrein

1
Không ai có thể trả lời câu hỏi đó vì bạn không cung cấp tập lệnh của mình hoặc nó đang làm gì.

Xin chào Shawn, tôi đã thêm vào kịch bản cho câu hỏi của mình.
Craig Efrein

1

Tôi cũng đã gặp phải vấn đề này với công việc máy chủ sql tích hợp syspolicy_purge_history Vấn đề là với SQLPS trong SQL Server 2012 và có vẻ như vậy. Tôi đã tìm thấy 2008 R2 không gặp phải vấn đề tương tự.
SQL Server 2012 SQLPS được bảo mật hơn bằng cách thêm vào một cài đặt rõ ràng của chính sách thực thi quy trình để SQLPS được từ xa. Vấn đề là, phạm vi chính sách thực thi cho Powershell là một hệ thống phân cấp & thực hiện một set-ExecutionPolicychính sách hạn chế hơn ở phạm vi thấp hơn (ví dụ quy trình) sẽ gây ra lỗi như sau: nhập mô tả hình ảnh ở đây

vì vậy các lựa chọn của bạn là:

  • Tạo chính sách thực thi SQLPS được tìm thấy trong sổ đăng ký tại HKLM: SOFTWARE \ Microsoft \ PowerShell \ 1 \ ShellIds \ Microsoft.SqlServer.Man Quản lý.PowerShell.sqlps110 \ ExecutPolicy khớp với LocalMachine hoặc nếu GPO được cấu hình giống như MachinePolicy.
  • Đặt chính sách LocalMachine của bạn thành Bypass, trong trường hợp đó, lỗi ở trên sẽ biến mất.

Đối với tôi, việc thay đổi sổ đăng ký trước đây dễ dàng hơn là gặp rắc rối trong việc thuyết phục quản trị viên tên miền thiết lập một chính sách máy khác chỉ dành cho máy chủ của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.