Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inno Setup Run Extracted Batch File As Administrator

I am building an installer with Inno Setup and would like for the extracted files to be run as an administrator. Is there a way to force the extracted files (i.e. batch file) to run as an administrator? If so, what code elements do I need to include to perform this.

The setup log shows something like the following:

2013-05-07 17:34:25.303   -- Run entry --
2013-05-07 17:34:25.303   Run as: Current user
2013-05-07 17:34:25.303   Type: Exec
2013-05-07 17:34:25.303   Filename: C:\Temp\is-U4VID.tmp\Filename.bat
2013-05-07 17:34:25.412   Process exit code: 0

The files that I am having problems with running as an admin user are included in the [Run] section.

like image 887
John Avatar asked May 07 '13 22:05

John


2 Answers

If you are using [Run] section then make sure you use runascurrentuser flag (If this flag is specified, the spawned process will inherit Setup/Uninstall's user credentials (typically, full administrative privileges))

Else there are three ways how to run applications programatically (recommended way):

function Exec(const Filename, Params, WorkingDir: String; const ShowCmd: Integer; const Wait: TExecWait; var ResultCode: Integer): Boolean;

function ShellExec(const Verb, Filename, Params, WorkingDir: String; const ShowCmd: Integer; const Wait: TExecWait; var ErrorCode: Integer): Boolean;

function ShellExecAsOriginalUser(const Verb, Filename, Params, WorkingDir: String; const ShowCmd: Integer; const Wait: TExecWait; var ErrorCode: Integer): Boolean;

You should use Exec() or ShellExec() because they open the specified file or performs another action specified by Verb, using the same credentials as Setup/Uninstall.

But none of mentioned ways will work if your installer is not running in elevated mode. So make sure the UAC window will appear before installer starts:

In section [Setup] use directive PrivilegesRequired

Valid values:

none, poweruser, admin, or lowest

Use admin to ensure appropriate credentials.

like image 151
Slappy Avatar answered Nov 20 '22 15:11

Slappy


But what if you need to run a batch file in the postUninstall moment? In this case to restore a backup of database files that were altered by the application?

It tooks some hours trying everything until I found this hack.

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var 
  ResultCode: Integer;
  outfile: String;
  runBatHeader: String;
  runBatBody: String;

begin

  if CurUninstallStep = usPostUninstall then
  begin
    (*
        This is a messy hack, but the only way I could find to run a bat file
        during the post unistall section. In this case all files copied are 
        already removed, and it was not permitted to extract temp files in
        the uninstall phase. Code here writes 'outfile' to a system folder then runs it. 
    *)
    if DirExists('C:\ProgramData\MySQL\MySQL Server 5.7_bak') then begin
      if MsgBox('Uninstall located a possible backup of your original MySQL tables. ' +
        'Uninstall can attempt to copy it to the previous location. There is no ' +
        'guarantee that it will succeed. Do you want to try restoring this folder?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDYES then
      begin 

        outFile := 'C:\ProgramData\MySQL\restore.bat';
        runBatHeader := '@echo off' + #13#10 + #13#10;
        runBatBody := 'ECHO Attempt to stop MySQL57' + #13#10 + 
              'NET STOP MySQL57' + #13#10 + 
              'ECHO Removing application databases' + #13#10 + 
              'RMDIR /S /Q "C:\ProgramData\MySQL\MySQL Server 5.7\"' +  #13#10 + 
              'ECHO Copying backup to original location' + #13#10 + 
              'XCOPY "C:\ProgramData\MySQL\MySQL Server 5.7_bak" "C:\ProgramData\MySQL\MySQL Server 5.7\"  /C /E /H /I /K /O /Q /R /Y' +  #13#10 +   #13#10 + 
              'ECHO Try to start MySQL57' + #13#10 + 
              'NET START MySQL57';';
        SaveStringToFile(outFile, runBatHeader, False); 
        SaveStringToFile(outFile, runBatBody, True); 

        MsgBox('ShelExec : C:\ProgramData\MySQL\restore.bat', mbConfirmation, MB_OK);
        if not ShellExec('', 'C:\ProgramData\MySQL\restore.bat', '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
        begin
          // handle failure if necessary
          MsgBox('Apparently, the administrative privilege was not operational. Exiting without restoring the backup. ('+ IntToStr(ResultCode) +')', mbConfirmation, MB_OK);
        end;
        DeleteFile(outfile);

      end;
    end;
  end;
end;

It was not my idea though. I found an example here.

like image 38
ndasusers Avatar answered Nov 20 '22 14:11

ndasusers