【问题标题】:Get Results from XP_CMDSHELL从 XP_CMDSHELL 获取结果
【发布时间】:2012-02-29 14:47:13
【问题描述】:

我一直在网上搜索一些,似乎从 XP_CMDSHELL 获取结果的唯一方法是将它们存储到临时表中。真的没有更简单的方法吗?

来自专家交流:

不,xp_cmdshell 不会从 exe 中返回任何信息。你必须使用以下 如果您不在 master 数据库中运行它,请使用语法。大师..xp_cmdshell。你不得不 授予您的用户在 master 数据库中执行此过程的权限。你必须有 您的 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

【问题讨论】:

    标签: sql-server stored-procedures xp-cmdshell


    【解决方案1】:

    没有更简单的方法可以从xp_cmdshell 捕获 STDOUT/STDERR 反馈;至少有一种选择,但它不能被归类为更容易:
    作为命令的一部分,可以将命令的输出重定向到文本文件,然后使用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
    

    【讨论】:

      【解决方案2】:

      这就是我最终做的事情......我今天回来查看并看到了您的回复。昨天我处于实时紧缩状态,因此开始朝临时表的方向工作,因为它是已确认的工作解决方案。我选择避免创建临时文件,因为在内部处理事情似乎同样容易或更容易,因为我实际上只是将它用作剪贴板。如有必要,我将进行的一项更改是在临时表名称中添加一个唯一编号,尽管我认为我不必担心这些会同时处理(这意味着存储过程的第二次调用可能会转储临时表,而cmd shell 正在运行)。我们拭目以待……

      我调用一个存储过程(往下看)来加密密码: 下面的代码已经过修改,使其能够自给自足。我实际上并没有手动设置密码,因为这基本上是一种密码卸载/同步解决方案。

      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
      

      【讨论】:

        猜你喜欢
        • 2015-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多