Получить результаты от XP_CMDSHELL - PullRequest
14 голосов
/ 29 февраля 2012

Я некоторое время искал в Интернете, и кажется, что единственный способ получить результаты из XP_CMDSHELL - это сохранить их во временной таблице.Неужели нет более простого способа?

От экспертов Exchange:

Нет, xp_cmdshell не будет возвращать какую-либо информацию из exe.и вы должны использовать следующий синтаксис, если вы не в основной базе данных, чтобы запустить его.master..xp_cmdshell.Вы должны будете дать своему пользователю разрешение на выполнение этой процедуры в базе данных master.Вам нужно будет, чтобы ваш 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

Ответы [ 2 ]

20 голосов
/ 29 февраля 2012

Нет более простого способа получить обратную связь STDOUT / STDERR от xp_cmdshell;есть по крайней мере одна альтернатива, но ее нельзя классифицировать как более простую:
Можно было бы перенаправить вывод команды в текстовый файл как часть команды, а затем прочитать текстовый файл, используя OPENROWSET.

Кстати, в вышеприведенном скрипте есть хотя бы одна ошибка.Документы для xp_cmdshell указывают, что он возвращает вывод команды в виде nvarchar (255).
Кроме того, временная таблица должна иметь столбец идентификаторов, иначе результаты могут отображаться не в правильном порядке.:

...
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
1 голос
/ 01 марта 2012

Это то, что я в конечном итоге сделал ... Я проверил сегодня и увидел ваш ответ.Вчера я был в затруднительном положении в реальном времени, поэтому начал работать в направлении временной таблицы, поскольку это было подтвержденное рабочее решение.Я решил избегать создания временных файлов, поскольку казалось, что обрабатывать вещи внутренне так же просто или просто, поскольку я просто использую их как буфер обмена.Единственное изменение, которое я сделаю при необходимости, - это добавление уникального номера к имени временной таблицы, хотя я не думаю, что мне нужно беспокоиться о том, что они обрабатываются одновременно (это означает, что второй вызов хранимой процедуры может вывести временную таблицу, покаоболочка 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
...