19

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

専門家交換から:

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

と...

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

うーん...

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
4

2 に答える 2

28

からの STDOUT/STDERR フィードバックをキャプチャする簡単な方法はありませんxp_cmdshell。少なくとも 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
于 2012-02-29T19:11:56.340 に答える
1

これが私がやったことです... 今日もう一度チェックして、あなたの反応を見ました。昨日はリアルタイムの危機に瀕していたので、確認済みの実用的な解決策だったので、一時テーブルの方向で作業を開始しました。実際にはクリップボードとして使用しているだけなので、内部で物事を処理するのと同じくらい簡単または簡単に思えたので、一時ファイルの作成を避けることにしました。必要に応じて行う変更の 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
于 2012-03-01T17:01:34.867 に答える