2012-02-29 30 views
14

Tôi đã tìm kiếm trên web một số và có vẻ như cách duy nhất để có được kết quả từ XP_CMDSHELL là lưu trữ chúng vào bảng tạm thời. Có thực sự không có cách nào dễ dàng hơn?Nhận kết quả từ XP_CMDSHELL

Từ Các chuyên gia giao dịch:

Không, xp_cmdshell sẽ không trả lại bất kỳ thông tin từ exe. và bạn phải sử dụng cú pháp sau nếu bạn không ở trong cơ sở dữ liệu chính để chạy nó. master..xp_cmdshell. Bạn sẽ phải cấp cho người dùng quyền thực thi quy trình này trong cơ sở dữ liệu chính. Bạn sẽ phải có exe ​​của bạn tự chèn thông tin vì nó không thể trả lại thông tin cho quá trình gọi nó.

Và ...

Trong khi @result chỉ nhận được giá trị trả về từ xp_cmdshell, bạn có thể nắm bắt được kết quả của lệnh bằng cách chèn trực tiếp vào một bảng ... một cái gì đó như thế này:

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 

Trả lời

18

không có cách nào dễ dàng hơn để nắm bắt STDOUT/sTDERR phản hồi từ xp_cmdshell; có ít nhất một giải pháp thay thế nhưng không thể phân loại dễ dàng hơn:
Có thể chuyển hướng đầu ra của lệnh tới tệp văn bản như một phần của lệnh, sau đó đọc tệp văn bản bằng cách sử dụng OPENROWSET.

BTW có ít nhất một lỗi trong tập lệnh được đăng ở trên. Tài liệu cho trạng thái xp_cmdshell trả về kết quả đầu ra của lệnh là nvarchar (255).
Ngoài ra, các bảng tạm thời phải có một cột sắc, nếu không thì kết quả có thể không được hiển thị theo đúng thứ tự:

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

Đây là những gì tôi đã kết thúc làm ... Tôi đã kiểm tra lại ngày hôm nay và thấy bạn phản ứng. Tôi đã ở trong một cuộc khủng hoảng thời gian thực ngày hôm qua để bắt đầu làm việc theo hướng của bảng tạm thời vì nó là một giải pháp làm việc được xác nhận. Tôi đã chọn để tránh tạo ra các tập tin tạm thời vì nó có vẻ dễ dàng hoặc dễ dàng hơn để xử lý những thứ nội bộ vì tôi thực sự chỉ sử dụng nó như một clipboard. Một thay đổi mà tôi sẽ thực hiện nếu cần thiết là thêm một số duy nhất vào tên bảng tạm thời mặc dù tôi không nghĩ rằng tôi phải lo lắng về việc xử lý đồng thời (nghĩa là cuộc gọi thứ hai của thủ tục được lưu trữ có thể đổ bảng tạm thời trong khi shell cmd đang chạy). Chúng ta sẽ thấy ...

Tôi gọi thủ tục được lưu trữ (xem tiếp xuống) để mã hóa mật khẩu: Mã dưới đây đã được sửa đổi để làm cho nó tự cung tự cấp. Tôi không thực sự thiết lập mật khẩu theo cách thủ công vì đây là giải pháp offloading/đồng bộ hóa mật khẩu.

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 

Đây là thủ tục lưu trữ mã hóa: Để kiểm tra và chắc chắn rằng các chương trình thực hiện đúng mà không cần phải đoán tại sao đoạn code trở lại chỉ ra sự thất bại, tôi có mã bổ sung (không được liệt kê ở đây) để kiểm tra @@ rowset. Nếu đó là nhiều hơn 1, tôi biết có điều gì đó sai và tôi có thể nắm bắt/trả lại lỗi thực tế (nếu muốn) thay vì chỉ tạo thông báo của riêng tôi cho biết không thành công mà không đưa ra bất kỳ dấu hiệu nào về lý do.Thực tế kiểm tra theo cách này là hữu ích hơn để gỡ lỗi hoặc để đăng nhập lỗi vào một bảng khác để xem xét trong tương lai - không phải để giải thích thời gian thực vì tôi sẽ không gửi một lỗi như vậy trở lại cho người dùng cuối.

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 
Các vấn đề liên quan