Extended stored procedure xp_fileexist appears to require sysadmin permissions

Moloney, Doug 1 Reputation point
2021-06-03T18:00:55.5+00:00

xp_fileexist appears to require sysadmin permissions.

If I run this with sysadmin

exec xp_fileexist '\servername\appfolder\filename.txt'

I get File Exist with a 1

However, when sysadmin permissions are removed it returns File Exists with a 0.

Does anyone know of any other way to grant the permission to return the correct result.

Developer technologies | Transact-SQL
SQL Server | Other
0 comments No comments
{count} votes

5 answers

Sort by: Most helpful
  1. Hafeez Uddin 296 Reputation points
    2021-06-03T18:20:45.64+00:00

    You can try

    SELECT * FROM sys.dm_os_file_exists('\servername\appfolder\filename.txt');

    2 people found this answer helpful.

  2. Tom Phillips 17,771 Reputation points
    2021-06-03T18:48:12.977+00:00

    I highly recommend against using undocumented extended procs or TSQL for file manipulation. They are not intended for user usage.

    If you need to something on the file system, I suggest you use SSIS or SQL Agent.

    2 people found this answer helpful.
    0 comments No comments

  3. Hafeez Uddin 296 Reputation points
    2021-06-03T19:14:19.987+00:00
    2 people found this answer helpful.
    0 comments No comments

  4. Erland Sommarskog 121.9K Reputation points MVP Volunteer Moderator
    2021-06-03T21:42:23.933+00:00

    I would agree with Hafeez that using sys.dm_os_file_exists is a better choice, since it is easier to use programmatically. But it is equally undocumented as xp_fileexists.

    Nevertheless, there is a solution. Put the operation you want to conduct in a stored procedure, probably including at least the part of the folder to where the user can look for a file. That is, the user should not be able to interrogate the entire server.

    Next you create a certificate and sign the procedure with the certificate. Then you create a login from the certificate and make that login member of sysadmin. That "login" is not a real login that can log in, it exists only to connect certificate and permission.

    I discuss this technique in a lot more detail in the article (Packaging Permissions in Stored Procedures](https://www.sommarskog.se/grantperm.html) on my web site.

    1 person found this answer helpful.
    0 comments No comments

  5. Chris Rokusek 0 Reputation points
    2023-04-15T23:43:41.0933333+00:00

    After discovering the same issue we used a mock bulk insert on the file. The login is required to be a member of the bulkadmin server role which is better than sysadmin (and it is perform a bulk admin anyway):

    
    GO
    SET ANSI_NULLS ON;
    GO
    SET QUOTED_IDENTIFIER ON;
    GO
    ALTER procedure [Common].[usp_FileExists] (
        @pPathName nvarchar(300),
        @poExists bit out,
        @pDebug bit = 0
    )    
    with execute as 'LoginThatIsInBulkAdminRole'
    as
    /*---------------------------------------------------------------------------------------------------------------------
        Purpose:   Return true if the file exists.  Alternative to the xp_fileexists which may requires special permissions 
                   for most users.
                      
        Modified    By              Description
        ----------  --------------  ---------------------------------------------------------------------------------------
        2020.04.08  crokusek        Initial version from udf_FileExists with added bulk insert test as a backup
      ---------------------------------------------------------------------------------------------------------------------*/ 
    begin try
      
        declare
            @fileExists int;
            
        exec xp_fileexist @pPathName, @fileExists output;
        
        set @poExists = iif(coalesce(@fileExists, 0) = 1, 1, 0);
        
        if (@poExists = 1)
            return;
            
        -- else retest using a bulk insert as the above returns false negatives on 
        -- network drives that aren't physically the local machine and missing instance permission.
                
        begin try
            declare 
                @sql varchar(1000) = '
                    declare @a bit = (
                        select 1 
                        from openrowset(bulk ''' + @pPathName + ''', single_blob) f
                    );
                ';
                
            execute (@sql)        
            set @poExists = 1;  -- assume if no error that it worked
        end try    
        begin catch
            declare
                @errorMessage nvarchar(max) = error_message();
                
            if (@pDebug = 1)
                print 'Caught bulk test error: ' + @errorMessage;
            
            set @poExists = 0;
        end catch
        
        return @poExists;
    end try
    begin catch
        declare        
            @CatchingUsp  varchar(100) = object_name(@@procid);    
      
        if (xact_state() = -1)
            rollback;
        
      /*  Adjust as needed
    
       exec Common.usp_Log
            @pMethod = @CatchingUsp;
            
        exec Common.usp_RethrowError
            @pCatchingMethod = @CatchingUsp;*/
    end catch
    
    GO
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.