[Setup] AppId={{9C4A6F1D-8975-476E-8512-4217DE029A88}} AppName=LOGAR Client AppVersion=0.3.4.2 AppPublisher=LOGAR AppPublisherURL=https://logar.eibl.tech AppSupportURL=https://logar.eibl.tech AppUpdatesURL=https://logar.eibl.tech DefaultDirName={autopf}\LOGAR UsePreviousAppDir=yes OutputDir=..\dist OutputBaseFilename=LOGAR-Client-Setup PrivilegesRequired=admin Compression=lzma SolidCompression=yes WizardStyle=modern SetupIconFile=assets\logo.ico WizardImageFile=assets\wizard_sidebar.bmp WizardSmallImageFile=assets\wizard_small.bmp VersionInfoCompany=LOGAR VersionInfoDescription=LOGAR Windows Edge Log Forwarder Setup VersionInfoVersion=0.3.4.2 VersionInfoProductName=LOGAR Client VersionInfoProductVersion=0.3.4.2 [Files] Source: "..\dist\Win_Client.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "..\compilation\nssm.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "..\dist\runtime\*"; DestDir: "{app}\runtime"; Flags: ignoreversion recursesubdirs createallsubdirs [Dirs] Name: "{code:GetDataDir}"; Permissions: users-modify [Run] Filename: "{app}\nssm.exe"; Parameters: "install LOGAR_Client ""{app}\Win_Client.exe"""; Flags: runhidden Filename: "{app}\nssm.exe"; Parameters: "set LOGAR_Client AppDirectory ""{app}"""; Flags: runhidden Filename: "{app}\nssm.exe"; Parameters: "set LOGAR_Client AppStdout ""{code:GetDataDir}\client.log"""; Flags: runhidden Filename: "{app}\nssm.exe"; Parameters: "set LOGAR_Client AppStderr ""{code:GetDataDir}\client_err.log"""; Flags: runhidden Filename: "{app}\nssm.exe"; Parameters: "set LOGAR_Client AppParameters ""--config """"{code:GetDataDir}\client_config.json"""" --interval 30"""; Flags: runhidden Filename: "{app}\nssm.exe"; Parameters: "start LOGAR_Client"; Flags: runhidden [UninstallRun] Filename: "{app}\nssm.exe"; Parameters: "stop LOGAR_Client"; Flags: runhidden Filename: "{app}\nssm.exe"; Parameters: "remove LOGAR_Client confirm"; Flags: runhidden [UninstallDelete] Type: filesandordirs; Name: "{app}\certs" Type: files; Name: "{app}\client_config.json" Type: files; Name: "{app}\client_state.json" Type: files; Name: "{app}\*.log" Type: filesandordirs; Name: "{app}\runtime" Type: filesandordirs; Name: "{app}" Type: filesandordirs; Name: "{commonappdata}\LOGAR" [Code] var DataDirPage: TInputDirWizardPage; ConfigFilePage: TInputFileWizardPage; IsUpdateMode: Boolean; ExistingDataDir: String; function InitializeSetup(): Boolean; var ServerFound: Boolean; Val: String; begin Result := True; IsUpdateMode := False; ExistingDataDir := ''; ServerFound := False; // 1. Mutual Exclusion Check: Deny installation if LOGAR Server is already present if RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\LOGAR\LOGAR-Server') or RegValueExists(HKEY_LOCAL_MACHINE, 'Software\LOGAR\LOGAR-Server', 'DataDir') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{{4F3D675E-1E4E-43B6-8C84-B47DE290BE4A}}_is1') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{{4F3D675E-1E4E-43B6-8C84-B47DE290BE4A}}_is1') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\LOGAR Server_is1') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\LOGAR Server_is1') or FileExists(ExpandConstant('{autopf}\LOGAR-Server\Server.exe')) then begin ServerFound := True; end; if ServerFound then begin MsgBox('LOGAR Server is already installed on this machine.'#13#10#13#10 + 'LOGAR Client cannot be installed on a LOGAR Server host (LOGAR Server already provides built-in log collection).'#13#10#13#10 + 'Please uninstall LOGAR Server first if you wish to run a standalone forwarder client.', mbCriticalError, MB_OK); Result := False; Exit; end; // 2. Existing LOGAR Client Detection for In-Place Update Mode if RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\LOGAR\LOGAR-Client') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{{9C4A6F1D-8975-476E-8512-4217DE029A88}}_is1') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{{9C4A6F1D-8975-476E-8512-4217DE029A88}}_is1') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\LOGAR Client_is1') or RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\LOGAR Client_is1') or FileExists(ExpandConstant('{autopf}\LOGAR\Win_Client.exe')) then begin IsUpdateMode := True; if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\LOGAR\LOGAR-Client', 'DataDir', Val) then ExistingDataDir := Val; MsgBox('An existing installation of LOGAR Client was detected.'#13#10#13#10 + 'Setup will perform an in-place update: core binaries will be updated, while your existing configuration (client_config.json), state tracking, and certificates will be preserved.', mbInformation, MB_OK); end; end; procedure InitializeWizard; begin DataDirPage := CreateInputDirPage( wpSelectDir, 'Data and Configuration Location', 'Where should LOGAR Client store its state tracking and certificates?', 'Select the folder where LOGAR Client should store state tracking (client_state.json), configuration (client_config.json), and mTLS certificates.'#13#10#13#10 + 'By default, this is stored in Common AppData (C:\ProgramData\LOGAR), which is accessible to background Windows services.', False, '' ); DataDirPage.Add('Data Directory:'); if (ExistingDataDir <> '') then DataDirPage.Values[0] := ExistingDataDir else DataDirPage.Values[0] := ExpandConstant('{commonappdata}\LOGAR'); ConfigFilePage := CreateInputFilePage( DataDirPage.ID, 'Import Client Configuration (Optional)', 'Do you have a pre-exported client_config.json profile to import?', 'Select your client_config.json profile exported from the LOGAR Server Hub.'#13#10#13#10 + 'If selected, this configuration will be copied into the data directory and used for automated server connection and enrollment.'#13#10#13#10 + 'You can also leave this blank to place client_config.json in the data directory manually later.' ); ConfigFilePage.Add('Client Configuration (client_config.json):', 'JSON Files (*.json)|*.json|All Files (*.*)|*.*', '.json'); end; function ShouldSkipPage(PageID: Integer): Boolean; begin Result := False; if IsUpdateMode then begin if (PageID = wpSelectDir) or (PageID = DataDirPage.ID) or (PageID = ConfigFilePage.ID) then Result := True; end; end; function GetDataDir(Param: String): String; begin if IsUpdateMode and (ExistingDataDir <> '') then begin Result := ExistingDataDir; Exit; end; Result := DataDirPage.Values[0]; if Result = '' then Result := ExpandConstant('{commonappdata}\LOGAR'); end; function GetConfigFile(Param: String): String; begin Result := ConfigFilePage.Values[0]; end; procedure CurStepChanged(CurStep: TSetupStep); var ResultCode: Integer; CfgPath, DestCfg: String; begin if CurStep = ssInstall then begin Exec('net.exe', 'stop LOGAR_Client', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Exec('sc.exe', 'stop LOGAR_Client', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Exec('taskkill.exe', '/F /T /IM Win_Client.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Exec('taskkill.exe', '/F /T /IM nssm.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Sleep(500); end else if CurStep = ssPostInstall then begin RegWriteStringValue(HKEY_LOCAL_MACHINE, 'Software\LOGAR\LOGAR-Client', 'InstallDir', ExpandConstant('{app}')); RegWriteStringValue(HKEY_LOCAL_MACHINE, 'Software\LOGAR\LOGAR-Client', 'DataDir', GetDataDir('')); if not IsUpdateMode then begin CfgPath := GetConfigFile(''); if (CfgPath <> '') and FileExists(CfgPath) then begin DestCfg := GetDataDir('') + '\client_config.json'; FileCopy(CfgPath, DestCfg, False); end; end; end; end; procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); var CustomDataDir, AppDir, PowerShellCmd: String; I, ResultCode: Integer; begin if CurUninstallStep = usUninstall then begin AppDir := ExpandConstant('{app}'); Exec('net.exe', 'stop LOGAR_Client', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Exec('sc.exe', 'stop LOGAR_Client', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); if FileExists(AppDir + '\nssm.exe') then begin Exec(AppDir + '\nssm.exe', 'stop LOGAR_Client', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Exec(AppDir + '\nssm.exe', 'remove LOGAR_Client confirm', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); end; Exec('sc.exe', 'delete LOGAR_Client', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Exec('taskkill.exe', '/F /T /IM Win_Client.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Exec('taskkill.exe', '/F /T /IM nssm.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); PowerShellCmd := '-NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "' + 'Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -like ''' + AppDir + '\*'' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }"'; Exec('powershell.exe', PowerShellCmd, '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Sleep(1200); end else if CurUninstallStep = usPostUninstall then begin AppDir := ExpandConstant('{app}'); Exec('taskkill.exe', '/F /T /IM Win_Client.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); Exec('taskkill.exe', '/F /T /IM nssm.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\LOGAR\LOGAR-Client', 'DataDir', CustomDataDir) then begin if (CustomDataDir <> '') and DirExists(CustomDataDir) then begin for I := 1 to 5 do begin if DelTree(CustomDataDir, True, True, True) or not DirExists(CustomDataDir) then Break; Sleep(300); end; end; RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE, 'Software\LOGAR\LOGAR-Client'); end; if (AppDir <> '') and DirExists(AppDir) then begin for I := 1 to 10 do begin DeleteFile(AppDir + '\nssm.exe'); DeleteFile(AppDir + '\Win_Client.exe'); DelTree(AppDir + '\runtime', True, True, True); DelTree(AppDir + '\certs', True, True, True); if DelTree(AppDir, True, True, True) or not DirExists(AppDir) then Break; Sleep(300); end; end; end; end;