Ausführungsrichtlinienfehler beim Ausführen des Powershell-Skripts im SQL Server-Agenten

7

Ausführen eines Powershell-Skripts vom SQL Server-Agenten im Jahr 2014 mithilfe meines AD-Kontos über einen Berechtigungsnachweis. Ich erhalte den folgenden Fehler.

Ein Jobschritt hat in Zeile 1 eines PowerShell-Skripts einen Fehler erhalten. Die entsprechende Zeile lautet 'set-executepolicy RemoteSigned -scope process -Force'. Korrigieren Sie das Skript und planen Sie den Job neu. Die von PowerShell zurückgegebenen Fehlerinformationen lauten: 'Sicherheitsfehler.

Meine Suchanfragen bei Google haben nichts Nützliches ergeben. Ich kann das Skript problemlos über SSMS auf meiner Workstation über die Powershell-Konsole ausführen.

Die Ausführungsrichtlinie ist auf uneingeschränkt festgelegt

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

Die in der Fehlerausgabe erwähnte Zeile muss automatisch von SQL Server hinzugefügt werden, da sie RemoteSigned -scope process -Forcesich nirgendwo im Code befindet.

Gibt es noch etwas, das ich in SQL Server Agent festlegen muss, außer dass ich AD-Konto zum Ausführen des Jobs verwende?

Hier ist die Powershell-Reihe von msdb.dbo.syssubsystems

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

Aktualisieren

Hier ist die Version

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

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

Update 01/03/2015

Dieses Skript erstellt eine Tabellenserverliste basierend auf den registrierten Servern eines zentralen Verwaltungsservers. Es stellt dann eine Verbindung zu jedem dieser Server her und identifiziert den Port, den es abhört.

# 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()
Craig Efrein
quelle

Antworten:

3

Der Fehler, den Sie erhalten, wurde tatsächlich in einem Verbindungselement vermerkt , aber Microsoft zeigt ihn als an closed won't fix. Was in diesem Verbindungselement fehlt, ist die Tatsache, dass das Subsystem für SQLPSüber einen Registrierungsschlüssel festgelegt wird. Wann und was dies tatsächlich einstellt, weiß ich nicht.

Dieser Registrierungsschlüssel befindet sich im Pfad unten und ist auf meiner lokalen Box auf eingestellt RemoteSigned. Jetzt empfehle ich im Allgemeinen nicht, Registrierungsschlüssel zu ändern, aber Sie können versuchen, dies zu ändern, RemoteSignedund Sie werden wahrscheinlich feststellen, dass Ihre Skripte ohne Fehler ausgeführt werden. Möglicherweise muss der SQL Agent-Dienst neu gestartet werden.

Geben Sie hier die Bildbeschreibung ein HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.SqlServer.Management.PowerShell.sqlps120

Mit der Verwendung können UnrestrictedSie jetzt dazu führen, dass Skripts beim Ausführen des PowerShell-Skripts eine Eingabeaufforderung erhalten. Dies kann der eigentliche Fehler sein, da SQL Agent nicht auf die Eingabeaufforderung reagieren kann oder nicht weiß, wie er damit umgehen soll. Es gibt wirklich keinen Grund, diese Richtlinieneinstellung zu verwenden, da dies RemoteSignedeine ausreichende Richtlinie ist, damit Skripte, die Sie auf dem Server geschrieben und eingerichtet haben, ohne Aufforderung ausgeführt werden können.

Ich würde außer wenn Sie sich mit dem vollständigen Fehler befasst haben, der zurückgegeben wird, könnte er Text ähnlich der folgenden Nachricht enthalten. Dies ist die Eingabeaufforderung, die Sie erhalten können, wenn Sie die Ausführungsrichtlinie auf Folgendes setzen Unrestricted:

Sicherheitswarnung

Führen Sie nur Skripte aus, denen Sie vertrauen. Während Skripte aus dem Internet nützlich sein können, kann dieses Skript möglicherweise Ihren Computer beschädigen. Willst du Rennen

[D] Nicht ausführen [R] Einmal ausführen [S] Suspend [?] Help (Standard ist "D"):


quelle
Hallo Shawn, danke für die Antwort. Das Ausführen des Skripts über den Taskplaner wird fehlerfrei ausgeführt. Das Skript führt SQL-Befehle auf anderen entfernten Servern aus. Vielleicht treten auf diesen anderen Computern Berechtigungsprobleme auf? Keine Ahnung, aber ich habe eine Lösung gefunden.
Craig Efrein
1
Niemand kann diese Frage beantworten, da Sie Ihr Skript nicht angegeben haben oder nicht wissen, was es tut.
Hallo Shawn, ich habe das Skript zu meiner Frage hinzugefügt.
Craig Efrein
1

Ich habe dieses Problem auch speziell mit dem integrierten SQL Server-Job syspolicy_purge_history erlitten. Das Problem ist anscheinend mit SQLPS in SQL Server 2012 und höher. Ich habe festgestellt, dass 2008 R2 nicht das gleiche Problem hat.
SQL Server 2012 SQLPS wurde sicherer gemacht, indem eine explizite Einstellung der Prozessausführungsrichtlinie für SQLPS hinzugefügt wurde, die entfernt werden soll. Das Problem ist, dass der Ausführungsrichtlinienbereich für Powershell eine Hierarchie ist und das Ausführen einer set-ExecutionPolicymit einer restriktiveren Richtlinie in einem niedrigeren Bereich (z. B. Prozess) einen Fehler wie den folgenden auslöst: Geben Sie hier die Bildbeschreibung ein

Ihre Optionen sind also:

  • Stellen Sie sicher, dass die SQLPS-Ausführungsrichtlinie in der Registrierung unter HKLM: SOFTWARE \ Microsoft \ PowerShell \ 1 \ ShellIds \ Microsoft.SqlServer.Management.PowerShell.sqlps110 \ ExecutionPolicy mit der LocalMachine übereinstimmt oder wenn ein Gruppenrichtlinienobjekt mit der MachinePolicy konfiguriert ist.
  • Stellen Sie Ihre LocalMachine-Richtlinie auf Bypass ein. In diesem Fall wird der obige Fehler behoben.

Für mich ist die frühere Registrierungsänderung einfacher, als den Domänenadministrator davon zu überzeugen, eine andere Computerrichtlinie nur für meine Server einzurichten.

Nick Kavadias
quelle