2012-02-29 79 views
14

He estado buscando en la web y parece que la única forma de obtener los resultados de XP_CMDSHELL es almacenarlos en una tabla temporal. ¿No hay realmente una manera más fácil?Obtener resultados de XP_CMDSHELL

De intercambio de los expertos:

No, xp_cmdshell no devolverá información del exe. y debe usar la siguiente sintaxis si no se encuentra en la base de datos master para ejecutarla. master..xp_cmdshell. Tendrá que dar permiso a su usuario para ejecutar este procedimiento en la base de datos maestra. Deberá tener su exe insertar la información en sí mismo porque no puede devolver información al proceso que lo llamó.

Y ...

Mientras @result sólo se obtiene el valor de retorno de xp_cmdshell, que puede ser capaz de capturar los resultados del comando insertando directamente en una mesa ... algo como esto:

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 

Respuesta

18

no hay manera más fácil de capturar STDOUT/retroalimentación STDERR de xp_cmdshell; existe al menos una alternativa, pero no se clasificó como más fácil:
. Sería posible redirigir la salida del comando a un archivo de texto como parte del comando, luego leer el archivo de texto usando OPENROWSET.

BTW hay al menos un error en el script publicado anteriormente. Los documentos para xp_cmdshell indican que devuelve el resultado del comando como nvarchar (255).
Además, la tabla temporal debe tener una columna de identidad, de lo contrario los resultados no se pueden mostrar en el orden correcto:

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

Esto es lo que terminé haciendo ... he comprobado volver hoy y vi su respuesta. Ayer tuve una crisis en tiempo real, así que comencé a trabajar en la dirección de la mesa de trabajo temporal, ya que era una solución de trabajo confirmada. Había elegido evitar crear los archivos temporales ya que me parecía fácil o más fácil de manejar internamente, ya que realmente lo estoy usando como un portapapeles. El único cambio que haré si es necesario es agregar un número único al nombre de la tabla temporal aunque no creo que tenga que preocuparme de que se procesen simultáneamente (lo que significa que una segunda llamada del procedimiento almacenado podría volcar la tabla temporal mientras el shell cmd se está ejecutando). Veremos ...

Llamo a un procedimiento almacenado (mire más abajo) para encriptar la contraseña: El código siguiente se modificó para que sea autosuficiente. En realidad, no estoy configurando la contraseña manualmente, ya que básicamente es una solución de descarga/sincronización de contraseña.

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 

Aquí está el procedimiento almacenado cifrar: Para comprobar y asegurarse de que el programa se ejecuta correctamente sin tener que adivinar qué el código de retorno indica el fracaso, no tengo código adicional (no mencionados aquí) que comprueba @@ conjunto de filas. Si es más de 1, sé que algo salió mal y puedo capturar/devolver el error real (si lo desea) en lugar de solo crear mi propio mensaje que dice que falló sin dar ninguna indicación de por qué.La comprobación realista de esta manera es más útil para la depuración o para registrar el error en otra tabla para su futura revisión, no para la interpretación en tiempo real, ya que no voy a enviar un error como ese al usuario final.

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 
Cuestiones relacionadas