# This file must be UNICODE !define PRODUCT_NAME "Salt Minion" !define PRODUCT_PUBLISHER "SaltStack, Inc" !define PRODUCT_WEB_SITE "http://saltproject.io" !define PRODUCT_CALL_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-call.exe" !define PRODUCT_CP_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-cp.exe" !define PRODUCT_KEY_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-key.exe" !define PRODUCT_MASTER_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-master.exe" !define PRODUCT_MINION_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-minion.exe" !define PRODUCT_RUN_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-run.exe" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define PRODUCT_UNINST_ROOT_KEY "HKLM" # Request admin rights RequestExecutionLevel admin # Import Libraries !include "FileFunc.nsh" !include "LogicLib.nsh" !include "MoveFileFolder.nsh" !include "MUI2.nsh" !include "nsDialogs.nsh" !include "StrFunc.nsh" !include "WinMessages.nsh" !include "WinVer.nsh" !include "x64.nsh" ${StrLoc} ${StrRep} ${StrStrAdv} # Required by MoveFileFolder.nsh !insertmacro Locate # Get salt version from CLI argument /DSaltVersion !ifdef SaltVersion !define PRODUCT_VERSION "${SaltVersion}" !else !define PRODUCT_VERSION "Undefined Version" !endif # Get architecture from CLI argument /DPythonArchitecture # Should be x64, AMD64, or x86 !ifdef PythonArchitecture !define PYTHON_ARCHITECTURE "${PythonArchitecture}" !else # Default !define PYTHON_ARCHITECTURE "x64" !endif # Get Estimated Size from CLI argument /DEstimatedSize !ifdef EstimatedSize !define ESTIMATED_SIZE "${EstimatedSize}" !else # Default !define ESTIMATED_SIZE 0 !endif # x64 and AMD64 are AMD64, all others are x86 !if "${PYTHON_ARCHITECTURE}" == "x64" !define CPUARCH "AMD64" !else if "${PYTHON_ARCHITECTURE}" == "AMD64" !define CPUARCH "AMD64" !else !define CPUARCH "x86" !endif !define BUILD_TYPE "Python 3" !define OUTFILE "Salt-Minion-${PRODUCT_VERSION}-Py3-${CPUARCH}-Setup.exe" VIProductVersion "1.0.0.0" # This actually updates File Version VIAddVersionKey FileVersion "1.0.0.0" # This doesn't seem to do anything, but you'll get a warning without it VIAddVersionKey "ProductName" "${PRODUCT_NAME}" VIAddVersionKey "LegalTrademarks" "${PRODUCT_NAME} is a trademark of ${PRODUCT_PUBLISHER}" VIAddVersionKey "LegalCopyright" "© ${PRODUCT_PUBLISHER}" VIAddVersionKey "FileDescription" "${PRODUCT_NAME} Installer" VIAddVersionKey "ProductVersion" "${PRODUCT_VERSION}" ################################################################################ # Early defines ################################################################################ !define Trim "!insertmacro Trim" !macro Trim ResultVar String Push "${String}" !ifdef __UNINSTALL__ Call un.Trim !else Call Trim !endif Pop "${ResultVar}" !macroend # Part of the Explode function for Strings !define Explode "!insertmacro Explode" !macro Explode Length Separator String Push "${Separator}" Push "${String}" Call Explode Pop "${Length}" !macroend # Variables for Logging Var LogFile Var TimeStamp Var cmdLineParams Var logFileHandle Var msg # Followed this: https://nsis.sourceforge.io/StrRep !define LogMsg '!insertmacro LogMsg' !macro LogMsg _msg Push "${_msg}" !ifdef __UNINSTALL__ Call un.LogMsg !else Call LogMsg !endif !macroend !macro Func_LogMsg un Function ${un}LogMsg Pop $msg ${If} $TimeStamp == "" ${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6 StrCpy $TimeStamp "$2-$1-$0_$4-$5-$6" ${EndIf} ${If} $LogFile == "" !ifdef __UNINSTALL__ StrCpy $LogFile "$TEMP\SaltInstaller\$TimeStamp-uninstall.log" !else StrCpy $LogFile "$TEMP\SaltInstaller\$TimeStamp-install.log" !endif ${IfNot} ${FileExists} "$TEMP\SaltInstaller\*.*" CreateDirectory "$TEMP\SaltInstaller" ${EndIf} ${EndIf} ${Trim} $msg $msg DetailPrint "$msg" FileOpen $logFileHandle "$LogFile" a FileSeek $logFileHandle 0 END FileWrite $logFileHandle "$msg$\r$\n" FileClose $logFileHandle FunctionEnd !macroend !insertmacro Func_LogMsg "" !insertmacro Func_LogMsg "un." ############################################################################### # Configure Pages, Ordering, and Configuration ############################################################################### !define MUI_ABORTWARNING !define MUI_ICON "salt.ico" !define MUI_UNICON "salt.ico" !define MUI_WELCOMEFINISHPAGE_BITMAP "panel.bmp" !define MUI_UNWELCOMEFINISHPAGE_BITMAP "panel.bmp" # Welcome page !insertmacro MUI_PAGE_WELCOME # License page !insertmacro MUI_PAGE_LICENSE "LICENSE.txt" # Install location page !define MUI_PAGE_CUSTOMFUNCTION_SHOW pageCheckExistingInstall !insertmacro MUI_PAGE_DIRECTORY # Configure Minion page Page custom pageMinionConfig pageMinionConfig_Leave # Instfiles page !insertmacro MUI_PAGE_INSTFILES # Finish page (Customized) !define MUI_PAGE_CUSTOMFUNCTION_SHOW pageFinish_Show !define MUI_PAGE_CUSTOMFUNCTION_LEAVE pageFinish_Leave !insertmacro MUI_PAGE_FINISH # Uninstaller pages !insertmacro MUI_UNPAGE_INSTFILES # Language files !insertmacro MUI_LANGUAGE "English" ############################################################################### # Custom Dialog Box Variables ############################################################################### Var Dialog Var Label Var MinionStart_ChkBox Var MinionStartDelayed_ChkBox Var MasterHost_Cfg Var MasterHost_TxtBox Var MasterHost Var MinionName_Cfg Var MinionName_TxtBox Var MinionName Var ExistingConfigFound Var ConfigType_DropList Var ConfigType Var CustomConfig_TxtBox Var CustomConfig_Btn Var CustomConfig Var CustomConfigWarning_Lbl Var ExistingConfigWarning_Lbl Var DefaultConfigWarning_Lbl Var MoveExistingConfig_ChkBox Var MoveExistingConfig Var StartMinion Var StartMinionDelayed Var DeleteInstallDir Var DeleteRootDir Var ConfigWriteMinion Var ConfigWriteMaster # For new method installation Var RegInstDir Var RegRootDir Var RootDir Var SysDrive Var ExistingInstallation Var CustomLocation ############################################################################### # Directory Picker Dialog Box ############################################################################### Function pageCheckExistingInstall # If this is an Existing Installation we want to disable the directory # picker functionality # https://nsis-dev.github.io/NSIS-Forums/html/t-166727.html # Use the winspy tool (https://sourceforge.net/projects/winspyex/) to get # the Control ID for the items you want to disable # The Control ID is in the Details tab # It is a Hex value that needs to be converted to an integer ${If} $ExistingInstallation == 1 # 32770 is Class name used by all NSIS dialog boxes FindWindow $R0 "#32770" "" $HWNDPARENT # 1019 is the Destination Folder text field (0x3FB) GetDlgItem $R1 $R0 1019 EnableWindow $R1 0 # 1001 is the Browse button (0x3E9) GetDlgItem $R1 $R0 1001 EnableWindow $R1 0 # Disabling the Location Picker causes the buttons to behave incorrectly # Esc and Enter don't work. Nor can you use Alt+N and Alt+B. Setting # the focus to the Next button seems to fix this # Set focus on Next button (0x1) # Next=1, cancel=2, back=3 GetDlgItem $R1 $HWNDPARENT 1 SendMessage $HWNDPARENT ${WM_NEXTDLGCTL} $R1 1 ${EndIf} FunctionEnd ############################################################################### # Minion Settings Dialog Box ############################################################################### Function pageMinionConfig # Set Page Title and Description !insertmacro MUI_HEADER_TEXT "Minion Settings" "Set the Minion Master and ID" nsDialogs::Create 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} # Master IP or Hostname Dialog Control ${NSD_CreateLabel} 0 0 100% 9u "&Master IP or Hostname:" Pop $Label ${NSD_CreateText} 0 10u 100% 12u $MasterHost Pop $MasterHost_TxtBox # Minion ID Dialog Control ${NSD_CreateLabel} 0 30u 100% 9u "Minion &Name:" Pop $Label ${NSD_CreateText} 0 40u 100% 12u $MinionName Pop $MinionName_TxtBox # Config Drop List ${NSD_CreateDropList} 0 60u 25% 36u "" Pop $ConfigType_DropList ${NSD_CB_AddString} $ConfigType_DropList "Default Config" ${NSD_CB_AddString} $ConfigType_DropList "Custom Config" ${NSD_OnChange} $ConfigType_DropList pageMinionConfig_OnChange # Add Existing Config Warning Label ${NSD_CreateLabel} 0 75u 100% 50u \ "The values above are taken from an existing configuration found in \ `$RootDir\conf\minion`.$\n\ $\n\ Clicking `Install` will leave the existing config unchanged." Pop $ExistingConfigWarning_Lbl CreateFont $0 "Arial" 10 500 /ITALIC SendMessage $ExistingConfigWarning_Lbl ${WM_SETFONT} $0 1 SetCtlColors $ExistingConfigWarning_Lbl 0xBB0000 transparent # Add Checkbox to move root_dir ${NSD_CreateCheckBox} 0 125u 100% 10u \ "Move &existing root directory (C:\salt) to %ProgramData%\Salt." Pop $MoveExistingConfig_ChkBox CreateFont $0 "Arial" 10 500 SendMessage $MoveExistingConfig_ChkBox ${WM_SETFONT} $0 1 ${If} $MoveExistingConfig == 1 ${NSD_Check} $MoveExistingConfig_ChkBox ${EndIf} # Add Default Config Warning Label ${NSD_CreateLabel} 0 75u 100% 60u "Clicking `Install` will backup the \ existing minion config file and minion.d directories. The values \ above will be used in the new default config.$\n\ $\n\ NOTE: If Master IP is set to `salt` and Minion Name is set to \ `hostname` no changes will be made." Pop $DefaultConfigWarning_Lbl CreateFont $0 "Arial" 10 500 /ITALIC SendMessage $DefaultConfigWarning_Lbl ${WM_SETFONT} $0 1 SetCtlColors $DefaultConfigWarning_Lbl 0xBB0000 transparent # Add Custom Config File Selector and Warning Label ${NSD_CreateText} 26% 60u 64% 12u $CustomConfig Pop $CustomConfig_TxtBox ${NSD_CreateButton} 91% 60u 9% 12u "..." Pop $CustomConfig_Btn ${NSD_OnClick} $CustomConfig_Btn pageCustomConfigBtn_OnClick ${If} $ExistingConfigFound == 0 ${NSD_CreateLabel} 0 75u 100% 60u \ "Values entered above will be used in the custom config.$\n\ $\n\ NOTE: If Master IP is set to `salt` and Minion Name is set to \ `hostname` no changes will be made." ${Else} ${NSD_CreateLabel} 0 75u 100% 60u \ "Clicking `Install` will backup the existing minion config \ file and minion.d directories. The values above will be used in \ the custom config.$\n\ $\n\ NOTE: If Master IP is set to `salt` and Minion Name is set to \ `hostname` no changes will be made." ${Endif} Pop $CustomConfigWarning_Lbl CreateFont $0 "Arial" 10 500 /ITALIC SendMessage $CustomConfigWarning_Lbl ${WM_SETFONT} $0 1 SetCtlColors $CustomConfigWarning_Lbl 0xBB0000 transparent # If existing config found, add the Existing Config option to the Drop List # If not, hide the Default Warning ${If} $ExistingConfigFound == 1 ${NSD_CB_AddString} $ConfigType_DropList "Existing Config" ${Else} ShowWindow $DefaultConfigWarning_Lbl ${SW_HIDE} ${Endif} ${NSD_CB_SelectString} $ConfigType_DropList $ConfigType ${NSD_SetText} $CustomConfig_TxtBox $CustomConfig Call pageMinionConfig_OnChange nsDialogs::Show FunctionEnd Function pageMinionConfig_OnChange # You have to pop the top handle to keep the stack clean Pop $R0 # Assign the current checkbox state to the variable ${NSD_GetText} $ConfigType_DropList $ConfigType # Update Dialog ${Switch} $ConfigType ${Case} "Existing Config" # Enable Master/Minion and set values EnableWindow $MasterHost_TxtBox 0 EnableWindow $MinionName_TxtBox 0 ${NSD_SetText} $MasterHost_TxtBox $MasterHost_Cfg ${NSD_SetText} $MinionName_TxtBox $MinionName_Cfg # Hide Custom File Picker ShowWindow $CustomConfig_TxtBox ${SW_HIDE} ShowWindow $CustomConfig_Btn ${SW_HIDE} # Hide Warnings ShowWindow $DefaultConfigWarning_Lbl ${SW_HIDE} ShowWindow $CustomConfigWarning_Lbl ${SW_HIDE} # Show Existing Warning ShowWindow $ExistingConfigWarning_Lbl ${SW_SHOW} ${If} $RootDir == "C:\salt" ShowWindow $MoveExistingConfig_ChkBox ${SW_SHOW} ${Else} ShowWindow $MoveExistingConfig_ChkBox ${SW_HIDE} ${EndIf} ${Break} ${Case} "Custom Config" # Enable Master/Minion and set values EnableWindow $MasterHost_TxtBox 1 EnableWindow $MinionName_TxtBox 1 ${NSD_SetText} $MasterHost_TxtBox $MasterHost ${NSD_SetText} $MinionName_TxtBox $MinionName # Show Custom File Picker ShowWindow $CustomConfig_TxtBox ${SW_SHOW} ShowWindow $CustomConfig_Btn ${SW_SHOW} # Hide Warnings ShowWindow $DefaultConfigWarning_Lbl ${SW_HIDE} ShowWindow $ExistingConfigWarning_Lbl ${SW_HIDE} ShowWindow $MoveExistingConfig_ChkBox ${SW_HIDE} # Show Custom Warning ShowWindow $CustomConfigWarning_Lbl ${SW_SHOW} ${Break} ${Case} "Default Config" # Enable Master/Minion and set values EnableWindow $MasterHost_TxtBox 1 EnableWindow $MinionName_TxtBox 1 ${NSD_SetText} $MasterHost_TxtBox $MasterHost ${NSD_SetText} $MinionName_TxtBox $MinionName # Hide Custom File Picker ShowWindow $CustomConfig_TxtBox ${SW_HIDE} ShowWindow $CustomConfig_Btn ${SW_HIDE} # Hide Warnings ShowWindow $ExistingConfigWarning_Lbl ${SW_HIDE} ShowWindow $MoveExistingConfig_ChkBox ${SW_HIDE} ShowWindow $CustomConfigWarning_Lbl ${SW_HIDE} # Show Default Warning, if there is an existing config ${If} $ExistingConfigFound == 1 ShowWindow $DefaultConfigWarning_Lbl ${SW_SHOW} ${Endif} ${Break} ${EndSwitch} FunctionEnd # File Picker Definitions !define OFN_FILEMUSTEXIST 0x00001000 !define OFN_DONTADDTOREC 0x02000000 !define OPENFILENAME_SIZE_VERSION_400 76 !define OPENFILENAME 'i,i,i,i,i,i,i,i,i,i,i,i,i,i,&i2,&i2,i,i,i,i' Function pageCustomConfigBtn_OnClick Pop $0 System::Call '*(&t${NSIS_MAX_STRLEN})i.s' # Allocate OPENFILENAME.lpstrFile buffer System::Call '*(${OPENFILENAME})i.r0' # Allocate OPENFILENAME struct System::Call '*$0(${OPENFILENAME})(${OPENFILENAME_SIZE_VERSION_400}, \ $hwndparent, , , , , , sr1, ${NSIS_MAX_STRLEN} , , , , \ t"Select Custom Config File", \ ${OFN_FILEMUSTEXIST} | ${OFN_DONTADDTOREC})' # Populate file name field ${NSD_GetText} $CustomConfig_TxtBox $2 System::Call "*$1(&t${NSIS_MAX_STRLEN}r2)" ; Set lpstrFile to the old path (if any) # Open the dialog System::Call 'COMDLG32::GetOpenFileName(ir0)i.r2' # Get file name field ${If} $2 <> 0 System::Call "*$1(&t${NSIS_MAX_STRLEN}.r2)" ${NSD_SetText} $CustomConfig_TxtBox $2 ${EndIf} # Free resources System::Free $1 System::Free $0 FunctionEnd Function pageMinionConfig_Leave # Save the State ${NSD_GetText} $MasterHost_TxtBox $MasterHost ${NSD_GetText} $MinionName_TxtBox $MinionName ${NSD_GetText} $ConfigType_DropList $ConfigType ${NSD_GetText} $CustomConfig_TxtBox $CustomConfig ${NSD_GetState} $MoveExistingConfig_ChkBox $MoveExistingConfig # Abort if config file not found ${If} $ConfigType == "Custom Config" IfFileExists "$CustomConfig" done 0 MessageBox MB_OK|MB_ICONEXCLAMATION \ "File not found: $CustomConfig" \ /SD IDOK Abort ${EndIf} ${If} $MoveExistingConfig == 1 # This makes the $APPDATA variable point to the ProgramData folder # instead of the current user's roaming AppData folder SetShellVarContext all # Get directory status # We don't want to overwrite data in the new location, so it needs to # either be empty or not found. Otherwise, warn and abort ${DirState} "$APPDATA\Salt Project\Salt" $R0 # 0=Empty, 1=full, -1=Not Found StrCmp $R0 "1" 0 done # Move files if directory empty or missing MessageBox MB_OKCANCEL \ "The $APPDATA\Salt Project\Salt directory is not empty.$\n\ These files will need to be moved manually." \ /SD IDOK IDCANCEL cancel # OK: We're continuing without moving existing config StrCpy $MoveExistingConfig 0 Goto done cancel: # Cancel: We're unchecking the checkbox and returning the user to # the dialog box # Abort just returns the user back to the dialog box ${NSD_UNCHECK} $MoveExistingConfig_ChkBox Abort ${EndIf} done: FunctionEnd ############################################################################### # Custom Finish Page ############################################################################### Function pageFinish_Show # Imports so the checkboxes will show up !define SWP_NOSIZE 0x0001 !define SWP_NOMOVE 0x0002 !define HWND_TOP 0x0000 # Create Start Minion Checkbox ${NSD_CreateCheckbox} 120u 90u 100% 12u "&Start salt-minion" Pop $MinionStart_ChkBox SetCtlColors $MinionStart_ChkBox "" "ffffff" # This command required to bring the checkbox to the front System::Call "User32::SetWindowPos(i, i, i, i, i, i, i) b ($MinionStart_ChkBox, ${HWND_TOP}, 0, 0, 0, 0, ${SWP_NOSIZE}|${SWP_NOMOVE})" # Create Start Minion Delayed ComboBox ${NSD_CreateCheckbox} 130u 102u 100% 12u "&Delayed Start" Pop $MinionStartDelayed_ChkBox SetCtlColors $MinionStartDelayed_ChkBox "" "ffffff" # This command required to bring the checkbox to the front System::Call "User32::SetWindowPos(i, i, i, i, i, i, i) b ($MinionStartDelayed_ChkBox, ${HWND_TOP}, 0, 0, 0, 0, ${SWP_NOSIZE}|${SWP_NOMOVE})" # Load current settings for Minion ${If} $StartMinion == 1 ${NSD_Check} $MinionStart_ChkBox ${EndIf} # Load current settings for Minion Delayed ${If} $StartMinionDelayed == 1 ${NSD_Check} $MinionStartDelayed_ChkBox ${EndIf} FunctionEnd Function pageFinish_Leave # Assign the current checkbox states ${NSD_GetState} $MinionStart_ChkBox $StartMinion ${NSD_GetState} $MinionStartDelayed_ChkBox $StartMinionDelayed FunctionEnd ############################################################################### # Installation Settings ############################################################################### Name "${PRODUCT_NAME} ${PRODUCT_VERSION} (${BUILD_TYPE})" OutFile "${OutFile}" InstallDir "C:\Program Files\Salt Project\Salt" InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" "" ShowInstDetails show ShowUnInstDetails show Section -copy_prereqs # Copy prereqs to the Plugins Directory # These files are downloaded by build_pkg.bat # This directory gets removed upon completion SetOutPath "$PLUGINSDIR\" File /r "..\..\prereqs\" SectionEnd # Check and install Visual C++ redist 2022 packages # Hidden section (-) to install VCRedist Section -install_vcredist_2022 ${DisableX64FSRedirection} Var /GLOBAL VcRedistName # Determine which architecture needs to be installed ${if} ${runningx64} strcpy $VcRedistName "vcredist_x64_2022" ${else} strcpy $VcRedistName "vcredist_x86_2022" ${endif} detailPrint "Selected $VcRedistName installer" # Check for the presence of vcruntime140.dll IfFileExists "$WINDIR\System32\vcruntime140.dll" file_found file_not_found: detailPrint "$VcRedistName not found" # Install Call InstallVCRedist Goto end_of_section file_found: detailPrint "$VcRedistName found, install will continue" end_of_section: ${EnableX64FSRedirection} SectionEnd Function InstallVCRedist detailPrint "System requires $VcRedistName" MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 \ "$VcRedistName is currently not installed. Would you like to install?" \ /SD IDYES IDYES InstallVcRedist detailPrint "$VcRedistName not installed" detailPrint ">>>Installation aborted by user<<<" MessageBox MB_ICONEXCLAMATION \ "$VcRedistName not installed. Aborted by user.$\n$\n\ Installer will now close." \ /SD IDOK Quit InstallVcRedist: # If an output variable is specified ($0 in the case below), ExecWait # sets the variable with the exit code (and only sets the error flag if # an error occurs; if an error occurs, the contents of the user # variable are undefined). # http://nsis.sourceforge.net/Reference/ExecWait ClearErrors detailPrint "Installing $VcRedistName..." ExecWait '"$PLUGINSDIR\$VcRedistName.exe" /install /quiet /norestart' $0 IfErrors 0 CheckVcRedistErrorCode detailPrint "An error occurred during installation of $VcRedistName" MessageBox MB_OK|MB_ICONEXCLAMATION \ "$VcRedistName failed to install. Try installing the package \ manually.$\n$\n\ The installer will now close." \ /SD IDOK Quit CheckVcRedistErrorCode: # Check for Reboot Error Code (3010) ${If} $0 == 3010 detailPrint "$VcRedistName installed but requires a restart to complete." detailPrint "Reboot and run Salt install again" MessageBox MB_OK|MB_ICONINFORMATION \ "$VcRedistName installed but requires a restart to complete." \ /SD IDOK # Check for any other errors ${ElseIfNot} $0 == 0 detailPrint "An error occurred during installation of $VcRedistName" detailPrint "Error: $0" MessageBox MB_OK|MB_ICONEXCLAMATION \ "$VcRedistName failed to install. Try installing the package \ mnually.$\n\ ErrorCode: $0$\n\ The installer will now close." \ /SD IDOK ${EndIf} FunctionEnd Section "Install" Install01 ${If} $MoveExistingConfig == 1 ${LogMsg} "Moving existing config to $APPDATA\Salt Project\Salt" # This makes the $APPDATA variable point to the ProgramData folder # instead of the current user's roaming AppData folder ${LogMsg} "Set context to all users" SetShellVarContext all # Make sure the target directory exists ${LogMsg} "Creating rootdir in ProgramData" CreateDirectory "$APPDATA\Salt Project\Salt" # Take ownership of the C:\salt directory ${LogMsg} "Taking ownership: $RootDir" nsExec::ExecToStack "takeown /F $RootDir /R" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} # Move the C:\salt directory to the new location StrCpy $switch_overwrite 0 ${If} ${FileExists} "$RootDir\conf\*.*" ${LogMsg} "Moving $RootDir\conf to $APPDATA" !insertmacro MoveFolder "$RootDir\conf" "$APPDATA\Salt Project\Salt\conf" "*.*" ${EndIf} ${If} ${FileExists} "$RootDir\srv\*.*" ${LogMsg} "Moving $RootDir\srv to $APPDATA" !insertmacro MoveFolder "$RootDir\srv" "$APPDATA\Salt Project\Salt\srv" "*.*" ${EndIf} ${If} ${FileExists} "$RootDir\var\*.*" ${LogMsg} "Moving $RootDir\var to $APPDATA" !insertmacro MoveFolder "$RootDir\var" "$APPDATA\Salt Project\Salt\var" "*.*" ${EndIf} # Make RootDir the new location StrCpy $RootDir "$APPDATA\Salt Project\Salt" ${EndIf} ${If} $ConfigType != "Existing Config" Call BackupExistingConfig ${EndIf} # Install files to the Installation Directory ${LogMsg} "Setting outpath to $INSTDIR" SetOutPath "$INSTDIR\" ${LogMsg} "Setting Overwrite off" SetOverwrite off ${LogMsg} "Copying files" File /r "..\..\buildenv\" # Set up Root Directory ${LogMsg} "Creating directory structure" CreateDirectory "$RootDir\conf\pki\minion" CreateDirectory "$RootDir\conf\minion.d" CreateDirectory "$RootDir\var\cache\salt\minion\extmods\grains" CreateDirectory "$RootDir\var\cache\salt\minion\proc" CreateDirectory "$RootDir\var\log\salt" CreateDirectory "$RootDir\var\run" ${LogMsg} "Setting permissions on RootDir" nsExec::ExecToStack 'icacls "$RootDir" /inheritance:r /grant:r "*S-1-5-32-544":(OI)(CI)F /grant:r "*S-1-5-18":(OI)(CI)F' pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} SectionEnd Function .onInit # This function gets executed before any other. This is where we will # detect existing installations and config to be used by the installer ${LogMsg} "Running ${OUTFILE}" # Make sure we do not allow 32-bit Salt on 64-bit systems # This is the system the installer is running on ${If} ${RunningX64} # This is the Python architecture the installer was built with ${If} ${CPUARCH} == "x86" StrCpy $msg "Detected 64-bit Operating system.$\n\ Please install the 64-bit version of Salt on this operating system." ${LogMsg} $msg MessageBox MB_OK|MB_ICONEXCLAMATION $msg /SD IDOK ${LogMsg} "Aborting" Abort ${EndIf} ${Else} # This is the Python architecture the installer was built with ${If} ${CPUARCH} == "AMD64" StrCpy $msg "Detected 32-bit Operating system.$\n\ Please install the 32-bit version of Salt on this operating system." ${LogMsg} $msg MessageBox MB_OK|MB_ICONEXCLAMATION $msg /SD IDOK ${LogMsg} "Aborting" Abort ${EndIf} ${EndIf} InitPluginsDir Call parseInstallerCommandLineSwitches # Uninstall msi-installed salt # Source: https://nsis-dev.github.io/NSIS-Forums/html/t-303468.html !define upgradecode {FC6FB3A2-65DE-41A9-AD91-D10A402BD641} # Salt upgrade code StrCpy $0 0 ${LogMsg} "Looking for MSI installation" loop: System::Call 'MSI::MsiEnumRelatedProducts(t "${upgradecode}",i0,i r0,t.r1)i.r2' ${If} $2 = 0 # Now $1 contains the product code ${LogMsg} product:$1 push $R0 StrCpy $R0 $1 Call UninstallMSI pop $R0 IntOp $0 $0 + 1 goto loop ${Endif} # If a custom config is passed on the CLI, verify its existence before # continuing so we don't uninstall an existing installation and then fail # NOTE: This handles custom config for silent installations where the # NOTE: custom config is passed on the CLI. The GUI has its own checking # NOTE: when the user selects a custom config. ${If} $ConfigType == "Custom Config" ${LogMsg} "Verifying custom config" ${If} ${FileExists} "$CustomConfig" ${LogMsg} "Found full path to custom config: $CustomConfig" Goto checkExistingInstallation ${EndIf} ${If} ${FileExists} "$EXEDIR\$CustomConfig" ${LogMsg} "Found custom config with the install binary: $CustomConfig" Goto checkExistingInstallation ${EndIf} ${LogMsg} "Custom config not found. Aborting" Abort ${EndIf} checkExistingInstallation: # Check for existing installation ${LogMsg} "Checking for existing installation" # The NSIS installer is a 32bit application and will use the WOW6432Node # in the registry by default. We need to look in the 64 bit location on # 64 bit systems ${If} ${RunningX64} ${LogMsg} "Setting registry context to 64-bit" # https://nsis.sourceforge.io/Docs/Chapter4.html#setregview SetRegView 64 # View the 64 bit portion of the registry ${LogMsg} "Reading uninstall string" ReadRegStr $R0 HKLM \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ "UninstallString" # Puts the nullsoft installer back to its default ${LogMsg} "Setting registry context to 32-bit" SetRegView 32 # Set it back to the 32 bit portion of the registry ${Else} ${LogMsg} "Reading uninstall string" ReadRegStr $R0 HKLM \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ "UninstallString" ${EndIf} # If it's empty it's not installed StrCmp $R0 "" skipUninstall # Set InstDir to the parent directory so that we can uninstall it ${GetParent} $R0 $INSTDIR ${LogMsg} "Found existing installation at $R0" # Found existing installation, prompt to uninstall StrCpy $msg "${PRODUCT_NAME} is already installed.$\n\ Click `OK` to remove the existing installation." ${LogMsg} $msg MessageBox MB_OKCANCEL|MB_USERICON $msg /SD IDOK IDOK uninst ${LogMsg} "Aborting" Abort uninst: # Get current Silent status ${LogMsg} "Getting current silent setting" StrCpy $R0 0 ${If} ${Silent} StrCpy $R0 1 ${EndIf} # Turn on Silent mode ${LogMsg} "Setting to silent mode" SetSilent silent # Don't remove all directories when upgrading (old method) ${LogMsg} "Setting uninstaller to not delete the install dir" StrCpy $DeleteInstallDir 0 # Don't remove RootDir when upgrading (new method) ${LogMsg} "Setting uninstaller to not delete the root dir" StrCpy $DeleteRootDir 0 # Uninstall silently Call uninstallSalt ${LogMsg} "Resetting silent setting to original" # Set it back to Normal mode, if that's what it was before ${If} $R0 == 0 SetSilent normal ${EndIf} skipUninstall: Call getExistingInstallation Call getExistingMinionConfig ${If} $ExistingConfigFound == 0 ${AndIf} $ConfigType == "Existing Config" ${LogMsg} "Existing config not found, using Default config" StrCpy $ConfigType "Default Config" ${EndIf} FunctionEnd Function BackupExistingConfig ${If} $ExistingConfigFound == 1 # If existing config found ${AndIfNot} $ConfigType == "Existing Config" # If not using Existing Config # Backup the minion config ${If} ${FileExists} "$RootDir\conf\minion" ${LogMsg} "Renaming existing config file" Rename "$RootDir\conf\minion" "$RootDir\conf\minion-$TimeStamp.bak" ${EndIf} ${If} ${FileExists} "$RootDir\conf\minion.d\*.*" ${LogMsg} "Renaming existing config directory" Rename "$RootDir\conf\minion.d" "$RootDir\conf\minion.d-$TimeStamp.bak" ${EndIf} ${EndIf} # By this point there should be no existing config. It was either backed up # or wasn't there to begin with ${If} $ConfigType == "Custom Config" # If we're using Custom Config ${AndIfNot} $CustomConfig == "" # If a custom config is passed # Check for a file name # Named file should be in the same directory as the installer ${LogMsg} "Make sure config directory is exists" ${LogMsg} "Path: $RootDir\conf" CreateDirectory "$RootDir\conf" ${If} ${FileExists} "$EXEDIR\$CustomConfig" ${LogMsg} "Copying custom config from path relative to installer" ${LogMsg} "Path: $EXEDIR\$CustomConfig" CopyFiles /SILENT /FILESONLY "$EXEDIR\$CustomConfig" "$RootDir\conf\minion" ${ElseIf} ${FileExists} "$CustomConfig" ${LogMsg} "Copying custom config from full path" ${LogMsg} "Path: $CustomConfig" CopyFiles /SILENT /FILESONLY "$CustomConfig" "$RootDir\conf\minion" ${Else} ${LogMsg} "Custom config not found, default values will be used" ${EndIf} ${EndIf} FunctionEnd Section -Post ${LogMsg} "Writing uninstaller" WriteUninstaller "$INSTDIR\uninst.exe" # The NSIS installer is a 32bit application and will use the WOW6432Node in # the registry by default. We need to look in the 64 bit location on 64 bit # systems ${If} ${RunningX64} # https://nsis.sourceforge.io/Docs/Chapter4.html#setregview ${LogMsg} "Setting registry context to 64-bit registry" SetRegView 64 # View 64 bit portion of the registry ${EndIf} ${LogMsg} "Updating installation information in the registry" # Write Uninstall Registry Entries WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ "DisplayName" "$(^Name)" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ "UninstallString" "$INSTDIR\uninst.exe" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ "DisplayIcon" "$INSTDIR\salt.ico" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ "DisplayVersion" "${PRODUCT_VERSION}" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ "URLInfoAbout" "${PRODUCT_WEB_SITE}" WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ "Publisher" "${PRODUCT_PUBLISHER}" WriteRegStr HKLM "SYSTEM\CurrentControlSet\services\salt-minion" \ "DependOnService" "nsi" ${LogMsg} "Getting estimated size" # If ESTIMATED_SIZE is not set, calculated it ${If} ${ESTIMATED_SIZE} == 0 ${GetSize} "$INSTDIR" "/S=OK" $R0 $R1 $R2 ${Else} StrCpy $R0 ${ESTIMATED_SIZE} ${Endif} IntFmt $R0 "0x%08X" $R0 ${LogMsg} "Setting estimated size: $R0" WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ "EstimatedSize" "$R0" # Write Commandline Registry Entries ${LogMsg} "Registering salt commands for the cli" WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "" "$INSTDIR\salt-call.exe" WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "Path" "$INSTDIR\" WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "" "$INSTDIR\salt-minion.exe" WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "Path" "$INSTDIR\" # Write Salt Configuration Registry Entries # We want to write EXPAND_SZ string types to allow us to use environment # variables. It's OK to use EXPAND_SZ even if you don't use an environment # variable so we'll just do that whether it's new location or old. # Check for Program Files # We want to use the environment variables instead of the hardcoded path # when setting values in the registry ${LogMsg} "Getting registry values for install_dir and root_dir" ${If} ${RunningX64} ${StrRep} "$RegInstDir" "$INSTDIR" "$ProgramFiles64" "%PROGRAMFILES%" ${Else} ${StrRep} "$RegInstDir" "$INSTDIR" "$ProgramFiles" "%PROGRAMFILES%" ${EndIf} ${LogMsg} "install_dir: $RegInstDir" SetShellVarContext all ${StrRep} "$RegRootDir" "$RootDir" "$APPDATA" "%PROGRAMDATA%" ${LogMsg} "root_dir: $RegRootDir" ${LogMsg} "Writing install_dir and root_dir to the registry" WriteRegExpandStr HKLM "SOFTWARE\Salt Project\Salt" "install_dir" "$RegInstDir" WriteRegExpandStr HKLM "SOFTWARE\Salt Project\Salt" "root_dir" "$RegRootDir" # Puts the nullsoft installer back to its default ${LogMsg} "Setting registry context back to 32-bit" SetRegView 32 # Set it back to the 32 bit portion of the registry # Register the Salt-Minion Service ${LogMsg} "Registering the salt-minion service" nsExec::ExecToStack `"$INSTDIR\ssm.exe" install salt-minion "$INSTDIR\salt-minion.exe" -c """$RootDir\conf""" -l quiet` pop $0 # ExitCode pop $1 # StdOut ${IfNot} $0 == 0 StrCpy $msg "Failed to register the salt minion service.$\n\ ExitCode: $0$\n\ StdOut: $1" ${LogMsg} $msg MessageBox MB_OK|MB_ICONEXCLAMATION $msg /SD IDOK IDOK ${LogMsg} "Aborting" Abort ${Else} ${LogMsg} "Setting service description" nsExec::ExecToStack "$INSTDIR\ssm.exe set salt-minion Description Salt Minion from saltstack.com" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} ${LogMsg} "Setting service autostart" nsExec::ExecToStack "$INSTDIR\ssm.exe set salt-minion Start SERVICE_AUTO_START" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} ${LogMsg} "Setting service console stop method" nsExec::ExecToStack "$INSTDIR\ssm.exe set salt-minion AppStopMethodConsole 24000" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} ${LogMsg} "Setting service windows stop method" nsExec::ExecToStack "$INSTDIR\ssm.exe set salt-minion AppStopMethodWindow 2000" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} ${LogMsg} "Setting service app restart delay" nsExec::ExecToStack "$INSTDIR\ssm.exe set salt-minion AppRestartDelay 60000" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} ${EndIf} # There is a default minion config laid down in the $INSTDIR directory ${Switch} $ConfigType ${Case} "Existing Config" ${LogMsg} "Using existing config" # If this is an Existing Config, we don't do anything ${Break} ${Case} "Custom Config" ${LogMsg} "Using custom config" # If this is a Custom Config, update the custom config Call updateMinionConfig ${Break} ${Case} "Default Config" ${LogMsg} "Using default config" # If this is the Default Config, we move it and update it StrCpy $switch_overwrite 1 !insertmacro MoveFolder "$INSTDIR\configs" "$RootDir\conf" "*.*" Call updateMinionConfig ${Break} ${EndSwitch} # Delete the configs directory that came with the installer ${LogMsg} "Removing configs directory" RMDir /r "$INSTDIR\configs" # Add $INSTDIR in the Path ${LogMsg} "Adding salt to the path" EnVar::SetHKLM EnVar::AddValue Path "$INSTDIR" Pop $0 ${If} $0 == 0 ${LogMsg} "Success" ${Else} # See this table for Error Codes: # https://github.com/GsNSIS/EnVar#error-codes ${LogMsg} "Failed. Error Code: $0" ${EndIf} SectionEnd Function .onInstSuccess # If StartMinionDelayed is 1, then set the service to start delayed ${If} $StartMinionDelayed == 1 ${LogMsg} "Setting the salt-minion service to start delayed" nsExec::ExecToStack "$INSTDIR\ssm.exe set salt-minion Start SERVICE_DELAYED_AUTO_START" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} ${EndIf} # If start-minion is 1, then start the service ${If} $StartMinion == 1 ${LogMsg} "Starting the salt-minion service" nsExec::ExecToStack "$INSTDIR\ssm.exe start salt-minion" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} ${EndIf} ${LogMsg} "Salt installation complete" # I don't know of another way to fix this. The installer hangs intermittently # This will force kill the installer process. This must be the last thing that # is run. StrCpy $1 "wmic Path win32_process where $\"name like '$EXEFILE'$\" Call Terminate" nsExec::Exec $1 FunctionEnd Function un.onInit Call un.parseUninstallerCommandLineSwitches StrCpy $msg "Are you sure you want to completely remove $(^Name) and all \ of its components?" ${LogMsg} $msg MessageBox MB_USERICON|MB_YESNO|MB_DEFBUTTON1 $msg /SD IDYES IDYES continue_remove ${LogMsg} "Aborting" Abort continue_remove: FunctionEnd Section Uninstall Call un.uninstallSalt # Remove $INSTDIR from the Path ${LogMsg} "Removing salt from the path" EnVar::SetHKLM EnVar::DeleteValue Path "$INSTDIR" Pop $0 ${If} $0 == 0 ${LogMsg} "Success" ${Else} # See this table for Error Codes: # https://github.com/GsNSIS/EnVar#error-codes ${LogMsg} "Failed. Error Code: $0" ${EndIf} SectionEnd !macro uninstallSalt un Function ${un}uninstallSalt # WARNING: Any changes made here need to be reflected in the MSI uninstaller # Make sure we're in the right directory ${LogMsg} "Detecting INSTDIR" ${If} $INSTDIR == "c:\salt\Scripts" StrCpy $INSTDIR "C:\salt" ${EndIf} # $ProgramFiles is different depending on the CPU Architecture # https://nsis.sourceforge.io/Reference/$PROGRAMFILES # x86 : C:\Program Files # x64 : C:\Program Files (x86) ${If} $INSTDIR == "$ProgramFiles\Salt Project\Salt\Scripts" StrCpy $INSTDIR "$ProgramFiles\Salt Project\Salt" ${EndIf} # $ProgramFiles64 is the C:\Program Files directory ${If} $INSTDIR == "$ProgramFiles64\Salt Project\Salt\Scripts" StrCpy $INSTDIR "$ProgramFiles64\Salt Project\Salt" ${EndIf} ${LogMsg} "INSTDIR: $INSTDIR" # Only attempt to remove the services if ssm.exe is present" ${If} ${FileExists} "$INSTDIR\ssm.exe" ${LogMsg} "ssm.exe found" # Stop and Remove salt-minion service ${LogMsg} "Stopping salt-minion service" nsExec::ExecToStack "$INSTDIR\ssm.exe stop salt-minion" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" ${EndIf} ${LogMsg} "Removing salt-minion service" nsExec::ExecToStack "$INSTDIR\ssm.exe remove salt-minion confirm" pop $0 # ExitCode pop $1 # StdOut ${If} $0 == 0 ${LogMsg} "Success" ${Else} ${LogMsg} "Failed$\r$\nExitCode: $0$\r$\nStdOut: $1" Abort ${EndIf} ${Else} ${LogMsg} "ssm.exe not found" ${EndIf} # Remove files ${LogMsg} "Deleting individual files" Delete "$INSTDIR\multi-minion*" Delete "$INSTDIR\salt*" Delete "$INSTDIR\ssm.exe" Delete "$INSTDIR\uninst.exe" Delete "$INSTDIR\vcredist.exe" ${LogMsg} "Deleting directories" RMDir /r "$INSTDIR\DLLs" RMDir /r "$INSTDIR\Include" RMDir /r "$INSTDIR\Lib" RMDir /r "$INSTDIR\libs" RMDir /r "$INSTDIR\Scripts" # Remove everything in the 64 bit registry # The NSIS installer is a 32bit application and will use the WOW6432Node in # the registry by default. We need to look in the 64 bit location on 64 bit # systems ${If} ${RunningX64} ${LogMsg} "Removing 64-bit registry items" # https://nsis.sourceforge.io/Docs/Chapter4.html#setregview SetRegView 64 # View the 64 bit portion of the registry ${EndIf} ${LogMsg} "Getting RootDir from 64-bit registry" # Get Root Directory from the Registry (64 bit) ReadRegStr $RootDir HKLM "SOFTWARE\Salt Project\Salt" "root_dir" ${LogMsg} "RootDir: $RootDir" # Remove Registry entries ${LogMsg} "Deleting Add/Remove programs entries" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" # Remove Command Line Registry entries ${LogMsg} "Deleting Command Line Registry Entries" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_CALL_REGKEY}" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_CP_REGKEY}" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_KEY_REGKEY}" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_MASTER_REGKEY}" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_MINION_REGKEY}" DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_RUN_REGKEY}" DeleteRegKey HKLM "SOFTWARE\Salt Project" # SystemDrive is not a built in NSIS constant, so we need to get it from # the environment variables ${LogMsg} "Getting System Drive" ReadEnvStr $0 "SystemDrive" # Get the SystemDrive env var StrCpy $SysDrive "$0\" ${LogMsg} "SystemDrive: $SysDrive" # Automatically close when finished SetAutoClose true # Old Method Installation ${If} $INSTDIR == "C:\salt" # Prompt to remove the Installation Directory. This is because that # directory is also the root_dir which includes the config and pki # directories ${IfNot} $DeleteInstallDir == 1 StrCpy $msg "Would you like to completely remove $INSTDIR and all \ of its contents?" ${LogMsg} $msg MessageBox MB_YESNO|MB_DEFBUTTON2|MB_USERICON $msg /SD IDNO IDNO finished ${EndIf} ${LogMsg} "Removing INSTDIR" SetOutPath "$SysDrive" # Can't remove CWD RMDir /r "$INSTDIR" ${Else} # Prompt for the removal of the Installation Directory which contains # the extras directory and the Root Directory which contains the config # and pki directories. These directories will not be removed during # an upgrade. ${IfNot} $DeleteRootDir == 1 StrCpy $msg "Would you like to completely remove the entire Salt \ Installation? This includes the following:$\n\ - Extra Pip Packages ($INSTDIR\extras-3.##)$\n\ - Minion Config ($RootDir\conf)$\n\ - Minion PKIs ($RootDir\conf\pki)" ${LogMsg} $msg MessageBox MB_YESNO|MB_DEFBUTTON2|MB_USERICON $msg /SD IDNO IDNO finished ${EndIf} # New Method Installation # This makes the $APPDATA variable point to the ProgramData folder instead # of the current user's roaming AppData folder ${LogMsg} "Setting Shell Context to All Users" SetShellVarContext all # We can always remove the Installation Directory on New Method Installs # because it only contains binary data # Remove INSTDIR # Make sure you're not removing important system directory such as # Program Files, C:\Windows, or C: ${If} $INSTDIR != $ProgramFiles ${AndIf} $INSTDIR != $ProgramFiles64 ${AndIf} $INSTDIR != $SysDrive ${AndIf} $INSTDIR != $WinDir ${LogMsg} "Removing INSTDIR" SetOutPath "$SysDrive" # Can't remove CWD RMDir /r $INSTDIR ${EndIf} # Remove INSTDIR (The parent) # For example, though salt is installed in ProgramFiles\Salt Project\Salt # We want to remove ProgramFiles\Salt Project # Only delete Salt Project directory if it's in Program Files # Otherwise, we can't guess where the user may have installed salt ${LogMsg} "Getting InstDir Parent Directory" ${GetParent} $INSTDIR $R0 # Get parent directory (Salt Project) ${LogMsg} "Parent: $R0" ${If} $R0 == "$ProgramFiles\Salt Project" # Make sure it's ProgramFiles ${OrIf} $R0 == "$ProgramFiles64\Salt Project" # Make sure it's Program Files (x86) ${LogMsg} "Removing Salt Project directory from Program Files" SetOutPath "$SysDrive" # Can't remove CWD RMDir /r $R0 ${EndIf} # If RootDir is still empty, use C:\salt ${If} $RootDir == "" StrCpy $RootDir "C:\salt" ${EndIf} # Expand any environment variables ExpandEnvStrings $RootDir $RootDir ${LogMsg} "Removing RootDir: $RootDir" # Remove the Salt Project directory in ProgramData # The Salt Project directory will only ever be in ProgramData # It is not user selectable ${LogMsg} "Getting RootDir Parent Directory" ${GetParent} $RootDir $R0 # Get parent directory ${LogMsg} "Parent: $R0" ${If} $R0 == "$APPDATA\Salt Project" # Make sure it's not ProgramData ${LogMsg} "Removing Parent Directory from APPDATA" SetOutPath "$SysDrive" # Can't remove CWD RMDir /r $R0 ${EndIf} ${EndIf} finished: ${LogMsg} "Uninstall Complete" FunctionEnd !macroend !insertmacro uninstallSalt "" !insertmacro uninstallSalt "un." Function un.onUninstSuccess HideWindow StrCpy $msg "$(^Name) was successfully removed from your computer." ${LogMsg} $msg MessageBox MB_OK|MB_USERICON $msg /SD IDOK # I don't know of another way to fix this. The installer hangs intermittently # This will force kill the installer process. This must be the last thing that # is run. StrCpy $1 "wmic Path win32_process where $\"name like '$EXEFILE'$\" Call Terminate" nsExec::Exec $1 FunctionEnd ############################################################################### # Helper Functions ############################################################################### #------------------------------------------------------------------------------ # Trim Function # - Trim whitespace from the beginning and end of a string # - Trims spaces, \r, \n, \t # # Usage: # Push " some string " ; String to Trim # Call Trim # Pop $0 ; Trimmed String: "some string" # # or # # ${Trim} $0 $1 ; Trimmed String, String to Trim #------------------------------------------------------------------------------ !macro Func_Trim un Function ${un}Trim Exch $R1 # Original string Push $R2 Loop: StrCpy $R2 "$R1" 1 StrCmp "$R2" " " TrimLeft StrCmp "$R2" "$\r" TrimLeft StrCmp "$R2" "$\n" TrimLeft StrCmp "$R2" "$\t" TrimLeft GoTo Loop2 TrimLeft: StrCpy $R1 "$R1" "" 1 Goto Loop Loop2: StrCpy $R2 "$R1" 1 -1 StrCmp "$R2" " " TrimRight StrCmp "$R2" "$\r" TrimRight StrCmp "$R2" "$\n" TrimRight StrCmp "$R2" "$\t" TrimRight GoTo Done TrimRight: StrCpy $R1 "$R1" -1 Goto Loop2 Done: Pop $R2 Exch $R1 FunctionEnd !macroend !insertmacro Func_Trim "" !insertmacro Func_Trim "un." #------------------------------------------------------------------------------ # Explode Function # - Splits a string based off the passed separator # - Each item in the string is pushed to the stack # - The last item pushed to the stack is the length of the array # # Usage: # Push "," ; Separator # Push "string,to,separate" ; String to explode # Call Explode # Pop $0 ; Number of items in the array # # or # # ${Explode} $0 $1 $2 ; Length, Separator, String #------------------------------------------------------------------------------ Function Explode # Initialize variables Var /GLOBAL explString Var /GLOBAL explSeparator Var /GLOBAL explStrLen Var /GLOBAL explSepLen Var /GLOBAL explOffset Var /GLOBAL explTmp Var /GLOBAL explTmp2 Var /GLOBAL explTmp3 Var /GLOBAL explArrCount # Get input from user Pop $explString Pop $explSeparator # Calculates initial values StrLen $explStrLen $explString StrLen $explSepLen $explSeparator StrCpy $explArrCount 1 ${If} $explStrLen <= 1 # If we got a single character ${OrIf} $explSepLen > $explStrLen # or separator is larger than the string, Push $explString # then we return initial string with no change Push 1 # and set array's length to 1 Return ${EndIf} # Set offset to the last symbol of the string StrCpy $explOffset $explStrLen IntOp $explOffset $explOffset - 1 # Clear temp string to exclude the possibility of appearance of occasional data StrCpy $explTmp "" StrCpy $explTmp2 "" StrCpy $explTmp3 "" # Loop until the offset becomes negative ${Do} # If offset becomes negative, it is time to leave the function ${IfThen} $explOffset == -1 ${|} ${ExitDo} ${|} # Remove everything before and after the searched part ("TempStr") StrCpy $explTmp $explString $explSepLen $explOffset ${If} $explTmp == $explSeparator # Calculating offset to start copy from IntOp $explTmp2 $explOffset + $explSepLen # Offset equals to the current offset plus length of separator StrCpy $explTmp3 $explString "" $explTmp2 Push $explTmp3 # Throwing array item to the stack IntOp $explArrCount $explArrCount + 1 # Increasing array's counter StrCpy $explString $explString $explOffset 0 # Cutting all characters beginning with the separator entry StrLen $explStrLen $explString ${EndIf} ${If} $explOffset = 0 # If the beginning of the line met and there is no separator, # copying the rest of the string ${If} $explSeparator == "" # Fix for the empty separator IntOp $explArrCount $explArrCount - 1 ${Else} Push $explString ${EndIf} ${EndIf} IntOp $explOffset $explOffset - 1 ${Loop} Push $explArrCount FunctionEnd #------------------------------------------------------------------------------ # UninstallMSI Function # - Uninstalls MSI by product code # # Usage: # Push product code # Call UninstallMSI # # Source: # https://nsis.sourceforge.io/Uninstalling_a_previous_MSI_(Windows_installer_package) #------------------------------------------------------------------------------ Function UninstallMSI ; $R0 === product code MessageBox MB_OKCANCEL|MB_ICONINFORMATION \ "${PRODUCT_NAME} is already installed via MSI.$\n$\n\ Click `OK` to remove the existing installation." \ /SD IDOK IDOK UninstallMSI Abort UninstallMSI: ExecWait '"msiexec.exe" /x $R0 /qb /quiet /norestart' FunctionEnd ############################################################################### # Specialty Functions ############################################################################### Function getExistingInstallation # Try to detect an existing installation. There are three possible scenarios # 1. Existing New Method Installation # 2. Existing Old Method Installation # 3. New Installation # The results of this function will determine if the user is allowed to set # the install location in the GUI. If there is an existing installation # present, the location picker will be grayed out # This function also sets the RootDir and INSTDIR variables used by the # installer. ${LogMsg} "Detecting existing installation" # Reset ExistingInstallation StrCpy $ExistingInstallation 0 # Get ProgramFiles # Use RunningX64 here to get the Architecture for the system running the # installer. # There are 3 scenarios here: ${LogMsg} "Setting Default InstDir" ${If} ${RunningX64} StrCpy $INSTDIR "$ProgramFiles64\Salt Project\Salt" ${Else} # 32 bit Salt on 32 bit system (C:\Program Files) StrCpy $INSTDIR "$ProgramFiles\Salt Project\Salt" ${EndIf} # This makes the $APPDATA variable point to the ProgramData folder instead # of the current user's roaming AppData folder SetShellVarContext all # Set default location of for salt config ${LogMsg} "Setting Default RootDir" StrCpy $RootDir "$APPDATA\Salt Project\Salt" # The NSIS installer is a 32bit application and will use the WOW6432Node in # the registry by default. We need to look in the 64 bit location on 64 bit # systems ${If} ${RunningX64} # https://nsis.sourceforge.io/Docs/Chapter4.html#setregview SetRegView 64 # View the 64 bit portion of the registry ${EndIf} # Check for existing new method installation from registry ${LogMsg} "Looking for New Method installation" # Look for `install_dir` in HKLM\SOFTWARE\Salt Project\Salt ${LogMsg} "Getting INSTDIR from Registry" ReadRegStr $R0 HKLM "SOFTWARE\Salt Project\Salt" "install_dir" StrCmp $R0 "" checkOldInstallation ${LogMsg} "Detected existing installation" StrCpy $ExistingInstallation 1 # Set INSTDIR to the location in the registry StrCpy $INSTDIR $R0 # Expand any environment variables it contains ExpandEnvStrings $INSTDIR $INSTDIR ${LogMsg} "INSTDIR: $INSTDIR" # Set RootDir, if defined ${LogMsg} "Getting RootDir" ReadRegStr $R0 HKLM "SOFTWARE\Salt Project\Salt" "root_dir" StrCmp $R0 "" finished StrCpy $RootDir $R0 # Expand any environment variables it contains ExpandEnvStrings $RootDir $RootDir ${LogMsg} "RootDir: $RootDir" Goto finished # Check for existing old method installation # Look for `python.exe` in C:\salt\bin checkOldInstallation: ${LogMsg} "Looking for Old Method installation" IfFileExists "C:\salt\bin\python.exe" 0 newInstallation StrCpy $ExistingInstallation 1 StrCpy $INSTDIR "C:\salt" StrCpy $RootDir "C:\salt" ${LogMsg} "Found Old Method installation" Goto finished # This is a new installation # Check if custom location was passed via command line newInstallation: ${LogMsg} "This is a New Installation" ${IfNot} $CustomLocation == "" StrCpy $INSTDIR $CustomLocation ${EndIf} finished: ${LogMsg} "Finished detecting installation type" SetRegView 32 # View the 32 bit portion of the registry FunctionEnd Function getExistingMinionConfig ${LogMsg} "Getting existing Minion Config" # Set Config Found Default Value StrCpy $ExistingConfigFound 0 # Find config, should be in $RootDir\conf\minion # Root dir is usually ProgramData\Salt Project\Salt\conf though it may be # C:\salt\conf if Salt was installed the old way ${LogMsg} "Looking for minion config in $RootDir" IfFileExists "$RootDir\conf\minion" check_owner ${LogMsg} "Looking for minion config in C:\salt" IfFileExists "C:\salt\conf\minion" old_location confNotFound old_location: ${LogMsg} "Found config in old location. Updating RootDir" StrCpy $RootDir "C:\salt" ${LogMsg} "RootDir: $RootDir" check_owner: # We need to verify the owner of the config directory (C:\salt\conf) to # ensure the config has not been modified by an unknown user. The # permissions and ownership of the directories is determined by the # installer used to install Salt. The NullSoft installer requests Admin # privileges so all directories are created with the Administrators # Group (S-1-5-32-544) as the owner. The MSI installer, however, runs in # the context of the Windows Installer service (msiserver), therefore # all directories are created with the Local System account (S-1-5-18) # as the owner. # # When Salt is launched it sets the root_dir (C:\salt) permissions as # follows: # - Owner: Administrators # - Allow Perms: # - Owner: Full Control # - System: Full Control # - Administrators: Full Control # # The conf_dir (C:\salt\conf) inherits Allow/Deny permissions from the # parent, but NOT Ownership. The owner will be the Administrators Group # if it was installed via NullSoft or the Local System account if it was # installed via the MSI. Therefore valid owners for the conf_dir are # both the Administrators group and the Local System account. # # An unprivileged account cannot change the owner of a directory by # default. So, if the owner of the conf_dir is either the Administrators # group or the Local System account, then we will trust it. Otherwise, # we will display an option to abort the installation or to backup the # untrusted config directory and continue with the default config. If # running the install with the silent option (/S) it will backup the # untrusted config directory and continue with the default config. ${LogMsg} "Validating permissions to config" AccessControl::GetFileOwner /SID "$RootDir\conf" Pop $0 # Check for valid SIDs StrCmp $0 "S-1-5-32-544" correct_owner # Administrators Group (NullSoft) StrCmp $0 "S-1-5-18" correct_owner # Local System (MSI) StrCpy $msg "Insecure config found at $RootDir\conf. If you continue, the \ config directory will be renamed to $RootDir\conf.insecure \ and the default config will be used. Continue?" ${LogMsg} $msg MessageBox MB_YESNO $msg /SD IDYES IDYES insecure_config ${LogMsg} "Aborting" Abort insecure_config: # Backing up insecure config ${LogMsg} "Backing up insecure config" Rename "$RootDir\conf" "$RootDir\conf.insecure-$TimeStamp" Goto confNotFound correct_owner: ${LogMsg} "Found existing config with correct permissions" StrCpy $ExistingConfigFound 1 ${LogMsg} "Opening minion config read-only" ClearErrors FileOpen $0 "$RootDir\conf\minion" r IfErrors 0 get_config_values ${LogMsg} "There was an error opening the minion config" ${LogMsg} "Config values will not be detected" Goto set_default_values get_config_values: ${LogMsg} "Getting config values from existing config" confLoop: ClearErrors # clear Errors FileRead $0 $1 # read the next line IfErrors EndOfFile # error is probably EOF ${StrLoc} $2 $1 "master:" ">" # find `master:` starting at the beginning ${If} $2 == 0 # if it found it in the first position, then it is defined ${StrStrAdv} $2 $1 "master: " ">" ">" "0" "0" "0" # read everything after `master: ` ${Trim} $2 $2 # trim white space ${If} $2 == "" # if it's empty, it's probably a list of masters masterLoop: ClearErrors # clear Errors FileRead $0 $1 # read the next line IfErrors EndOfFile # error is probably EOF ${StrStrAdv} $2 $1 "- " ">" ">" "0" "0" "0" # read everything after `- ` ${Trim} $2 $2 # trim white space ${IfNot} $2 == "" # if the line is not empty, we found something ${If} $MasterHost_Cfg == "" # if the config setting is empty StrCpy $MasterHost_Cfg $2 # make the first item the new entry ${Else} StrCpy $MasterHost_Cfg "$MasterHost_Cfg,$2" # Append the new master, comma separated ${EndIf} Goto masterLoop # check the next one ${EndIf} ${Else} StrCpy $MasterHost_Cfg $2 # a single master entry ${EndIf} ${EndIf} ${StrLoc} $2 $1 "id:" ">" ${If} $2 == 0 ${StrStrAdv} $2 $1 "id: " ">" ">" "0" "0" "0" ${Trim} $2 $2 StrCpy $MinionName_Cfg $2 ${EndIf} Goto confLoop EndOfFile: FileClose $0 confNotFound: ${LogMsg} "Config not found" set_default_values: # Set Default Config Values if not found ${If} $MasterHost_Cfg == "" ${LogMsg} "Setting master host setting to default: salt" StrCpy $MasterHost_Cfg "salt" ${EndIf} ${If} $MinionName_Cfg == "" ${LogMsg} "Setting minion id setting to default: hostname" StrCpy $MinionName_Cfg "hostname" ${EndIf} FunctionEnd Var cfg_line Var chk_line Var lst_check Var tgt_file Var tmp_file Function updateMinionConfig StrCpy $ConfigWriteMaster 1 # write the master config value StrCpy $ConfigWriteMinion 1 # write the minion config value ${If} $MasterHost == "" # if master is empty ${OrIf} $MasterHost == "salt" # or if master is 'salt' StrCpy $ConfigWriteMaster 0 # no need to write master config ${EndIf} # close if statement ${If} $MinionName == "" # if minion is empty ${OrIf} $MinionName == "hostname" # and if minion is not 'hostname' StrCpy $ConfigWriteMinion 0 # no need to write minion config ${EndIf} # close if statement ${If} $ConfigWriteMaster == 0 ${AndIf} $ConfigWriteMinion == 0 ${LogMsg} "No config values to update. Config will not be updated" Goto update_minion_config_finished ${EndIf} ${LogMsg} "Updating Minion Config" ${LogMsg} "Opening target file: $RootDir\conf\minion" ClearErrors FileOpen $tgt_file "$RootDir\conf\minion" r # open target file for reading ${If} ${Errors} ${LogMsg} "Target file could not be opened read-only" ${LogMsg} "Minion config will not be updated" Goto update_minion_config_finished ${EndIf} GetTempFileName $R0 # get new temp file name ${LogMsg} "Opening temp file: $R0" ClearErrors FileOpen $tmp_file "$R0" w # open temp file for writing ${If} ${Errors} ${LogMsg} "Temp file could not be opened for writing" ${LogMsg} "Minion config will not be updated" Goto update_minion_config_finished ${EndIf} loop: # loop through each line ${LogMsg} "Reading line from target config file" ClearErrors FileRead $tgt_file $cfg_line # read line from target file ${If} ${Errors} ${LogMsg} "Error: Most likely reached End-Of-File" Goto done ${EndIf} loop_after_read: StrCpy $lst_check 0 # list check not performed ${If} $ConfigWriteMaster == 1 # if we need to write master config ${StrLoc} $3 $cfg_line "master:" ">" # where is 'master:' in this line ${If} $3 == 0 # is it in the first... ${OrIf} $3 == 1 # or second position (account for comments) ${LogMsg} "Found master. Updating temp config" ${Explode} $9 "," $MasterHost # Split the hostname on commas, $9 is the number of items found ${If} $9 == 1 # 1 means only a single master was passed StrCpy $cfg_line "master: $MasterHost$\r$\n" # write the master ${Else} # make a multi-master entry StrCpy $cfg_line "master:" # make the first line "master:" loop_explode: # start a loop to go through the list in the config pop $8 # pop the next item off the stack ${Trim} $8 $8 # trim any whitespace StrCpy $cfg_line "$cfg_line$\r$\n - $8" # add it to the master variable ($2) IntOp $9 $9 - 1 # decrement the list count ${If} $9 >= 1 # if it's not 0 Goto loop_explode # do it again ${EndIf} # close if statement StrCpy $cfg_line "$cfg_line$\r$\n" # Make sure there's a new line at the end # Remove remaining items in list ${While} $lst_check == 0 # while list item found FileRead $tgt_file $chk_line # read line from target file IfErrors done # end if errors are encountered (end of line) ${StrLoc} $3 $chk_line " - " ">" # where is 'master:' in this line ${If} $3 == "" # is it in the first... StrCpy $lst_check 1 # list check performed and finished ${EndIf} ${EndWhile} ${EndIf} # close if statement StrCpy $ConfigWriteMaster 0 # master value written to config ${EndIf} # close if statement ${EndIf} # close if statement ${If} $ConfigWriteMinion == 1 # if we need to write minion config ${StrLoc} $3 $cfg_line "id:" ">" # where is 'id:' in this line ${If} $3 == 0 # is it in the first... ${OrIf} $3 == 1 # or the second position (account for comments) ${LogMsg} "Found minion ID. Updating temp config" StrCpy $cfg_line "id: $MinionName$\r$\n" # write the minion config setting StrCpy $ConfigWriteMinion 0 # minion value written to config ${EndIf} # close if statement ${EndIf} # close if statement ClearErrors ${LogMsg} "Writing config line(s) to temp file" # Enable this line for troubleshooting # ${LogMsg} "cfg_line: $cfg_line" FileWrite $tmp_file $cfg_line # write changed or unchanged line to temp file ${If} ${Errors} ${LogMsg} "There was an error writing new config line(s) to temp file" Goto update_minion_config_finished ${EndIf} ${If} $lst_check == 1 # master not written to the config StrCpy $cfg_line $chk_line Goto loop_after_read # A loop was performed, skip the next read ${EndIf} # close if statement Goto loop # check the next line in the config file done: ClearErrors # Does master config still need to be written ${If} $ConfigWriteMaster == 1 # master not written to the config ${LogMsg} "Master not found in existing config. Appending to the bottom" ${Explode} $9 "," $MasterHost # split the hostname on commas, $9 is the number of items found ${If} $9 == 1 # 1 means only a single master was passed StrCpy $cfg_line "master: $MasterHost" # write the master ${Else} # make a multi-master entry StrCpy $cfg_line "master:" # make the first line "master:" loop_explode_2: # start a loop to go through the list in the config pop $8 # pop the next item off the stack ${Trim} $8 $8 # trim any whitespace StrCpy $cfg_line "$cfg_line$\r$\n - $8" # add it to the master variable ($2) IntOp $9 $9 - 1 # decrement the list count ${If} $9 >= 1 # if it's not 0 Goto loop_explode_2 # do it again ${EndIf} # close if statement ${EndIf} # close if statement ClearErrors ${LogMsg} "Writing master config to temp file" FileWrite $tmp_file $cfg_line # write changed or unchanged line to temp file ${If} ${Errors} ${LogMsg} "There was an error writing master config to the temp file" ${LogMsg} "cfg_line: $cfg_line" Goto update_minion_config_finished ${EndIf} ${EndIf} # close if statement ${If} $ConfigWriteMinion == 1 # minion ID not written to the config ${LogMsg} "Minion ID not found in existing config. Appending to the bottom" StrCpy $cfg_line "$\r$\nid: $MinionName" # write the minion config setting ClearErrors ${LogMsg} "Writing minion id to temp config file" FileWrite $tmp_file $cfg_line # write changed or unchanged line to temp file ${If} ${Errors} ${LogMsg} "There was an error writing minion id to temop config file" ${LogMsg} "cfg_line: $cfg_line" Goto update_minion_config_finished ${EndIf} ${EndIf} # close if statement ${LogMsg} "Closing config files" FileClose $tgt_file # close target file FileClose $tmp_file # close temp file ${LogMsg} "Deleting target config" Delete "$RootDir\conf\minion" # delete target file ${LogMsg} "Copying new target config" CopyFiles /SILENT $R0 "$RootDir\conf\minion" # copy temp file to target file ${LogMsg} "Deleting old temp file" Delete $R0 # delete temp file update_minion_config_finished: ${LogMsg} "Update minion config finished" FunctionEnd Function un.parseUninstallerCommandLineSwitches ${LogMsg} "Parsing command line parameters for the Uninstaller" # Load the parameters ${GetParameters} $cmdLineParams # Uninstaller: Remove Installation Directory ${LogMsg} "Checking /delete-install-dir" ClearErrors ${GetOptions} $cmdLineParams "/delete-install-dir" $R1 ${If} ${Errors} ${LogMsg} "/delete-install-dir not found" ${Else} ${LogMsg} "Found /delete-install-dir" StrCpy $DeleteInstallDir 1 ${EndIf} # Uninstaller: Remove Root Directory ${LogMsg} "Checking /delete-root-dir" ClearErrors ${GetOptions} $cmdLineParams "/delete-root-dir" $R1 ${If} ${Errors} ${LogMsg} "/delete-root-dir not found" ${Else} ${LogMsg} "Found /delete-root-dir" StrCpy $DeleteRootDir 1 ${EndIf} FunctionEnd Function parseInstallerCommandLineSwitches ${LogMsg} "Parsing command line parameters for the Installer" # Load the parameters ${GetParameters} $cmdLineParams ${LogMsg} "Passed: $cmdLineParams" # Check for start-minion switches ${LogMsg} "Checking for /start-minion" ${GetOptions} $cmdLineParams "/start-minion=" $R1 ${IfNot} $R1 == "" ${LogMsg} "Found /start-minion=$R1" # If start-minion was passed something, then set it StrCpy $StartMinion $R1 ${Else} # Otherwise default to 1 ${LogMsg} "/start-minion not found. Using default" StrCpy $StartMinion 1 ${EndIf} # Service: Minion Startup Type Delayed ${LogMsg} "Checking for /start-minion-delayed" ClearErrors ${GetOptions} $cmdLineParams "/start-minion-delayed" $R1 ${If} ${Errors} ${LogMsg} "/start-minion-delayed not found" ${Else} ${LogMsg} "Found /start-minion-delayed" StrCpy $StartMinionDelayed 1 ${EndIf} # Set default value for Use Existing Config StrCpy $ConfigType "Existing Config" # Minion Config: Master IP/Name # If setting master, we don't want to use existing config ${LogMsg} "Checking for /master" ${GetOptions} $cmdLineParams "/master=" $R1 ${If} ${Errors} ${LogMsg} "/master= not found. Using default" StrCpy $MasterHost "salt" ${ElseIfNot} $R1 == "" ${LogMsg} "Found /master=$R1" StrCpy $MasterHost $R1 StrCpy $ConfigType "Default Config" ${Else} ${LogMsg} "/master found, but value not passed. Using default value" StrCpy $MasterHost "salt" ${EndIf} # Minion Config: Minion ID # If setting minion id, we don't want to use existing config ${LogMsg} "Checking for /minion-name" ${GetOptions} $cmdLineParams "/minion-name=" $R1 ${If} ${Errors} ${LogMsg} "/minion-name= not found. Using default" StrCpy $MinionName "hostname" ${ElseIfNot} $R1 == "" ${LogMsg} "Found /minion-name=$R1" StrCpy $MinionName $R1 StrCpy $ConfigType "Default Config" ${Else} ${LogMsg} "/minion-name= found, but value not passed. Using default" StrCpy $MinionName "hostname" ${EndIf} # Use Default Config ${LogMsg} "Checking for /default-config" ClearErrors ${GetOptions} $cmdLineParams "/default-config" $R1 ${If} ${Errors} ${LogMsg} "/default-config not found" ${Else} ${LogMsg} "Found /default-config" StrCpy $ConfigType "Default Config" ${EndIf} # Use Custom Config # Set default value for Use Custom Config ${LogMsg} "Checking for /custom-config" # Existing config will get a `.bak` extension ${GetOptions} $cmdLineParams "/custom-config=" $R1 ${If} ${Errors} ${LogMsg} "/custom-config= not found" StrCpy $CustomConfig "" ${ElseIfNot} $R1 == "" ${LogMsg} "Found /custom-config=$R1" StrCpy $CustomConfig $R1 StrCpy $ConfigType "Custom Config" ${Else} ${LogMsg} "/custom-config= found, but value not passed" StrCpy $CustomConfig "" ${EndIf} # Set Install Location ${LogMsg} "Checking for /install-dir" ClearErrors ${GetOptions} $cmdLineParams "/install-dir=" $R1 ${If} ${Errors} ${LogMsg} "/install-dir= not found" StrCpy $CustomLocation "" ${ElseIfNot} $R1 == "" # A Custom Location was passed, set it ${LogMsg} "Found /install-dir=$R1" StrCpy $CustomLocation $R1 ${Else} ${LogMsg} "/install-dir= found, but value not passed" StrCpy $CustomConfig "" ${EndIf} # Set Move Config Option ${LogMsg} "Checking for /move-config" ClearErrors ${GetOptions} $cmdLineParams "/move-config" $R1 ${If} ${Errors} ${LogMsg} "/move-config not found" StrCpy $MoveExistingConfig 0 ${Else} ${LogMsg} "Found /move-config" StrCpy $MoveExistingConfig 1 ${EndIf} FunctionEnd