私はPowerShellにかなり慣れていないので、SQLエージェントでPowerShellタスクを実行したいdbatools.ioを見つけました。
$ExportPath = $env:TEMP + '\DriveSpace.csv'
$datatable = Import-Csv $ExportPath | Out-DbaDataTable
Write-DbaDataTable -SqlServer MyServer -Database Utils -InputObject $datatable -Table dbo.FreeSpaceOnDiskDrive -AutoCreateTable
開始しますが、neverは終了します。私はこれを実行しているタスクを持つことも試みました:
Get-DbaDatabaseSpace -SqlServer MyServer -IncludeSystemDBs | Out-DbaDataTable | Write-DbaDataTable -SqlServer MyServer -database utils -Table dbo.DiskSpaceExample -AutoCreateTable
同じ問題。 Windows PowerShell ISEでは問題なく動作しますが、SQLエージェントでハングするだけです。これで、新しいテーブルが作成され、データが入力されましたが、ジョブは実行を続けます。
発生している問題は、SQL ServerエージェントのPowerShellサブシステムにあります。 SQL Server PowerShellプロバイダー(SQLPS.exe)のコンテキストに置かれているため、他のモジュールを使用する場合とは少し異なります。したがって、sqlps.exe
を開いてコードを実行する場合と同じように機能します。
dbatools モジュールで留意すべきことの1つは、-それはがSQLPSとsqlserver
モジュールの両方と競合することです。最後に、競合している主なものを確認しましたが、モジュールに現在あるTEPPです。コードをロードできません。 [警告:私はこのモジュールの主要な貢献者です。]
Dbatoolsモジュールにはカスタムのタイプとスタイルが組み込まれているため、SQLPSまたはSQLServerモジュールもインポートされているPowerShellホストでスクリプトを実行すると、結果が異なります。
SQLエージェントステップでdbatoolsを利用するには、CmdExecサブシステム(ステップタイプ)のみを使用し、PowerShellホストを呼び出してコードを実行します。スクリプトごとにファイルを維持したくない場合は、以下の方法でコードをSQLエージェントのCmdExecステップに配置できますが、スクリプトが複雑な場合は、ファイルを介して維持する方が簡単です。
USE [msdb]
GO
/****** Object: Job [dbatools_example] Script Date: 2017-08-30 8:53:15 AM ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 2017-08-30 8:53:15 AM ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
END
DECLARE @jobId BINARY(16)
EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'dbatools_example',
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=N'No description available.',
@category_name=N'[Uncategorized (Local)]',
@owner_login_name=N'sa', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object: Step [dbatools_command] Script Date: 2017-08-30 8:53:15 AM ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'dbatools_command',
@step_id=1,
@cmdexec_success_code=0,
@on_success_action=1,
@on_success_step_id=0,
@on_fail_action=2,
@on_fail_step_id=0,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0, @subsystem=N'CmdExec',
@command=N'powershell.exe -ExecutionPolicy Bypass -Command "Import-Module dbatools; $server = ''manatarms''; Get-DbaDatabaseSpace -SqlInstance $server -IncludeSystemDbs | Out-DbaDataTable | Write-DbaDataTable -SqlInstance $server -Database db1 -Table dbo.FreeSpaceOnDiskDrive -AutoCreateTable"',
@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO
上記のジョブを実行すると、データベースとテーブルdb1.dbo.FreeSpaceOnDiskDrive
にこれが表示されます
SQLエージェントの動作を誤解している。 PowerShellは、インスタンスの外部の外部で実行されます。
これは、操作がfinishedとして報告されるか、障害エラーが発生するまで、Powershell操作が永続的に行われることを意味します。セッションを閉じようとすると、シェルを閉じるまで無期限にハングします。場合によっては、シェルが起動している適切なプロセスを正しく停止しないと、これが不可能になることさえあります。
たとえば、これを行わない場合、一時停止操作でpowershellを実行した場合、エージェントがpowershellを開いたコンソールにアクセスできないため、貧弱なシェルは無期限にハングします。
これはドキュメントで正しくサポートされているだけでなく、操作が完了した後に明確に閉じられます。すべての種類のステップを設定することもでき、ドキュメントも豊富です。
のみ、出口パスをハードコーディングします。呼び出し元に戻る操作に依存しないでください。あなたはそれがそうであることを確認します。
実際、これがコーディングの最大のルールです。明示的に保証されていない限り、コードが機能すると想定しないでください。
どのアプローチでも:DAC、ODBC、bcp、接続、 統合サービス(SSIS)接続
SSISはパッケージを使用しており、繰り返しの操作にも最適です。
もっと...