ジョブは、SQL Server 2005 Service Pack 1 をインストールした後、トークンを使用するジョブ ステップが含まれている場合、SQL Server エージェントのジョブが失敗します。

文書翻訳 文書翻訳
文書番号: 915845
# をバグ: 426808 (SQLBUDT)
すべて展開する | すべて折りたたむ

現象

Microsoft SQL Server 2005 Service Pack 1 (SP1) をインストールした後、次の現象が発生します。
  • SQL Server エージェントのジョブが失敗するは、トークンを使用するジョブ ステップのジョブが含まれる場合。
  • 次のエラー メッセージが表示されます。
    ジョブ ステップには、1 つまたは複数のトークンが含まれます。ジョブを実行する前に SQL Server 2005 Service Pack 1 またはそれ以降のバージョンでは、すべてのジョブ ステップでトークンをマクロを更新しなければなりません。
メモ この問題はビルド 2046年や最新のバージョンの SQL Server 2005 で発生します。

原因

SQL Server 2005 SP1 では、SQL Server エージェントのジョブ ステップ トークン構文が変更されました。ここで、ジョブ ステップで、エスケープ マクロを使用するすべてのトークンを使用する場合があります。エスケープ マクロが含まれていない場合は、これらのジョブ ステップは失敗します。エスケープ マクロの例を次に示します。
元に戻す全体を表示する
エスケープ マクロ説明
$ (ESCAPE_SQUOTE (TokenName))このマクロは、トークンの置換文字列にアポストロフィ (') をエスケープします。マクロ 1 つの単一引用符 2 つのアポストロフィで置き換えます。
$ (ESCAPE_DQUOTE (TokenName))このマクロは、トークンの置換後の文字列に引用符 (') をエスケープします。マクロ 1 つの二重引用符に二重引用符を 2 つに置き換わります。
$ (ESCAPE_RBRACKET (TokenName))このマクロは、トークンの置換文字列の右角かっこ (]) をエスケープします。マクロ 1 つの右角かっこが 2 つの右角かっこで置き換えられます。
$ (ESCAPE_NONE (TokenName))マクロに文字列内の文字をエスケープせずにトークンを置き換えます。このマクロは、トークンの置換後の文字列を信頼されるユーザーのみ予想される環境との下位互換性をサポートするために用意されています。
たとえば、ジョブ ステップには使用して次の Transact SQL 文が含まれて可能性があります、 A-DBN トークン:
CREATE DATABASE [$(A-DBN)]
この例では、トークンの構文は、次の構文に更新する必要があります。
CREATE DATABASE [$(ESCAPE_RBRACKET(A-DBN))]
この変更は、エスケープ マクロを必要がない、以前の SQL Server 2005 動作から異なります。

解決方法

この問題を解決するには、すべての更新または新しいトークン構文にトークンを使用して特定ジョブだけ。これを行うを使用して、 sp_AddEscapeNoneToJobStepTokens ストアド プロシージャです。以下の Transact SQL スクリプトを使用して、このストアド プロシージャを作成できます。

メモ インストールする SQL Server 2005 SP1 ビルドがビルド 2046年またはそれ以降のビルドであるかどうかを確認します。さらに、スクリプトを実行するのには、sysadmin 固定サーバー ロールのメンバーをでする必要があります。
      -- This script is used to automatically edit SQL Agent job steps so that
-- unescaped tokens are prefaced with the ESCAPE_NONE syntax that was added in
-- SQL Server 2005 SP1.

if (@@microsoftversion < 0x90007FE)
BEGIN
    RAISERROR('This script should only be run on at least SQL Server 2005 SP1.', 20, 127) WITH LOG
    return
END

use msdb
go

if exists (select * from sys.objects where name = N'fn_PrefaceTokensWithEscapeNone' and type = 'FN')
    drop function fn_PrefaceTokensWithEscapeNone
go

-- This function manipulates @commands so that all bare tokens
-- are prefaced with ESCAPE_NONE.
create function fn_PrefaceTokensWithEscapeNone(@commands nvarchar(max)) RETURNS nvarchar(max)
AS
BEGIN
    if (@commands IS NULL)
    BEGIN
        return @commands
    END

    -- In order to let this script run under SQLCMD mode, we define
    -- the special "$(" variable start string by concatenation so that
    -- sqlcmd mode does not think that we are defining one of its variables.
    declare @strVariableStart nchar(2)
    select @strVariableStart = N'$' + N'('

    declare @idxTokenStart int
    select @idxTokenStart = CHARINDEX(@strVariableStart, @commands)
    while (@idxTokenStart != 0 and @idxTokenStart is not null)
    BEGIN
        declare @idxCloseParen int
        select @idxCloseParen = CHARINDEX(N')', SUBSTRING(@commands, @idxTokenStart, LEN(@commands)))
        -- Error checking. If there is no close parenthesis, return.
        if (0 = @idxCloseParen)
        BEGIN
            return @commands
        END

        -- Deduce the token variable.
        declare @tokenLen int
        select @tokenLen = @idxCloseParen - LEN(@strVariableStart) - 1
        declare @token nvarchar(max)
        select @token = SUBSTRING(@commands, @idxTokenStart + LEN(@strVariableStart), @tokenLen)

        -- Verify if @token contains a mis-matched number of open and
        -- close parens. This behavior could happen if invalid syntax is
        -- in a comment block. If so, skip to the next token.
        declare @idx int
        declare @cOpenParens int
        declare @cCloseParens int

        select @cOpenParens = 0
        select @idx = CHARINDEX(N'(', @token);
        while (@idx != 0)
        BEGIN
            select @cOpenParens = @cOpenParens + 1
            select @idx = CHARINDEX(N'(', @token, @idx + 1);
        END

        select @cCloseParens = 0
        select @idx = CHARINDEX(N')', @token);
        while (@idx != 0)
        BEGIN
            select @cCloseParens = @cCloseParens + 1
            select @idx = CHARINDEX(N')', @token, @idx + 1);
        END

        -- Special case for the WMI token.
        if (N'WMI(' = SUBSTRING(@token, 1, LEN(N'WMI(')))
        BEGIN
                select @cOpenParens = @cOpenParens - 1
        END

        if ((@cOpenParens = @cCloseParens) and
            (N'ESCAPE_NONE(' != SUBSTRING(@token, 1, LEN(N'ESCAPE_NONE('))) and
            (N'ESCAPE_SQUOTE(' != SUBSTRING(@token, 1, LEN(N'ESCAPE_SQUOTE('))) and
            (N'ESCAPE_DQUOTE(' != SUBSTRING(@token, 1, LEN(N'ESCAPE_DQUOTE('))) and
            (N'ESCAPE_RBRACKET(' != SUBSTRING(@token, 1, LEN(N'ESCAPE_RBRACKET('))))
        BEGIN
            select @commands = STUFF(@commands, @idxTokenStart + LEN(@strVariableStart), @tokenLen, N'ESCAPE_NONE(' + @token + N')')
        END
        select @idxTokenStart = CHARINDEX(@strVariableStart, @commands, @idxTokenStart + 1)
    END

    return @commands

END
go

if exists (select * from sys.objects where name = N'sp_AddEscapeNoneToJobStepTokens' and type = 'P')
    drop procedure sp_AddEscapeNoneToJobStepTokens
go

-- This procedure allows you to update jobs so that bare tokens
-- are prefaced with ESCAPE_NONE. By default, all jobs are updated.
-- You can optionally specify @job_name, @job_id, or @owner_name
-- to limit the jobs that will be affected.
CREATE PROCEDURE sp_AddEscapeNoneToJobStepTokens
(
    @job_name nvarchar(128) = null,
    @job_id uniqueidentifier = null,
    @owner_name nvarchar(256) = null
)
AS


  -- Find the jobs to update. These jobs must match all of the input
  -- criteria, unless all of the inputs are null. In this case, 
  -- examine all jobs.  The jobs must also be jobs created locally,
  -- such as sysjobs.originating_server_id = 0. These jobs should not be a job that we run
  -- because another server told us to.  Furthermore, if the job
  -- is local but it is meant to be run on a target server, we send an
  -- update for the job.
  declare @jobsToUpdate TABLE (job_id uniqueidentifier not null)
  
  insert into @jobsToUpdate
      select job_id
      from sysjobs
      where originating_server_id = 0 -- local jobs
      and ((COALESCE(@job_name, sysjobs.name) = sysjobs.name) and
           (COALESCE(@job_id, sysjobs.job_id) = sysjobs.job_id) and
           (COALESCE(@owner_name, suser_sname(sysjobs.owner_sid)) = suser_sname(sysjobs.owner_sid)))
  
  -- Now find the job steps to update, creating the new command by using
  -- fn_PrefaceTokensWithEscapeNone.
  declare @jobStepsToUpdate TABLE (job_id uniqueidentifier not null, 
                                   step_id int not null, 
                                   command_old nvarchar(max) null, 
                                   command_new nvarchar(max) null,
                                   output_file_old nvarchar(max) null, 
                                   output_file_new nvarchar(max) null)
  
  insert into @jobStepsToUpdate
  (job_id, step_id, command_old, command_new, output_file_old, output_file_new)
      select job_id, step_id, command, dbo.fn_PrefaceTokensWithEscapeNone(command), output_file_name, dbo.fn_PrefaceTokensWithEscapeNone(output_file_name)
      from sysjobsteps
      where sysjobsteps.job_id = 
      (select job_id 
       from @jobsToUpdate 
       where job_id = sysjobsteps.job_id)
  
  -- Now we update the actual job step commands. We do this first before
  -- we push out the updated jobs to the target servers so the
  -- target servers actually get the updated version.
  declare @updated_job_id uniqueidentifier
  declare @updated_job_step_id int
  declare @updated_job_step_command nvarchar(max)
  declare @updated_job_step_output_file nvarchar(max)
  
  declare job_steps_cursor CURSOR FOR
      select job_id, step_id, command_new, output_file_new
      from @jobStepsToUpdate
      order by job_id, step_id
  
  OPEN job_steps_cursor
  FETCH NEXT from job_steps_cursor into @updated_job_id, @updated_job_step_id, @updated_job_step_command, @updated_job_step_output_file
  WHILE (@@FETCH_STATUS <> -1)
  BEGIN
      IF (@@FETCH_STATUS <> -2)
      BEGIN
          EXEC sp_update_jobstep @job_id = @updated_job_id, @step_id = @updated_job_step_id, @command = @updated_job_step_command, @output_file_name = @updated_job_step_output_file
      END
      FETCH NEXT from job_steps_cursor into @updated_job_id, @updated_job_step_id, @updated_job_step_command, @updated_job_step_output_file
  END
  
  CLOSE job_steps_cursor
  DEALLOCATE job_steps_cursor
  
  
  -- For multiserver jobs, call the sp_post_msx_operation stored procedure to update
  -- all the target servers. Note that the sp_post_msx_operation stored procedure is safe
  -- to call because it verifies whether the job is really a multiserver job.
  declare jobs_cursor CURSOR FOR
      select job_id
      from @jobsToUpdate
  
  OPEN jobs_cursor
  FETCH NEXT from jobs_cursor into @updated_job_id
  WHILE (@@FETCH_STATUS <> -1)
  BEGIN
      IF (@@FETCH_STATUS <> -2)
      BEGIN
          EXEC sp_post_msx_operation @operation = 'UPDATE', @job_id = @updated_job_id
      END
      FETCH NEXT from jobs_cursor into @updated_job_id
  END
  
  CLOSE jobs_cursor
  DEALLOCATE jobs_cursor

  -- List the jobs that we ran on, including the previous command
  -- text. We list all of the job steps, even the ones that we did not
  -- update. Otherwise, a jumble of job steps from
  -- different jobs run together and the output is not
  -- useful.
  select N'Warning - Jobs Updated' = N'The following job steps and job output file names were analyzed and potentially updated to add the ESCAPE_NONE macro before any job tokens that were not already escaped. Please review the modified job steps and replace ESCAPE_NONE with the correct escape macro.'
  
  select suser_sname(jobs.owner_sid) as N'Job owner', 
         jobs.name as N'Job name', 
         jobs.job_id, 
         jobStepsUpdated.step_id, 
         N'Modified' = CASE WHEN jobStepsUpdated.command_new != jobStepsUpdated.command_old or jobStepsUpdated.output_file_new != jobStepsUpdated.output_file_old THEN 1 ELSE 0 END,
         N'Command' = jobStepsUpdated.command_new, 
         N'Previous Command' = jobStepsUpdated.command_old, 
         N'Output file' = jobStepsUpdated.output_file_new, 
         N'Previous Output file' = jobStepsUpdated.output_file_old
      from sysjobs as jobs, @jobsToUpdate as jobsUpdated, @jobStepsToUpdate as jobStepsUpdated
      where jobsUpdated.job_id = jobs.job_id and jobsUpdated.job_id = jobStepsUpdated.job_id
      order by 'Job name', jobStepsUpdated.step_id
go

このスクリプトを実行した後、 sp_AddEscapeNoneToJobStepTokens ストアド プロシージャが作成されます。既定では、このストアド プロシージャはパラメーターを指定せずに実行するとすべてのジョブが更新されます。特定のジョブのみを更新する場合は、null 以外の値は、次の 3 つのパラメーターの少なくとも 1 つ指定してください。
  • @ ジョブ
  • @job_id
  • @ 所有者
たとえば、次の構文を使用する可能性があります。
  • すべてのジョブを更新します。
    EXEC sp_AddEscapeNoneToJobStepTokens
  • ジョブは、ジョブ名を指定して更新します。
    EXEC sp_AddEscapeNoneToJobStepTokens 'MyJob'
  • 同じ所有者に所有されているジョブを更新します。
    EXEC sp_AddEscapeNoneToJobStepTokens null,null,'JobOwner'
このスクリプトを追加、 ESCAPE_NONE マクロは、トークンが含まれているすべてのジョブ ステップに。このスクリプトを実行した後、できるだけ早くトークンを使用して、ジョブ ステップを確認することをお勧めします。その後、交換、 ESCAPE_NONE ジョブ ステップのコンテキストに適した他のエスケープ マクロのマクロです。

メモ マスター サーバー (MSX) および対象サーバー (TSX) 環境で作業している場合は、これを実行する必要がありますスクリプトは MSX および TSX、TSX 上のマスターのジョブが正しく更新されているかどうかを確認します。

新しい構文を使用してジョブを更新する方法、およびエスケープ マクロを使用して、SQL Server エージェントのジョブ ステップでのトークンの交換を有効にする方法の詳細については、SQL Server 2005 Books Online (2006 年 4 月) またはそれ以降のバージョンの SQL Server 2005 Books Online の「を使用してトークン ジョブ ステップ」トピックを参照してください。

状況

マイクロソフトでは、この「対象」に記載されているマイクロソフト製品の問題として認識しています。

関連情報

ジョブ ステップでトークンを使用する方法の詳細については、次のマイクロソフト開発ネットワーク (MSDN) Web サイトを参照してください。
http://msdn2.microsoft.com/en-us/library/ms175575.aspx

プロパティ

文書番号: 915845 - 最終更新日: 2011年8月4日 - リビジョン: 6.0
キーワード:?
kbtshoot kbprb kbexpertiseadvanced kbsql2005presp1fix kbmt KB915845 KbMtja
機械翻訳の免責
重要: このサポート技術情報 (以下「KB」) は、翻訳者による翻訳の代わりに、マイクロソフト機械翻訳システムによって翻訳されたものです。マイクロソフトは、お客様に、マイクロソフトが提供している全ての KB を日本語でご利用いただけるように、翻訳者による翻訳 KB に加え機械翻訳 KB も提供しています。しかしながら、機械翻訳の品質は翻訳者による翻訳ほど十分ではありません。誤訳や、文法、言葉使い、その他、たとえば日本語を母国語としない方が日本語を話すときに間違えるようなミスを含んでいる可能性があります。マイクロソフトは、機械翻訳の品質、及び KB の内容の誤訳やお客様が KB を利用されたことによって生じた直接または間接的な問題や損害については、いかなる責任も負わないものとします。マイクロソフトは、機械翻訳システムの改善を継続的に行っています。
英語版 KB:915845
Microsoft Knowledge Base の免責: Microsoft Knowledge Baseに含まれている情報は、いかなる保証もない現状ベースで提供されるものです。Microsoft Corporation及びその関連会社は、市場性および特定の目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。さらに、Microsoft Corporation及びその関連会社は、本文書に含まれている情報の使用及び使用結果につき、正確性、真実性等、いかなる表明・保証も行ないません。Microsoft Corporation、その関連会社及びこれらの権限ある代理人による口頭または書面による一切の情報提供またはアドバイスは、保証を意味するものではなく、かつ上記免責条項の範囲を狭めるものではありません。Microsoft Corporation、その関連会社 及びこれらの者の供給者は、直接的、間接的、偶発的、結果的損害、逸失利益、懲罰的損害、または特別損害を含む全ての損害に対して、状況のいかんを問わず一切責任を負いません。(Microsoft Corporation、その関連会社 またはこれらの者の供給者がかかる損害の発生可能性を了知している場合を含みます。) 結果的損害または偶発的損害に対する責任の免除または制限を認めていない地域においては、上記制限が適用されない場合があります。なお、本文書においては、文書の体裁上の都合により製品名の表記において商標登録表示、その他の商標表示を省略している場合がありますので、予めご了解ください。

フィードバック

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com