Search code examples
inno-setupwindows-update

Inno Setup - How to Install Windows Update Offline Installer


I'm writing a function that will install a required component for my appliance, which is built upon PowerShell. If a specific version of PowerShell is not found, I want the installer to help the user install it. The problem I'm running into is how to appropriately call the offline installer for installation. Here is the code I have, which is a generic function (I am using the InnoSetup Dependency Installer):

function SmartExec(product : TProduct; var resultcode : Integer): boolean;
begin
    if (LowerCase(Copy(product.File, Length(product.File) - 2, 3)) = 'exe') then begin
        Result := Exec(product.File, product.Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, resultcode);
    end else begin
        Result := ShellExec('', product.File, product.Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, resultcode);
    end;
end;

I have tried using the following:

function SmartExec(product : TProduct; var resultcode : Integer): boolean;
begin
    if (LowerCase(Copy(product.File, Length(product.File) - 2, 3)) = 'exe') then begin
        Result := Exec(product.File, product.Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, resultcode);
  end else if (LowerCase(Copy(product.File, Length(product.File) - 2, 3)) = 'msu') then begin
        Result := ShellExec('', 'wusa.exe ' + product.File, product.Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, resultcode);
    end else begin
        Result := ShellExec('', product.File, product.Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, resultcode);
    end;
end;

When I compile and test the installer, I'm greeted with:

enter image description here

I am passing /quiet /norestart as parameters to the MSU file, which execute perfectly from a command prompt.

The installation file is downloaded to %tmp% for the current user, and I see the file.

Any help or comments?


Solution

  • The .msu extension is associated with wusa.exe, so the existing branch ShellExec('', product.File, ...) should do the job. You should not need to add a specific msu branch.


    Anyway, the specific branch can help with the debugging, so it's worth trying.

    The second parameter of ShellExec function is a FileName, while you pass in wusa.exe xxx.msu, what is not a valid file name.

    This should work:

    Result := ShellExec('', 'wusa.exe', product.File + ' ' + product.Parameters, ...);
    

    Though using the ShellExec to run an executable is an overkill, use plain Exec function instead:

    Result := Exec('wusa.exe', product.File + ' ' + product.Parameters, ...);
    

    When the Exec returns False, the ResultCode is a Windows error code explaining why the execution failed. You are getting code 3, what is ERROR_PATH_NOT_FOUND (The system cannot find the path specified.).

    So it looks like the path you are using (product.File) is not valid.

    Make sure you pass in a full path to the .msu, not just a filename.

    Try logging the path before calling the Exec and check if the file exists. You can use:

    Log(Format('Path is [%s], Exists = %d', [product.File, Integer(FileExists(product.File))]));