認証情報を介して私のADアカウントを使用して2014年にSQL ServerエージェントからPowerShellスクリプトを実行します。次のエラーが発生します。
ジョブステップは、PowerShellスクリプトの1行目でエラーを受け取りました。対応する行は「set-executionpolicy RemoteSigned -scope process -Force」です。スクリプトを修正し、ジョブを再スケジュールしてください。 PowerShellによって返されるエラー情報は次のとおりです: 'セキュリティエラー。
グーグルでの私の検索では、何も役に立たなかった。ワークステーションでSSMSを介してPowershellコンソールから問題なくスクリプトを実行できます。
実行ポリシーが無制限に設定されています
_PS C:\WINDOWS\system32> Get-ExecutionPolicy
Unrestricted
_
_RemoteSigned -scope process -Force
_はコードのどこにもないため、エラー出力で言及されている行はSQL Serverによって自動的に追加される必要があります。
ジョブを実行するためにADアカウントを使用する以外に、SQL Serverエージェントで設定する必要があるものはありますか?
これが_msdb.dbo.syssubsystems
_のPowerShell行です
C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\SQLPS.exe
更新
こちらがバージョンです
_PS SQLSERVER:\SQL\CD000023\CEF_2014_1> $PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
2 0 -1 -1
_
2015年1月3日更新
このスクリプトは、中央管理サーバーの登録済みサーバーに基づいて、サーバーリストを作成します。次に、それらの各サーバーに接続し、リッスンしているポートを識別します。
_# 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()
_
受け取ったエラーは実際には connect item で示されていましたが、Microsoftはclosed won't fix
と表示しています。この接続項目で見逃されているのは、SQLPS
のサブシステムがレジストリキーを介して設定されているという事実です。いつ、実際にこれを設定するのかはわかりません。
このレジストリキーは以下のパスにあり、ローカルボックスではRemoteSigned
に設定されています。レジストリキーを変更することはお勧めしませんが、これをRemoteSigned
に変更すると、スクリプトがエラーなしで実行される可能性があります。 SQLエージェントサービスの再起動が必要になる場合がありますが、わかりません。
HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.SqlServer.Management.PowerShell.sqlps120
これで、Unrestricted
を使用して、PowerShellスクリプトの実行時にスクリプトにプロンプトを表示させることができます。 SQLエージェントがプロンプトに応答できないか、プロンプトの処理方法がわからないため、これが実際にエラーを生成している可能性があります。 RemoteSigned
は、プロンプトが表示されずにサーバー上で作成および設定したスクリプトを実行できるようにするための十分なポリシーであるため、このポリシー設定を使用する理由は本当にありません。
返された完全なエラーを掘り下げた場合は、以下のメッセージに類似したテキストが含まれている可能性があります。これは、実行ポリシーをUnrestricted
に設定したときに受け取るプロンプトです。
セキュリティ警告
信頼できるスクリプトのみを実行してください。インターネットからのスクリプトは有用ですが、このスクリプトはコンピュータに害を及ぼす可能性があります。走りたいですか
[D]実行しない[R] 1回実行[S]一時停止[?]ヘルプ(デフォルトは "D"):
特に組み込みSQLサーバージョブsyspolicy_purge_historyでもこの問題に苦しんでいます。SQLServer 2012以降のSQLPSで問題が発生しているようです。 2008 R2でも同じ問題は発生しません。
SQLPS 2012のSQLPSは、リモート署名されるSQLPSのプロセス実行ポリシーの明示的な設定を追加することでさらに安全になりました。問題は、Powershellの実行ポリシーのスコープが階層であり、set-ExecutionPolicy
より低いスコープ(プロセスなど)でより制限的なポリシーを使用すると、次のようなエラーが発生します。
だからあなたのオプションは:
私にとって、以前のレジストリ変更は、ドメイン管理者に自分のサーバーだけに別のマシンポリシーを設定するように説得するよりも簡単です。