1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546 |
- !define PRODUCT_NAME "Salt Minion"
- !define PRODUCT_NAME_OTHER "Salt"
- !define PRODUCT_PUBLISHER "SaltStack, Inc"
- !define PRODUCT_WEB_SITE "http://saltstack.org"
- !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_KEY_OTHER "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_OTHER}"
- !define PRODUCT_UNINST_ROOT_KEY "HKLM"
- !define OUTFILE "Salt-Minion-${PRODUCT_VERSION}-${CPUARCH}-Setup.exe"
- # Import Libraries
- !include "MUI2.nsh"
- !include "nsDialogs.nsh"
- !include "LogicLib.nsh"
- !include "FileFunc.nsh"
- !include "StrFunc.nsh"
- !include "x64.nsh"
- !include "WinMessages.nsh"
- !include "WinVer.nsh"
- ${StrLoc}
- ${StrStrAdv}
- !ifdef SaltVersion
- !define PRODUCT_VERSION "${SaltVersion}"
- !else
- !define PRODUCT_VERSION "Undefined Version"
- !endif
- !if "$%PROCESSOR_ARCHITECTURE%" == "AMD64"
- !define CPUARCH "AMD64"
- !else if "$%PROCESSOR_ARCHITEW6432%" == "AMD64"
- !define CPUARCH "AMD64"
- !else
- !define CPUARCH "x86"
- !endif
- # Part of the Trim function for Strings
- !define Trim "!insertmacro Trim"
- !macro Trim ResultVar String
- Push "${String}"
- Call Trim
- 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
- ###############################################################################
- # 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"
- # 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 CheckBox_Minion_Start
- Var CheckBox_Minion_Start_Delayed
- Var ConfigMasterHost
- Var MasterHost
- Var MasterHost_State
- Var ConfigMinionName
- Var MinionName
- Var MinionName_State
- Var ExistingConfigFound
- Var ConfigType
- Var ConfigType_State
- Var CustomConfig
- Var CustomConfig_btn
- Var CustomConfig_State
- Var WarningCustomConfig
- Var WarningExistingConfig
- Var WarningDefaultConfig
- Var StartMinion
- Var StartMinionDelayed
- Var DeleteInstallDir
- Var ConfigWriteMinion
- Var ConfigWriteMaster
- ###############################################################################
- # 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% 12u "Master IP or Hostname:"
- Pop $Label
- ${NSD_CreateText} 0 13u 100% 12u $MasterHost_State
- Pop $MasterHost
- # Minion ID Dialog Control
- ${NSD_CreateLabel} 0 30u 100% 12u "Minion Name:"
- Pop $Label
- ${NSD_CreateText} 0 43u 100% 12u $MinionName_State
- Pop $MinionName
- # Config Drop List
- ${NSD_CreateDropList} 0 65u 25% 36u ""
- Pop $ConfigType
- ${NSD_CB_AddString} $ConfigType "Default Config"
- ${NSD_CB_AddString} $ConfigType "Custom Config"
- ${NSD_OnChange} $ConfigType pageMinionConfig_OnChange
- # Add Existing Config Warning Label
- ${NSD_CreateLabel} 0 80u 100% 60u "The values above are taken from an \
- existing configuration found in `c:\salt\conf\minion`. Configuration \
- settings defined in the `minion.d` directories, if they exist, are not \
- shown here.$\r$\n\
- $\r$\n\
- Clicking `Install` will leave the existing config unchanged."
- Pop $WarningExistingConfig
- CreateFont $0 "Arial" 10 500 /ITALIC
- SendMessage $WarningExistingConfig ${WM_SETFONT} $0 1
- SetCtlColors $WarningExistingConfig 0xBB0000 transparent
- # Add Default Config Warning Label
- ${NSD_CreateLabel} 0 80u 100% 60u "Clicking `Install` will backup the \
- the existing minion config file and minion.d directories. The values \
- above will be used in the new default config.$\r$\n\
- $\r$\n\
- NOTE: If Master IP is set to `salt` and Minion Name is set to \
- `hostname` no changes will be made."
- Pop $WarningDefaultConfig
- CreateFont $0 "Arial" 10 500 /ITALIC
- SendMessage $WarningDefaultConfig ${WM_SETFONT} $0 1
- SetCtlColors $WarningDefaultConfig 0xBB0000 transparent
- # Add Custom Config File Selector and Warning Label
- ${NSD_CreateText} 26% 65u 64% 12u $CustomConfig_State
- Pop $CustomConfig
- ${NSD_CreateButton} 91% 65u 9% 12u "..."
- Pop $CustomConfig_btn
- ${NSD_OnClick} $CustomConfig_btn pageCustomConfigBtn_OnClick
- ${If} $ExistingConfigFound == 0
- ${NSD_CreateLabel} 0 80u 100% 60u "Values entered above will be used \
- in the custom config.$\r$\n\
- $\r$\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 80u 100% 60u "Clicking `Install` will backup the \
- the existing minion config file and minion.d directories. The \
- values above will be used in the custom config.$\r$\n\
- $\r$\n\
- NOTE: If Master IP is set to `salt` and Minion Name is set to \
- `hostname` no changes will be made."
- ${Endif}
- Pop $WarningCustomConfig
- CreateFont $0 "Arial" 10 500 /ITALIC
- SendMessage $WarningCustomConfig ${WM_SETFONT} $0 1
- SetCtlColors $WarningCustomConfig 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 "Existing Config"
- ${Else}
- ShowWindow $WarningDefaultConfig ${SW_HIDE}
- ${Endif}
- ${NSD_CB_SelectString} $ConfigType $ConfigType_State
- ${NSD_SetText} $CustomConfig $CustomConfig_State
- 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 $ConfigType_State
- # Update Dialog
- ${Switch} $ConfigType_State
- ${Case} "Existing Config"
- # Enable Master/Minion and set values
- EnableWindow $MasterHost 0
- EnableWindow $MinionName 0
- ${NSD_SetText} $MasterHost $ConfigMasterHost
- ${NSD_SetText} $MinionName $ConfigMinionName
- # Hide Custom File Picker
- ShowWindow $CustomConfig ${SW_HIDE}
- ShowWindow $CustomConfig_btn ${SW_HIDE}
- # Hide Warnings
- ShowWindow $WarningDefaultConfig ${SW_HIDE}
- ShowWindow $WarningCustomConfig ${SW_HIDE}
- # Show Existing Warning
- ShowWindow $WarningExistingConfig ${SW_SHOW}
- ${Break}
- ${Case} "Custom Config"
- # Enable Master/Minion and set values
- EnableWindow $MasterHost 1
- EnableWindow $MinionName 1
- ${NSD_SetText} $MasterHost $MasterHost_State
- ${NSD_SetText} $MinionName $MinionName_State
- # Show Custom File Picker
- ShowWindow $CustomConfig ${SW_SHOW}
- ShowWindow $CustomConfig_btn ${SW_SHOW}
- # Hide Warnings
- ShowWindow $WarningDefaultConfig ${SW_HIDE}
- ShowWindow $WarningExistingConfig ${SW_HIDE}
- # Show Custom Warning
- ShowWindow $WarningCustomConfig ${SW_SHOW}
- ${Break}
- ${Case} "Default Config"
- # Enable Master/Minion and set values
- EnableWindow $MasterHost 1
- EnableWindow $MinionName 1
- ${NSD_SetText} $MasterHost $MasterHost_State
- ${NSD_SetText} $MinionName $MinionName_State
- # Hide Custom File Picker
- ShowWindow $CustomConfig ${SW_HIDE}
- ShowWindow $CustomConfig_btn ${SW_HIDE}
- # Hide Warnings
- ShowWindow $WarningExistingConfig ${SW_HIDE}
- ShowWindow $WarningCustomConfig ${SW_HIDE}
- # Show Default Warning, if there is an existing config
- ${If} $ExistingConfigFound == 1
- ShowWindow $WarningDefaultConfig ${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 $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 $2
- ${EndIf}
- # Free resources
- System::Free $1
- System::Free $0
- FunctionEnd
- Function pageMinionConfig_Leave
- # Save the State
- ${NSD_GetText} $MasterHost $MasterHost_State
- ${NSD_GetText} $MinionName $MinionName_State
- ${NSD_GetText} $ConfigType $ConfigType_State
- ${NSD_GetText} $CustomConfig $CustomConfig_State
- # Abort if config file not found
- ${If} $ConfigType_State == "Custom Config"
- IfFileExists "$CustomConfig_State" continue 0
- MessageBox MB_OK "File not found: $CustomConfig_State" /SD IDOK
- Abort
- ${EndIf}
- continue:
- Call BackupExistingConfig
- 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 $CheckBox_Minion_Start
- SetCtlColors $CheckBox_Minion_Start "" "ffffff"
- # This command required to bring the checkbox to the front
- System::Call "User32::SetWindowPos(i, i, i, i, i, i, i) b ($CheckBox_Minion_Start, ${HWND_TOP}, 0, 0, 0, 0, ${SWP_NOSIZE}|${SWP_NOMOVE})"
- # Create Start Minion Delayed ComboBox
- ${NSD_CreateCheckbox} 130u 102u 100% 12u "&Delayed Start"
- Pop $CheckBox_Minion_Start_Delayed
- SetCtlColors $CheckBox_Minion_Start_Delayed "" "ffffff"
- # This command required to bring the checkbox to the front
- System::Call "User32::SetWindowPos(i, i, i, i, i, i, i) b ($CheckBox_Minion_Start_Delayed, ${HWND_TOP}, 0, 0, 0, 0, ${SWP_NOSIZE}|${SWP_NOMOVE})"
- # Load current settings for Minion
- ${If} $StartMinion == 1
- ${NSD_Check} $CheckBox_Minion_Start
- ${EndIf}
- # Load current settings for Minion Delayed
- ${If} $StartMinionDelayed == 1
- ${NSD_Check} $CheckBox_Minion_Start_Delayed
- ${EndIf}
- FunctionEnd
- Function pageFinish_Leave
- # Assign the current checkbox states
- ${NSD_GetState} $CheckBox_Minion_Start $StartMinion
- ${NSD_GetState} $CheckBox_Minion_Start_Delayed $StartMinionDelayed
- FunctionEnd
- ###############################################################################
- # Installation Settings
- ###############################################################################
- Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
- OutFile "${OutFile}"
- InstallDir "c:\salt"
- InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
- ShowInstDetails show
- ShowUnInstDetails show
- Section -copy_prereqs
- # Copy prereqs to the Plugins Directory
- # These files will be KB2999226 for Win8.1 and below
- # These files are downloaded by build_pkg.bat
- # This directory gets removed upon completion
- SetOutPath "$PLUGINSDIR\"
- File /r "..\prereqs\"
- SectionEnd
- # Check and install the Windows 10 Universal C Runtime (KB2999226)
- # ucrt is needed on Windows 8.1 and lower
- # They are installed as a Microsoft Update package (.msu)
- # ucrt for Windows 8.1 RT is only available via Windows Update
- Section -install_ucrt
- Var /GLOBAL MsuPrefix
- Var /GLOBAL MsuFileName
- # Get the Major.Minor version Number
- # Windows 10 introduced CurrentMajorVersionNumber
- ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" \
- CurrentMajorVersionNumber
- # Windows 10/2016 will return a value here, skip to the end if returned
- StrCmp $R0 '' lbl_needs_ucrt 0
- # Found Windows 10
- detailPrint "KB2999226 does not apply to this machine"
- goto lbl_done
- lbl_needs_ucrt:
- # UCRT only needed on Windows Server 2012R2/Windows 8.1 and below
- # The first ReadRegStr command above should have skipped to lbl_done if on
- # Windows 10 box
- # Is the update already installed
- ClearErrors
- # Use WMI to check if it's installed
- detailPrint "Checking for existing KB2999226 installation"
- nsExec::ExecToStack 'cmd /q /c wmic qfe get hotfixid | findstr "^KB2999226"'
- # Clean up the stack
- Pop $R0 # Gets the ErrorCode
- Pop $R1 # Gets the stdout, which should be KB2999226 if it's installed
- # If it returned KB2999226 it's already installed
- StrCmp $R1 'KB2999226' lbl_done
- detailPrint "KB2999226 not found"
- # All lower versions of Windows
- ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" \
- CurrentVersion
- # Get the name of the .msu file based on the value of $R0
- ${Switch} "$R0"
- ${Case} "6.3"
- StrCpy $MsuPrefix "Windows8.1"
- ${break}
- ${Case} "6.2"
- StrCpy $MsuPrefix "Windows8-RT"
- ${break}
- ${Case} "6.1"
- StrCpy $MsuPrefix "Windows6.1"
- ${break}
- ${Case} "6.0"
- StrCpy $MsuPrefix "Windows6.0"
- ${break}
- ${EndSwitch}
- # Use RunningX64 here to get the Architecture for the system running the installer
- # CPUARCH is defined when the installer is built and is based on the machine that
- # built the installer, not the target system as we need here.
- ${If} ${RunningX64}
- StrCpy $MsuFileName "$MsuPrefix-KB2999226-x64.msu"
- ${Else}
- StrCpy $MsuFileName "$MsuPrefix-KB2999226-x86.msu"
- ${EndIf}
- ClearErrors
- detailPrint "Installing KB2999226 using file $MsuFileName"
- nsExec::ExecToStack 'cmd /c wusa "$PLUGINSDIR\$MsuFileName" /quiet /norestart'
- # Clean up the stack
- Pop $R0 # Get Error
- Pop $R1 # Get stdout
- ${IfNot} $R0 == 0
- detailPrint "error: $R0"
- detailPrint "output: $R2"
- Sleep 3000
- ${Else}
- detailPrint "KB2999226 installed successfully"
- ${EndIf}
- lbl_done:
- SectionEnd
- Section "MainSection" SEC01
- SetOutPath "$INSTDIR\"
- SetOverwrite off
- CreateDirectory $INSTDIR\conf\pki\minion
- CreateDirectory $INSTDIR\conf\minion.d
- File /r "..\buildenv\"
- nsExec::Exec 'icacls c:\salt /inheritance:r /grant:r "*S-1-5-32-544":(OI)(CI)F /grant:r "*S-1-5-18":(OI)(CI)F'
- SectionEnd
- Function .onInit
- Call parseCommandLineSwitches
- # 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
- loop:
- System::Call 'MSI::MsiEnumRelatedProducts(t "${upgradecode}",i0,i r0,t.r1)i.r2'
- ${If} $2 = 0
- # Now $1 contains the product code
- DetailPrint product:$1
- push $R0
- StrCpy $R0 $1
- Call UninstallMSI
- pop $R0
- IntOp $0 $0 + 1
- goto loop
- ${Endif}
- # If custom config passed, verify its existence before continuing so we
- # don't uninstall an existing installation and then fail
- ${If} $ConfigType_State == "Custom Config"
- IfFileExists "$CustomConfig_State" customConfigExists 0
- Abort
- ${EndIf}
- customConfigExists:
- # Check for existing installation
- ReadRegStr $R0 HKLM \
- "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
- "UninstallString"
- StrCmp $R0 "" checkOther
- # Found existing installation, prompt to uninstall
- MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
- "${PRODUCT_NAME} is already installed.$\n$\n\
- Click `OK` to remove the existing installation." \
- /SD IDOK IDOK uninst
- Abort
- checkOther:
- # Check for existing installation of full salt
- ReadRegStr $R0 HKLM \
- "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_OTHER}" \
- "UninstallString"
- StrCmp $R0 "" skipUninstall
- # Found existing installation, prompt to uninstall
- MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
- "${PRODUCT_NAME_OTHER} is already installed.$\n$\n\
- Click `OK` to remove the existing installation." \
- /SD IDOK IDOK uninst
- Abort
- uninst:
- # Get current Silent status
- StrCpy $R0 0
- ${If} ${Silent}
- StrCpy $R0 1
- ${EndIf}
- # Turn on Silent mode
- SetSilent silent
- # Don't remove all directories
- StrCpy $DeleteInstallDir 0
- # Uninstall silently
- Call uninstallSalt
- # Set it back to Normal mode, if that's what it was before
- ${If} $R0 == 0
- SetSilent normal
- ${EndIf}
- skipUninstall:
- Call getExistingMinionConfig
- ${If} $ExistingConfigFound == 0
- ${AndIf} $ConfigType_State == "Existing Config"
- StrCpy $ConfigType_State "Default Config"
- ${EndIf}
- IfSilent 0 +2
- Call BackupExistingConfig
- FunctionEnd
- # Time Stamp Definition
- !define /date TIME_STAMP "%Y-%m-%d-%H-%M-%S"
- Function BackupExistingConfig
- ${If} $ExistingConfigFound == 1 # If existing config found
- ${AndIfNot} $ConfigType_State == "Existing Config" # If not using Existing Config
- # Backup the minion config
- Rename "$INSTDIR\conf\minion" "$INSTDIR\conf\minion-${TIME_STAMP}.bak"
- IfFileExists "$INSTDIR\conf\minion.d" 0 +2
- Rename "$INSTDIR\conf\minion.d" "$INSTDIR\conf\minion.d-${TIME_STAMP}.bak"
- ${EndIf}
- # By this point there should be no existing config
- # It was either backed up or wasn't there to begin with
- ${If} $ConfigType_State == "Custom Config" # If we're using Custom Config
- ${AndIfNot} $CustomConfig_State == "" # If a custom config is passed
- # Check for a file name
- # Named file should be in the same directory as the installer
- CreateDirectory "$INSTDIR\conf"
- IfFileExists "$EXEDIR\$CustomConfig_State" 0 checkFullPath
- CopyFiles /SILENT /FILESONLY "$EXEDIR\$CustomConfig_State" "$INSTDIR\conf\minion"
- goto finished
- # Maybe it was a full path to a file
- checkFullPath:
- IfFileExists "$CustomConfig_State" 0 finished
- CopyFiles /SILENT /FILESONLY "$CustomConfig_State" "$INSTDIR\conf\minion"
- finished:
- ${EndIf}
- FunctionEnd
- Section -Post
- WriteUninstaller "$INSTDIR\uninst.exe"
- # 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"
- # Set the estimated size
- ${GetSize} "$INSTDIR\bin" "/S=OK" $0 $1 $2
- IntFmt $0 "0x%08X" $0
- WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
- "EstimatedSize" "$0"
- # Commandline Registry Entries
- WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "" "$INSTDIR\salt-call.bat"
- WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "Path" "$INSTDIR\bin\"
- WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "" "$INSTDIR\salt-minion.bat"
- WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "Path" "$INSTDIR\bin\"
- # Register the Salt-Minion Service
- nsExec::Exec "$INSTDIR\bin\ssm.exe install salt-minion $INSTDIR\bin\python.exe -E -s $INSTDIR\bin\Scripts\salt-minion -c $INSTDIR\conf -l quiet"
- nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Description Salt Minion from saltstack.com"
- nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Start SERVICE_AUTO_START"
- nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion AppStopMethodConsole 24000"
- nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion AppStopMethodWindow 2000"
- ${IfNot} $ConfigType_State == "Existing Config" # If not using Existing Config
- Call updateMinionConfig
- ${EndIf}
- Push "C:\salt"
- Call AddToPath
- SectionEnd
- Function .onInstSuccess
- # If StartMinionDelayed is 1, then set the service to start delayed
- ${If} $StartMinionDelayed == 1
- nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Start SERVICE_DELAYED_AUTO_START"
- ${EndIf}
- # If start-minion is 1, then start the service
- ${If} $StartMinion == 1
- nsExec::Exec 'net start salt-minion'
- ${EndIf}
- FunctionEnd
- Function un.onInit
- # Load the parameters
- ${GetParameters} $R0
- # Uninstaller: Remove Installation Directory
- ClearErrors
- ${GetOptions} $R0 "/delete-install-dir" $R1
- IfErrors delete_install_dir_not_found
- StrCpy $DeleteInstallDir 1
- delete_install_dir_not_found:
- MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 \
- "Are you sure you want to completely remove $(^Name) and all of its components?" \
- /SD IDYES IDYES +2
- Abort
- FunctionEnd
- Section Uninstall
- Call un.uninstallSalt
- # Remove C:\salt from the Path
- Push "C:\salt"
- Call un.RemoveFromPath
- SectionEnd
- !macro uninstallSalt un
- Function ${un}uninstallSalt
- # Make sure we're in the right directory
- ${If} $INSTDIR == "c:\salt\bin\Scripts"
- StrCpy $INSTDIR "C:\salt"
- ${EndIf}
- # Stop and Remove salt-minion service
- nsExec::Exec 'net stop salt-minion'
- nsExec::Exec 'sc delete salt-minion'
- # Stop and remove the salt-master service
- nsExec::Exec 'net stop salt-master'
- nsExec::Exec 'sc delete salt-master'
- # Remove files
- Delete "$INSTDIR\uninst.exe"
- Delete "$INSTDIR\ssm.exe"
- Delete "$INSTDIR\salt*"
- Delete "$INSTDIR\vcredist.exe"
- RMDir /r "$INSTDIR\bin"
- # Remove Registry entries
- DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
- DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY_OTHER}"
- 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}"
- # Automatically close when finished
- SetAutoClose true
- # Prompt to remove the Installation directory
- ${IfNot} $DeleteInstallDir == 1
- MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 \
- "Would you like to completely remove $INSTDIR and all of its contents?" \
- /SD IDNO IDNO finished
- ${EndIf}
- # Make sure you're not removing Program Files
- ${If} $INSTDIR != 'Program Files'
- ${AndIf} $INSTDIR != 'Program Files (x86)'
- RMDir /r "$INSTDIR"
- ${EndIf}
- finished:
- FunctionEnd
- !macroend
- !insertmacro uninstallSalt ""
- !insertmacro uninstallSalt "un."
- Function un.onUninstSuccess
- HideWindow
- MessageBox MB_ICONINFORMATION|MB_OK \
- "$(^Name) was successfully removed from your computer." \
- /SD IDOK
- 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
- #------------------------------------------------------------------------------
- Function 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
- #------------------------------------------------------------------------------
- # 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
- #------------------------------------------------------------------------------
- # StrStr Function
- # - find substring in a string
- #
- # Usage:
- # Push "this is some string"
- # Push "some"
- # Call StrStr
- # Pop $0 # "some string"
- #------------------------------------------------------------------------------
- !macro StrStr un
- Function ${un}StrStr
- Exch $R1 # $R1=substring, stack=[old$R1,string,...]
- Exch # stack=[string,old$R1,...]
- Exch $R2 # $R2=string, stack=[old$R2,old$R1,...]
- Push $R3 # $R3=strlen(substring)
- Push $R4 # $R4=count
- Push $R5 # $R5=tmp
- StrLen $R3 $R1 # Get the length of the Search String
- StrCpy $R4 0 # Set the counter to 0
- loop:
- StrCpy $R5 $R2 $R3 $R4 # Create a moving window of the string that is
- # the size of the length of the search string
- StrCmp $R5 $R1 done # Is the contents of the window the same as
- # search string, then done
- StrCmp $R5 "" done # Is the window empty, then done
- IntOp $R4 $R4 + 1 # Shift the windows one character
- Goto loop # Repeat
- done:
- StrCpy $R1 $R2 "" $R4
- Pop $R5
- Pop $R4
- Pop $R3
- Pop $R2
- Exch $R1 # $R1=old$R1, stack=[result,...]
- FunctionEnd
- !macroend
- !insertmacro StrStr ""
- !insertmacro StrStr "un."
- #------------------------------------------------------------------------------
- # AddToPath Function
- # - Adds item to Path for All Users
- # - Overcomes NSIS ReadRegStr limitation of 1024 characters by using Native
- # Windows Commands
- #
- # Usage:
- # Push "C:\path\to\add"
- # Call AddToPath
- #------------------------------------------------------------------------------
- !define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
- Function AddToPath
- Exch $0 # Path to add
- Push $1 # Current Path
- Push $2 # Results of StrStr / Length of Path + Path to Add
- Push $3 # Handle to Reg / Length of Path
- Push $4 # Result of Registry Call
- # Open a handle to the key in the registry, handle in $3, Error in $4
- System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
- # Make sure registry handle opened successfully (returned 0)
- IntCmp $4 0 0 done done
- # Load the contents of path into $1, Error Code into $4, Path length into $2
- System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
- # Close the handle to the registry ($3)
- System::Call "advapi32::RegCloseKey(i $3)"
- # Check for Error Code 234, Path too long for the variable
- IntCmp $4 234 0 +4 +4 # $4 == ERROR_MORE_DATA
- DetailPrint "AddToPath Failed: original length $2 > ${NSIS_MAX_STRLEN}"
- MessageBox MB_OK \
- "You may add C:\salt to the %PATH% for convenience when issuing local salt commands from the command line." \
- /SD IDOK
- Goto done
- # If no error, continue
- IntCmp $4 0 +5 # $4 != NO_ERROR
- # Error 2 means the Key was not found
- IntCmp $4 2 +3 # $4 != ERROR_FILE_NOT_FOUND
- DetailPrint "AddToPath: unexpected error code $4"
- Goto done
- StrCpy $1 ""
- # Check if already in PATH
- Push "$1;" # The string to search
- Push "$0;" # The string to find
- Call StrStr
- Pop $2 # The result of the search
- StrCmp $2 "" 0 done # String not found, try again with ';' at the end
- # Otherwise, it's already in the path
- Push "$1;" # The string to search
- Push "$0\;" # The string to find
- Call StrStr
- Pop $2 # The result
- StrCmp $2 "" 0 done # String not found, continue (add)
- # Otherwise, it's already in the path
- # Prevent NSIS string overflow
- StrLen $2 $0 # Length of path to add ($2)
- StrLen $3 $1 # Length of current path ($3)
- IntOp $2 $2 + $3 # Length of current path + path to add ($2)
- IntOp $2 $2 + 2 # Account for the additional ';'
- # $2 = strlen(dir) + strlen(PATH) + sizeof(";")
- # Make sure the new length isn't over the NSIS_MAX_STRLEN
- IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0
- DetailPrint "AddToPath Failed: new length $2 > ${NSIS_MAX_STRLEN}"
- MessageBox MB_OK \
- "You may add C:\salt to the %PATH% for convenience when issuing local salt commands from the command line." \
- /SD IDOK
- Goto done
- # Append dir to PATH
- DetailPrint "Add to PATH: $0"
- StrCpy $2 $1 1 -1 # Copy the last character of the existing path
- StrCmp $2 ";" 0 +2 # Check for trailing ';'
- StrCpy $1 $1 -1 # remove trailing ';'
- StrCmp $1 "" +2 # Make sure Path is not empty
- StrCpy $0 "$1;$0" # Append new path at the end ($0)
- # We can use the NSIS command here. Only 'ReadRegStr' is affected
- WriteRegExpandStr ${Environ} "PATH" $0
- # Broadcast registry change to open programs
- SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
- done:
- Pop $4
- Pop $3
- Pop $2
- Pop $1
- Pop $0
- FunctionEnd
- #------------------------------------------------------------------------------
- # RemoveFromPath Function
- # - Removes item from Path for All Users
- # - Overcomes NSIS ReadRegStr limitation of 1024 characters by using Native
- # Windows Commands
- #
- # Usage:
- # Push "C:\path\to\add"
- # Call un.RemoveFromPath
- #------------------------------------------------------------------------------
- Function un.RemoveFromPath
- Exch $0
- Push $1
- Push $2
- Push $3
- Push $4
- Push $5
- Push $6
- # Open a handle to the key in the registry, handle in $3, Error in $4
- System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
- # Make sure registry handle opened successfully (returned 0)
- IntCmp $4 0 0 done done
- # Load the contents of path into $1, Error Code into $4, Path length into $2
- System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
- # Close the handle to the registry ($3)
- System::Call "advapi32::RegCloseKey(i $3)"
- # Check for Error Code 234, Path too long for the variable
- IntCmp $4 234 0 +4 +4 # $4 == ERROR_MORE_DATA
- DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}"
- Goto done
- # If no error, continue
- IntCmp $4 0 +5 # $4 != NO_ERROR
- # Error 2 means the Key was not found
- IntCmp $4 2 +3 # $4 != ERROR_FILE_NOT_FOUND
- DetailPrint "AddToPath: unexpected error code $4"
- Goto done
- StrCpy $1 ""
- # Ensure there's a trailing ';'
- StrCpy $5 $1 1 -1 # Copy the last character of the path
- StrCmp $5 ";" +2 # Check for trailing ';', if found continue
- StrCpy $1 "$1;" # ensure trailing ';'
- # Check for our directory inside the path
- Push $1 # String to Search
- Push "$0;" # Dir to Find
- Call un.StrStr
- Pop $2 # The results of the search
- StrCmp $2 "" done # If results are empty, we're done, otherwise continue
- # Remove our Directory from the Path
- DetailPrint "Remove from PATH: $0"
- StrLen $3 "$0;" # Get the length of our dir ($3)
- StrLen $4 $2 # Get the length of the return from StrStr ($4)
- StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
- StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
- StrCpy $3 "$5$6" # Combine $5 and $6
- # Check for Trailing ';'
- StrCpy $5 $3 1 -1 # Load the last character of the string
- StrCmp $5 ";" 0 +2 # Check for ';'
- StrCpy $3 $3 -1 # remove trailing ';'
- # Write the new path to the registry
- WriteRegExpandStr ${Environ} "PATH" $3
- # Broadcast the change to all open applications
- SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
- done:
- Pop $6
- Pop $5
- Pop $4
- Pop $3
- Pop $2
- Pop $1
- Pop $0
- 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_ICONEXCLAMATION \
- "${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 getExistingMinionConfig
- # Set Config Found Default Value
- StrCpy $ExistingConfigFound 0
- confFind:
- IfFileExists "$INSTDIR\conf\minion" confFound confNotFound
- confNotFound:
- ${If} $INSTDIR == "c:\salt\bin\Scripts"
- StrCpy $INSTDIR "C:\salt"
- goto confFind
- ${Else}
- goto confReallyNotFound
- ${EndIf}
- confFound:
- StrCpy $ExistingConfigFound 1
- FileOpen $0 "$INSTDIR\conf\minion" r
- 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} $ConfigMasterHost == "" # if the config setting is empty
- StrCpy $ConfigMasterHost $2 # make the first item the new entry
- ${Else}
- StrCpy $ConfigMasterHost "$ConfigMasterHost,$2" # Append the new master, comma separated
- ${EndIf}
- Goto masterLoop # check the next one
- ${EndIf}
- ${Else}
- StrCpy $ConfigMasterHost $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 $ConfigMinionName $2
- ${EndIf}
- Goto confLoop
- EndOfFile:
- FileClose $0
- confReallyNotFound:
- # Set Default Config Values if not found
- ${If} $ConfigMasterHost == ""
- StrCpy $ConfigMasterHost "salt"
- ${EndIf}
- ${If} $ConfigMinionName == ""
- StrCpy $ConfigMinionName "hostname"
- ${EndIf}
- FunctionEnd
- Var cfg_line
- Var chk_line
- Var lst_check
- Function updateMinionConfig
- ClearErrors
- FileOpen $0 "$INSTDIR\conf\minion" "r" # open target file for reading
- GetTempFileName $R0 # get new temp file name
- FileOpen $1 $R0 "w" # open temp file for writing
- StrCpy $ConfigWriteMaster 1 # write the master config value
- StrCpy $ConfigWriteMinion 1 # write the minion config value
- loop: # loop through each line
- FileRead $0 $cfg_line # read line from target file
- IfErrors done # end if errors are encountered (end of line)
- loop_after_read:
- StrCpy $lst_check 0 # list check not performed
- ${If} $MasterHost_State == "" # if master is empty
- ${OrIf} $MasterHost_State == "salt" # or if master is 'salt'
- StrCpy $ConfigWriteMaster 0 # no need to write master config
- ${EndIf} # close if statement
- ${If} $MinionName_State == "" # if minion is empty
- ${OrIf} $MinionName_State == "hostname" # and if minion is not 'hostname'
- StrCpy $ConfigWriteMinion 0 # no need to write minion config
- ${EndIf} # close if statement
- ${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)
- ${Explode} $9 "," $MasterHost_state # 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_State$\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 $0 $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)
- StrCpy $cfg_line "id: $MinionName_State$\r$\n" # write the minion config setting
- StrCpy $ConfigWriteMinion 0 # minion value written to config
- ${EndIf} # close if statement
- ${EndIf} # close if statement
- FileWrite $1 $cfg_line # write changed or unchanged line to temp file
- ${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
- ${Explode} $9 "," $MasterHost_state # 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_State" # 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
- FileWrite $1 $cfg_line # write changed or unchanged line to temp file
- ${EndIf} # close if statement
- ${If} $ConfigWriteMinion == 1 # minion ID not written to the config
- StrCpy $cfg_line "$\r$\nid: $MinionName_State" # write the minion config setting
- FileWrite $1 $cfg_line # write changed or unchanged line to temp file
- ${EndIf} # close if statement
- FileClose $0 # close target file
- FileClose $1 # close temp file
- Delete "$INSTDIR\conf\minion" # delete target file
- CopyFiles /SILENT $R0 "$INSTDIR\conf\minion" # copy temp file to target file
- Delete $R0 # delete temp file
- FunctionEnd
- Function parseCommandLineSwitches
- # Load the parameters
- ${GetParameters} $R0
- # Display Help
- ClearErrors
- ${GetOptions} $R0 "/?" $R1
- IfErrors display_help_not_found
- System::Call 'kernel32::GetStdHandle(i -11)i.r0'
- System::Call 'kernel32::AttachConsole(i -1)i.r1'
- ${If} $0 = 0
- ${OrIf} $1 = 0
- System::Call 'kernel32::AllocConsole()'
- System::Call 'kernel32::GetStdHandle(i -11)i.r0'
- ${EndIf}
- FileWrite $0 "$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "Help for Salt Minion installation$\n"
- FileWrite $0 "===============================================================================$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "/minion-name=$\t$\tA string value to set the minion name. Default value is$\n"
- FileWrite $0 "$\t$\t$\t'hostname'. Setting the minion name causes the installer$\n"
- FileWrite $0 "$\t$\t$\tto use the default config or a custom config if defined$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "/master=$\t$\tA string value to set the IP address or hostname of the$\n"
- FileWrite $0 "$\t$\t$\tmaster. Default value is 'salt'. You may pass a single$\n"
- FileWrite $0 "$\t$\t$\tmaster or a comma-separated list of masters. Setting$\n"
- FileWrite $0 "$\t$\t$\tthe master will cause the installer to use the default$\n"
- FileWrite $0 "$\t$\t$\tconfig or a custom config if defined$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "/start-minion=$\t$\t1 will start the minion service, 0 will not.$\n"
- FileWrite $0 "$\t$\t$\tDefault is 1$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "/start-minion-delayed$\tSet the minion start type to 'Automatic (Delayed Start)'$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "/default-config$\t$\tOverwrite the existing config if present with the$\n"
- FileWrite $0 "$\t$\t$\tdefault config for salt. Default is to use the existing$\n"
- FileWrite $0 "$\t$\t$\tconfig if present. If /master and/or /minion-name is$\n"
- FileWrite $0 "$\t$\t$\tpassed, those values will be used to update the new$\n"
- FileWrite $0 "$\t$\t$\tdefault config$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "$\t$\t$\tAny existing config will be backed up by appending$\n"
- FileWrite $0 "$\t$\t$\ta timestamp and a .bak extension. That includes\n"
- FileWrite $0 "$\t$\t$\tthe minion file and the minion.d directory$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "/custom-config=$\t$\tA string value specifying the name of a custom config$\n"
- FileWrite $0 "$\t$\t$\tfile in the same path as the installer or the full path$\n"
- FileWrite $0 "$\t$\t$\tto a custom config file. If /master and/or /minion-name$\n"
- FileWrite $0 "$\t$\t$\tis passed, those values will be used to update the new$\n"
- FileWrite $0 "$\t$\t$\tcustom config$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "$\t$\t$\tAny existing config will be backed up by appending$\n"
- FileWrite $0 "$\t$\t$\ta timestamp and a .bak extension. That includes\n"
- FileWrite $0 "$\t$\t$\tthe minion file and the minion.d directory$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "/S$\t$\t$\tInstall Salt silently$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "/?$\t$\t$\tDisplay this help screen$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "-------------------------------------------------------------------------------$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "Examples:$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "${OutFile} /S$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "${OutFile} /S /minion-name=myminion /master=master.mydomain.com /start-minion-delayed$\n"
- FileWrite $0 "$\n"
- FileWrite $0 "===============================================================================$\n"
- FileWrite $0 "$\n"
- System::Free $0
- System::Free $1
- System::Call 'kernel32::FreeConsole()'
- # Give the user back the prompt
- !define VK_RETURN 0x0D ; Enter Key
- !define KEYEVENTF_EXTENDEDKEY 0x0001
- !define KEYEVENTF_KEYUP 0x0002
- System::Call "user32::keybd_event(i${VK_RETURN}, i0x45, i${KEYEVENTF_EXTENDEDKEY}|0, i0)"
- System::Call "user32::keybd_event(i${VK_RETURN}, i0x45, i${KEYEVENTF_EXTENDEDKEY}|${KEYEVENTF_KEYUP}, i0)"
- Abort
- display_help_not_found:
- # Set default value for Use Existing Config
- StrCpy $ConfigType_State "Existing Config"
- # Check for start-minion switches
- # /start-service is to be deprecated, so we must check for both
- ${GetOptions} $R0 "/start-service=" $R1
- ${GetOptions} $R0 "/start-minion=" $R2
- # Service: Start Salt Minion
- ${IfNot} $R2 == ""
- # If start-minion was passed something, then set it
- StrCpy $StartMinion $R2
- ${ElseIfNot} $R1 == ""
- # If start-service was passed something, then set StartMinion to that
- StrCpy $StartMinion $R1
- ${Else}
- # Otherwise default to 1
- StrCpy $StartMinion 1
- ${EndIf}
- # Service: Minion Startup Type Delayed
- ClearErrors
- ${GetOptions} $R0 "/start-minion-delayed" $R1
- IfErrors start_minion_delayed_not_found
- StrCpy $StartMinionDelayed 1
- start_minion_delayed_not_found:
- # Minion Config: Master IP/Name
- # If setting master, we don't want to use existing config
- ${GetOptions} $R0 "/master=" $R1
- ${IfNot} $R1 == ""
- StrCpy $MasterHost_State $R1
- StrCpy $ConfigType_State "Default Config"
- ${ElseIf} $MasterHost_State == ""
- StrCpy $MasterHost_State "salt"
- ${EndIf}
- # Minion Config: Minion ID
- # If setting minion id, we don't want to use existing config
- ${GetOptions} $R0 "/minion-name=" $R1
- ${IfNot} $R1 == ""
- StrCpy $MinionName_State $R1
- StrCpy $ConfigType_State "Default Config"
- ${ElseIf} $MinionName_State == ""
- StrCpy $MinionName_State "hostname"
- ${EndIf}
- # Use Default Config
- ${GetOptions} $R0 "/default-config" $R1
- IfErrors default_config_not_found
- StrCpy $ConfigType_State "Default Config"
- default_config_not_found:
- # Use Custom Config
- # Set default value for Use Custom Config
- StrCpy $CustomConfig_State ""
- # Existing config will get a `.bak` extension
- ${GetOptions} $R0 "/custom-config=" $R1
- ${IfNot} $R1 == ""
- # Custom Config was passed something, set it
- StrCpy $CustomConfig_State $R1
- StrCpy $ConfigType_State "Custom Config"
- ${EndIf}
- FunctionEnd
|