web-dev-qa-db-ja.com

XP_CMDSHELLから結果を取得する

私はいくつかのWebを検索してきましたが、XP_CMDSHELLから結果を取得する唯一の方法はそれらを一時テーブルに格納することです。本当に簡単な方法はありませんか?

Experts Exchangeから:

いいえ、xp_cmdshellはexeから情報を返しません。実行するためにmasterデータベースにいない場合は、次の構文を使用する必要があります。 master..xp_cmdshell。 masterデータベースでこのプロシージャを実行するためのアクセス許可をユーザーに与える必要があります。それはそれを呼び出したプロセスに情報を返すことができないので、あなたはあなたのexeに情報をそれ自身に挿入させる必要があります。

そして...

@resultはxp_cmdshellからの戻り値のみを取得しますが、テーブルに直接挿入することでコマンドの結果をキャプチャできる場合があります...次のようなもの:

ymmv ...

set nocount on
declare  @filepath   varchar(255),
         @cmd        varchar(255),
         @rc         int

select   @filepath = 'c:\temp\'         
select   @cmd      = 'dir ' + @filepath + '~*.tmp'

create table #output (output varchar(255) null)
insert #output exec @rc = master..xp_cmdshell @cmd
select * from #output where output is not null
drop table #output
15
Saint Ronin

xp_cmdshellからSTDOUT/STDERRフィードバックを取得する簡単な方法はありません。少なくとも1つの代替案がありますが、これほど簡単には分類できません。
コマンドの出力をコマンドの一部としてテキストファイルにリダイレクトし、OPENROWSETを使用してテキストファイルを読み取ることができます。

ところで、上記のスクリプトに少なくとも1つのエラーがあります。 xp_cmdshell のドキュメントには、コマンド出力をnvarchar(255)として返すことが記載されています。
また、一時テーブルにはID列が必要です。それ以外の場合、結果が正しい順序で表示されないことがあります。

...
create table #output (id int identity(1,1), output nvarchar(255) null)
insert #output (output) exec @rc = master..xp_cmdshell @cmd
select * from #output where output is not null order by id
drop table #output
20
Ed Harper

これが私がやったことです...私は今日チェックして、あなたの反応を見ました。私は昨日リアルタイムで緊張していたので、確認済みの作業ソリューションであったため、一時テーブルの方向で作業を開始しました。クリップボードとして使用しているだけなので、内部で物事を処理するのと同じくらい簡単に、または簡単に思えたため、一時ファイルを作成しないようにしました。必要に応じて行う1つの変更は、一時テーブル名に一意の番号を追加することです。ただし、これらが同時に処理されることを心配する必要はないと思います(つまり、ストアドプロシージャの2回目の呼び出しで一時テーブルがダンプされる可能性があります) cmdシェルが実行されています)。わかります...

ストアドプロシージャを呼び出し(さらに下を見て)、パスワードを暗号化します。以下のコードは、それで十分なものになるように変更されています。これは基本的にパスワードオフロード/同期ソリューションであるため、実際には手動でパスワードを設定していません。

DECLARE @password       VARCHAR(64)
DECLARE @encryptedpass  VARCHAR(128);

SET @password = '1234'

BEGIN TRY
    EXEC pass_encrypt @password, @encryptedpass = @encryptedpass OUTPUT
END TRY
BEGIN CATCH
    PRINT 'ERROR'
    RETURN
END CATCH
SELECT @encryptedpass

暗号化ストアドプロシージャを次に示します。戻りコードが失敗を示す理由を推測せずにプログラムが正しく実行されることを確認するために、@@ rowsetをチェックする追加のコード(ここにはリストされていません)があります。 1より大きい場合は、問題が発生したことを知っているので、理由を示さずに失敗したことを示すメッセージを作成する代わりに、実際のエラーを(必要に応じて)キャプチャして返すことができます。この方法で現実的にチェックすることは、デバッグや将来のレビューのためにエラーを別のテーブルに記録する場合に役立ちます。このようなエラーをエンドユーザーに送り返さないため、リアルタイムの解釈には役立ちません。

USE [**my_database**]
GO

SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO


CREATE procedure [dbo].[pass_encrypt]
(   @password       VARCHAR(64),
    @encryptedpass  VARCHAR(128) OUTPUT
)
AS
BEGIN
    DECLARE @command        VARCHAR(200)
    SET @command = **'C:\encrypt_pwd.exe**' + ' "' + @password + '"'

    BEGIN
        IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[#temppass]') AND type in (N'U')) 
            DROP TABLE [dbo].[#temppass]
        BEGIN TRY
            CREATE TABLE #temppass(encrypted varchar(1000))
            INSERT INTO #temppass execute xp_cmdshell @command
            IF (@@ROWCOUNT > 1)
                BEGIN
                    SET @encryptedpass = NULL
                    DROP TABLE #temppass
                    RETURN
                END
            ELSE
                BEGIN
                    SELECT @encryptedpass = encrypted FROM #temppass
                END
            --SELECT @encryptedpass
        END TRY
        BEGIN CATCH
            SET @encryptedpass = NULL
            DROP TABLE #temppass
            RETURN
        END CATCH
        --SELECT encrypted FROM #temppass
        DROP TABLE #temppass
    END
END
1
Saint Ronin