2012-02-29 9 views
14

Przeszukałem niektóre strony i wydaje się, że jedynym sposobem uzyskania wyników z XP_CMDSHELL jest zapisanie ich w tabeli tymczasowej. Czy naprawdę nie ma prostszego sposobu?Wyniki z XP_CMDSHELL

Od Experts Exchange:

Nie, xp_cmdshell nie zwróci żadnych informacji z exe. i musisz użyć następującej składni , jeśli nie jesteś w głównej bazie danych, aby ją uruchomić. master..xp_cmdshell. Będziesz musiał dać użytkownikowi uprawnienia do wykonania tej procedury w głównej bazie danych. Będziesz musiał mieć swój exe wstawić informację siebie, ponieważ nie może on zwrócić informacji do procesu, który nazwał go proces, który został .

I ...

Podczas @result tylko pobiera wartości zwracanej z xp_cmdshell, może być w stanie uchwycić wyniki komendy poprzez wstawienie bezpośrednio do tabeli ... coś takiego:

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 

Odpowiedz

18

nie ma łatwiejszego sposobu, aby uchwycić STDOUT/stderr zwrotne od xp_cmdshell; istnieje co najmniej jedna alternatywa, ale nie można jej zaklasyfikować jako łatwiejszej:
Możliwe byłoby przekierowanie danych wyjściowych polecenia do pliku tekstowego jako części polecenia, a następnie odczytanie pliku tekstowego za pomocą OPENROWSET.

BTW występuje przynajmniej jeden błąd w skrypcie zamieszczonym powyżej. Dokumenty dla xp_cmdshell określają, że zwracają dane wyjściowe polecenia jako nvarchar (255).
Również tabela temp powinien mieć kolumnę tożsamości, w przeciwnym razie wyniki nie mogą być wyświetlane w odpowiedniej kolejności:

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

To, co skończyło się robi ... Sprawdziłem z powrotem dzisiaj i zobaczyłem swoje odpowiedź. Byłem w czasie kryzysu wczorajszego, więc zacząłem pracować w kierunku stołu tymczasowego, ponieważ było to potwierdzone rozwiązanie robocze. Postanowiłem uniknąć tworzenia plików tymczasowych, ponieważ sprawianie wewnętrznych problemów wydawało się równie łatwe lub łatwiejsze, ponieważ naprawdę używam go jako schowka. Jedną zmianą, którą wprowadzę w razie potrzeby, jest dodanie unikalnego numeru do nazwy tabeli tymczasowej, chociaż nie sądzę, żebym musiał się martwić o to, że są one przetwarzane jednocześnie (co oznacza, że ​​drugie wywołanie procedury składowanej może zrzucić tabelę tymczasową podczas powłoka cmd działa). Zobaczymy ...

Zadzwonię do procedury przechowywanej (patrz niżej), aby zaszyfrować hasło: Poniższy kod został zmodyfikowany, aby był samowystarczalny. W rzeczywistości nie ustawiam hasła ręcznie, ponieważ jest to w zasadzie rozwiązanie do odciążania/synchronizacji haseł.

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 

Oto szyfrowanie procedura przechowywana: Aby sprawdzić i upewnić się, że program wykonuje prawidłowo bez konieczności odgadnąć dlaczego kod powrotu wskazuje niepowodzenie, mam dodatkowy kod (nie wymienionych tutaj), który sprawdza @@ zestawu wierszy. Jeśli jest więcej niż 1, wiem, że coś poszło nie tak i mogę przechwycić/zwrócić rzeczywisty błąd (jeśli jest to pożądane) zamiast tworzyć własną wiadomość, która mówi, że nie udała się bez podania przyczyny.Realistyczna kontrola w ten sposób jest bardziej przydatna do debugowania lub rejestrowania błędu w innej tabeli do przyszłego przeglądu - nie w interpretacji w czasie rzeczywistym, ponieważ nie zamierzam wysyłać takiego błędu do użytkownika końcowego.

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 
Powiązane problemy