Получить результаты от XP_CMDSHELL

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

От обмена экспертами:

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

Ответы

Ответ 1

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

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

...
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

Ответ 2

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