Salt-Minion-Setup.nsi 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546
  1. !define PRODUCT_NAME "Salt Minion"
  2. !define PRODUCT_NAME_OTHER "Salt"
  3. !define PRODUCT_PUBLISHER "SaltStack, Inc"
  4. !define PRODUCT_WEB_SITE "http://saltstack.org"
  5. !define PRODUCT_CALL_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-call.exe"
  6. !define PRODUCT_CP_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-cp.exe"
  7. !define PRODUCT_KEY_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-key.exe"
  8. !define PRODUCT_MASTER_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-master.exe"
  9. !define PRODUCT_MINION_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-minion.exe"
  10. !define PRODUCT_RUN_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\salt-run.exe"
  11. !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
  12. !define PRODUCT_UNINST_KEY_OTHER "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_OTHER}"
  13. !define PRODUCT_UNINST_ROOT_KEY "HKLM"
  14. !define OUTFILE "Salt-Minion-${PRODUCT_VERSION}-${CPUARCH}-Setup.exe"
  15. # Import Libraries
  16. !include "MUI2.nsh"
  17. !include "nsDialogs.nsh"
  18. !include "LogicLib.nsh"
  19. !include "FileFunc.nsh"
  20. !include "StrFunc.nsh"
  21. !include "x64.nsh"
  22. !include "WinMessages.nsh"
  23. !include "WinVer.nsh"
  24. ${StrLoc}
  25. ${StrStrAdv}
  26. !ifdef SaltVersion
  27. !define PRODUCT_VERSION "${SaltVersion}"
  28. !else
  29. !define PRODUCT_VERSION "Undefined Version"
  30. !endif
  31. !if "$%PROCESSOR_ARCHITECTURE%" == "AMD64"
  32. !define CPUARCH "AMD64"
  33. !else if "$%PROCESSOR_ARCHITEW6432%" == "AMD64"
  34. !define CPUARCH "AMD64"
  35. !else
  36. !define CPUARCH "x86"
  37. !endif
  38. # Part of the Trim function for Strings
  39. !define Trim "!insertmacro Trim"
  40. !macro Trim ResultVar String
  41. Push "${String}"
  42. Call Trim
  43. Pop "${ResultVar}"
  44. !macroend
  45. # Part of the Explode function for Strings
  46. !define Explode "!insertmacro Explode"
  47. !macro Explode Length Separator String
  48. Push `${Separator}`
  49. Push `${String}`
  50. Call Explode
  51. Pop `${Length}`
  52. !macroend
  53. ###############################################################################
  54. # Configure Pages, Ordering, and Configuration
  55. ###############################################################################
  56. !define MUI_ABORTWARNING
  57. !define MUI_ICON "salt.ico"
  58. !define MUI_UNICON "salt.ico"
  59. !define MUI_WELCOMEFINISHPAGE_BITMAP "panel.bmp"
  60. !define MUI_UNWELCOMEFINISHPAGE_BITMAP "panel.bmp"
  61. # Welcome page
  62. !insertmacro MUI_PAGE_WELCOME
  63. # License page
  64. !insertmacro MUI_PAGE_LICENSE "LICENSE.txt"
  65. # Configure Minion page
  66. Page custom pageMinionConfig pageMinionConfig_Leave
  67. # Instfiles page
  68. !insertmacro MUI_PAGE_INSTFILES
  69. # Finish page (Customized)
  70. !define MUI_PAGE_CUSTOMFUNCTION_SHOW pageFinish_Show
  71. !define MUI_PAGE_CUSTOMFUNCTION_LEAVE pageFinish_Leave
  72. !insertmacro MUI_PAGE_FINISH
  73. # Uninstaller pages
  74. !insertmacro MUI_UNPAGE_INSTFILES
  75. # Language files
  76. !insertmacro MUI_LANGUAGE "English"
  77. ###############################################################################
  78. # Custom Dialog Box Variables
  79. ###############################################################################
  80. Var Dialog
  81. Var Label
  82. Var CheckBox_Minion_Start
  83. Var CheckBox_Minion_Start_Delayed
  84. Var ConfigMasterHost
  85. Var MasterHost
  86. Var MasterHost_State
  87. Var ConfigMinionName
  88. Var MinionName
  89. Var MinionName_State
  90. Var ExistingConfigFound
  91. Var ConfigType
  92. Var ConfigType_State
  93. Var CustomConfig
  94. Var CustomConfig_btn
  95. Var CustomConfig_State
  96. Var WarningCustomConfig
  97. Var WarningExistingConfig
  98. Var WarningDefaultConfig
  99. Var StartMinion
  100. Var StartMinionDelayed
  101. Var DeleteInstallDir
  102. Var ConfigWriteMinion
  103. Var ConfigWriteMaster
  104. ###############################################################################
  105. # Minion Settings Dialog Box
  106. ###############################################################################
  107. Function pageMinionConfig
  108. # Set Page Title and Description
  109. !insertmacro MUI_HEADER_TEXT "Minion Settings" "Set the Minion Master and ID"
  110. nsDialogs::Create 1018
  111. Pop $Dialog
  112. ${If} $Dialog == error
  113. Abort
  114. ${EndIf}
  115. # Master IP or Hostname Dialog Control
  116. ${NSD_CreateLabel} 0 0 100% 12u "Master IP or Hostname:"
  117. Pop $Label
  118. ${NSD_CreateText} 0 13u 100% 12u $MasterHost_State
  119. Pop $MasterHost
  120. # Minion ID Dialog Control
  121. ${NSD_CreateLabel} 0 30u 100% 12u "Minion Name:"
  122. Pop $Label
  123. ${NSD_CreateText} 0 43u 100% 12u $MinionName_State
  124. Pop $MinionName
  125. # Config Drop List
  126. ${NSD_CreateDropList} 0 65u 25% 36u ""
  127. Pop $ConfigType
  128. ${NSD_CB_AddString} $ConfigType "Default Config"
  129. ${NSD_CB_AddString} $ConfigType "Custom Config"
  130. ${NSD_OnChange} $ConfigType pageMinionConfig_OnChange
  131. # Add Existing Config Warning Label
  132. ${NSD_CreateLabel} 0 80u 100% 60u "The values above are taken from an \
  133. existing configuration found in `c:\salt\conf\minion`. Configuration \
  134. settings defined in the `minion.d` directories, if they exist, are not \
  135. shown here.$\r$\n\
  136. $\r$\n\
  137. Clicking `Install` will leave the existing config unchanged."
  138. Pop $WarningExistingConfig
  139. CreateFont $0 "Arial" 10 500 /ITALIC
  140. SendMessage $WarningExistingConfig ${WM_SETFONT} $0 1
  141. SetCtlColors $WarningExistingConfig 0xBB0000 transparent
  142. # Add Default Config Warning Label
  143. ${NSD_CreateLabel} 0 80u 100% 60u "Clicking `Install` will backup the \
  144. the existing minion config file and minion.d directories. The values \
  145. above will be used in the new default config.$\r$\n\
  146. $\r$\n\
  147. NOTE: If Master IP is set to `salt` and Minion Name is set to \
  148. `hostname` no changes will be made."
  149. Pop $WarningDefaultConfig
  150. CreateFont $0 "Arial" 10 500 /ITALIC
  151. SendMessage $WarningDefaultConfig ${WM_SETFONT} $0 1
  152. SetCtlColors $WarningDefaultConfig 0xBB0000 transparent
  153. # Add Custom Config File Selector and Warning Label
  154. ${NSD_CreateText} 26% 65u 64% 12u $CustomConfig_State
  155. Pop $CustomConfig
  156. ${NSD_CreateButton} 91% 65u 9% 12u "..."
  157. Pop $CustomConfig_btn
  158. ${NSD_OnClick} $CustomConfig_btn pageCustomConfigBtn_OnClick
  159. ${If} $ExistingConfigFound == 0
  160. ${NSD_CreateLabel} 0 80u 100% 60u "Values entered above will be used \
  161. in the custom config.$\r$\n\
  162. $\r$\n\
  163. NOTE: If Master IP is set to `salt` and Minion Name is set to \
  164. `hostname` no changes will be made."
  165. ${Else}
  166. ${NSD_CreateLabel} 0 80u 100% 60u "Clicking `Install` will backup the \
  167. the existing minion config file and minion.d directories. The \
  168. values above will be used in the custom config.$\r$\n\
  169. $\r$\n\
  170. NOTE: If Master IP is set to `salt` and Minion Name is set to \
  171. `hostname` no changes will be made."
  172. ${Endif}
  173. Pop $WarningCustomConfig
  174. CreateFont $0 "Arial" 10 500 /ITALIC
  175. SendMessage $WarningCustomConfig ${WM_SETFONT} $0 1
  176. SetCtlColors $WarningCustomConfig 0xBB0000 transparent
  177. # If existing config found, add the Existing Config option to the Drop List
  178. # If not, hide the Default Warning
  179. ${If} $ExistingConfigFound == 1
  180. ${NSD_CB_AddString} $ConfigType "Existing Config"
  181. ${Else}
  182. ShowWindow $WarningDefaultConfig ${SW_HIDE}
  183. ${Endif}
  184. ${NSD_CB_SelectString} $ConfigType $ConfigType_State
  185. ${NSD_SetText} $CustomConfig $CustomConfig_State
  186. Call pageMinionConfig_OnChange
  187. nsDialogs::Show
  188. FunctionEnd
  189. Function pageMinionConfig_OnChange
  190. # You have to pop the top handle to keep the stack clean
  191. Pop $R0
  192. # Assign the current checkbox state to the variable
  193. ${NSD_GetText} $ConfigType $ConfigType_State
  194. # Update Dialog
  195. ${Switch} $ConfigType_State
  196. ${Case} "Existing Config"
  197. # Enable Master/Minion and set values
  198. EnableWindow $MasterHost 0
  199. EnableWindow $MinionName 0
  200. ${NSD_SetText} $MasterHost $ConfigMasterHost
  201. ${NSD_SetText} $MinionName $ConfigMinionName
  202. # Hide Custom File Picker
  203. ShowWindow $CustomConfig ${SW_HIDE}
  204. ShowWindow $CustomConfig_btn ${SW_HIDE}
  205. # Hide Warnings
  206. ShowWindow $WarningDefaultConfig ${SW_HIDE}
  207. ShowWindow $WarningCustomConfig ${SW_HIDE}
  208. # Show Existing Warning
  209. ShowWindow $WarningExistingConfig ${SW_SHOW}
  210. ${Break}
  211. ${Case} "Custom Config"
  212. # Enable Master/Minion and set values
  213. EnableWindow $MasterHost 1
  214. EnableWindow $MinionName 1
  215. ${NSD_SetText} $MasterHost $MasterHost_State
  216. ${NSD_SetText} $MinionName $MinionName_State
  217. # Show Custom File Picker
  218. ShowWindow $CustomConfig ${SW_SHOW}
  219. ShowWindow $CustomConfig_btn ${SW_SHOW}
  220. # Hide Warnings
  221. ShowWindow $WarningDefaultConfig ${SW_HIDE}
  222. ShowWindow $WarningExistingConfig ${SW_HIDE}
  223. # Show Custom Warning
  224. ShowWindow $WarningCustomConfig ${SW_SHOW}
  225. ${Break}
  226. ${Case} "Default Config"
  227. # Enable Master/Minion and set values
  228. EnableWindow $MasterHost 1
  229. EnableWindow $MinionName 1
  230. ${NSD_SetText} $MasterHost $MasterHost_State
  231. ${NSD_SetText} $MinionName $MinionName_State
  232. # Hide Custom File Picker
  233. ShowWindow $CustomConfig ${SW_HIDE}
  234. ShowWindow $CustomConfig_btn ${SW_HIDE}
  235. # Hide Warnings
  236. ShowWindow $WarningExistingConfig ${SW_HIDE}
  237. ShowWindow $WarningCustomConfig ${SW_HIDE}
  238. # Show Default Warning, if there is an existing config
  239. ${If} $ExistingConfigFound == 1
  240. ShowWindow $WarningDefaultConfig ${SW_SHOW}
  241. ${Endif}
  242. ${Break}
  243. ${EndSwitch}
  244. FunctionEnd
  245. # File Picker Definitions
  246. !define OFN_FILEMUSTEXIST 0x00001000
  247. !define OFN_DONTADDTOREC 0x02000000
  248. !define OPENFILENAME_SIZE_VERSION_400 76
  249. !define OPENFILENAME 'i,i,i,i,i,i,i,i,i,i,i,i,i,i,&i2,&i2,i,i,i,i'
  250. Function pageCustomConfigBtn_OnClick
  251. Pop $0
  252. System::Call '*(&t${NSIS_MAX_STRLEN})i.s' # Allocate OPENFILENAME.lpstrFile buffer
  253. System::Call '*(${OPENFILENAME})i.r0' # Allocate OPENFILENAME struct
  254. System::Call '*$0(${OPENFILENAME})(${OPENFILENAME_SIZE_VERSION_400}, \
  255. $hwndparent, , , , , , sr1, ${NSIS_MAX_STRLEN} , , , , \
  256. t"Select Custom Config File", \
  257. ${OFN_FILEMUSTEXIST} | ${OFN_DONTADDTOREC})'
  258. # Populate file name field
  259. ${NSD_GetText} $CustomConfig $2
  260. System::Call "*$1(&t${NSIS_MAX_STRLEN}r2)" ; Set lpstrFile to the old path (if any)
  261. # Open the dialog
  262. System::Call 'COMDLG32::GetOpenFileName(ir0)i.r2'
  263. # Get file name field
  264. ${If} $2 <> 0
  265. System::Call "*$1(&t${NSIS_MAX_STRLEN}.r2)"
  266. ${NSD_SetText} $CustomConfig $2
  267. ${EndIf}
  268. # Free resources
  269. System::Free $1
  270. System::Free $0
  271. FunctionEnd
  272. Function pageMinionConfig_Leave
  273. # Save the State
  274. ${NSD_GetText} $MasterHost $MasterHost_State
  275. ${NSD_GetText} $MinionName $MinionName_State
  276. ${NSD_GetText} $ConfigType $ConfigType_State
  277. ${NSD_GetText} $CustomConfig $CustomConfig_State
  278. # Abort if config file not found
  279. ${If} $ConfigType_State == "Custom Config"
  280. IfFileExists "$CustomConfig_State" continue 0
  281. MessageBox MB_OK "File not found: $CustomConfig_State" /SD IDOK
  282. Abort
  283. ${EndIf}
  284. continue:
  285. Call BackupExistingConfig
  286. FunctionEnd
  287. ###############################################################################
  288. # Custom Finish Page
  289. ###############################################################################
  290. Function pageFinish_Show
  291. # Imports so the checkboxes will show up
  292. !define SWP_NOSIZE 0x0001
  293. !define SWP_NOMOVE 0x0002
  294. !define HWND_TOP 0x0000
  295. # Create Start Minion Checkbox
  296. ${NSD_CreateCheckbox} 120u 90u 100% 12u "&Start salt-minion"
  297. Pop $CheckBox_Minion_Start
  298. SetCtlColors $CheckBox_Minion_Start "" "ffffff"
  299. # This command required to bring the checkbox to the front
  300. 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})"
  301. # Create Start Minion Delayed ComboBox
  302. ${NSD_CreateCheckbox} 130u 102u 100% 12u "&Delayed Start"
  303. Pop $CheckBox_Minion_Start_Delayed
  304. SetCtlColors $CheckBox_Minion_Start_Delayed "" "ffffff"
  305. # This command required to bring the checkbox to the front
  306. 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})"
  307. # Load current settings for Minion
  308. ${If} $StartMinion == 1
  309. ${NSD_Check} $CheckBox_Minion_Start
  310. ${EndIf}
  311. # Load current settings for Minion Delayed
  312. ${If} $StartMinionDelayed == 1
  313. ${NSD_Check} $CheckBox_Minion_Start_Delayed
  314. ${EndIf}
  315. FunctionEnd
  316. Function pageFinish_Leave
  317. # Assign the current checkbox states
  318. ${NSD_GetState} $CheckBox_Minion_Start $StartMinion
  319. ${NSD_GetState} $CheckBox_Minion_Start_Delayed $StartMinionDelayed
  320. FunctionEnd
  321. ###############################################################################
  322. # Installation Settings
  323. ###############################################################################
  324. Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
  325. OutFile "${OutFile}"
  326. InstallDir "c:\salt"
  327. InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
  328. ShowInstDetails show
  329. ShowUnInstDetails show
  330. Section -copy_prereqs
  331. # Copy prereqs to the Plugins Directory
  332. # These files will be KB2999226 for Win8.1 and below
  333. # These files are downloaded by build_pkg.bat
  334. # This directory gets removed upon completion
  335. SetOutPath "$PLUGINSDIR\"
  336. File /r "..\prereqs\"
  337. SectionEnd
  338. # Check and install the Windows 10 Universal C Runtime (KB2999226)
  339. # ucrt is needed on Windows 8.1 and lower
  340. # They are installed as a Microsoft Update package (.msu)
  341. # ucrt for Windows 8.1 RT is only available via Windows Update
  342. Section -install_ucrt
  343. Var /GLOBAL MsuPrefix
  344. Var /GLOBAL MsuFileName
  345. # Get the Major.Minor version Number
  346. # Windows 10 introduced CurrentMajorVersionNumber
  347. ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" \
  348. CurrentMajorVersionNumber
  349. # Windows 10/2016 will return a value here, skip to the end if returned
  350. StrCmp $R0 '' lbl_needs_ucrt 0
  351. # Found Windows 10
  352. detailPrint "KB2999226 does not apply to this machine"
  353. goto lbl_done
  354. lbl_needs_ucrt:
  355. # UCRT only needed on Windows Server 2012R2/Windows 8.1 and below
  356. # The first ReadRegStr command above should have skipped to lbl_done if on
  357. # Windows 10 box
  358. # Is the update already installed
  359. ClearErrors
  360. # Use WMI to check if it's installed
  361. detailPrint "Checking for existing KB2999226 installation"
  362. nsExec::ExecToStack 'cmd /q /c wmic qfe get hotfixid | findstr "^KB2999226"'
  363. # Clean up the stack
  364. Pop $R0 # Gets the ErrorCode
  365. Pop $R1 # Gets the stdout, which should be KB2999226 if it's installed
  366. # If it returned KB2999226 it's already installed
  367. StrCmp $R1 'KB2999226' lbl_done
  368. detailPrint "KB2999226 not found"
  369. # All lower versions of Windows
  370. ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" \
  371. CurrentVersion
  372. # Get the name of the .msu file based on the value of $R0
  373. ${Switch} "$R0"
  374. ${Case} "6.3"
  375. StrCpy $MsuPrefix "Windows8.1"
  376. ${break}
  377. ${Case} "6.2"
  378. StrCpy $MsuPrefix "Windows8-RT"
  379. ${break}
  380. ${Case} "6.1"
  381. StrCpy $MsuPrefix "Windows6.1"
  382. ${break}
  383. ${Case} "6.0"
  384. StrCpy $MsuPrefix "Windows6.0"
  385. ${break}
  386. ${EndSwitch}
  387. # Use RunningX64 here to get the Architecture for the system running the installer
  388. # CPUARCH is defined when the installer is built and is based on the machine that
  389. # built the installer, not the target system as we need here.
  390. ${If} ${RunningX64}
  391. StrCpy $MsuFileName "$MsuPrefix-KB2999226-x64.msu"
  392. ${Else}
  393. StrCpy $MsuFileName "$MsuPrefix-KB2999226-x86.msu"
  394. ${EndIf}
  395. ClearErrors
  396. detailPrint "Installing KB2999226 using file $MsuFileName"
  397. nsExec::ExecToStack 'cmd /c wusa "$PLUGINSDIR\$MsuFileName" /quiet /norestart'
  398. # Clean up the stack
  399. Pop $R0 # Get Error
  400. Pop $R1 # Get stdout
  401. ${IfNot} $R0 == 0
  402. detailPrint "error: $R0"
  403. detailPrint "output: $R2"
  404. Sleep 3000
  405. ${Else}
  406. detailPrint "KB2999226 installed successfully"
  407. ${EndIf}
  408. lbl_done:
  409. SectionEnd
  410. Section "MainSection" SEC01
  411. SetOutPath "$INSTDIR\"
  412. SetOverwrite off
  413. CreateDirectory $INSTDIR\conf\pki\minion
  414. CreateDirectory $INSTDIR\conf\minion.d
  415. File /r "..\buildenv\"
  416. 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'
  417. SectionEnd
  418. Function .onInit
  419. Call parseCommandLineSwitches
  420. # Uninstall msi-installed salt
  421. # Source https://nsis-dev.github.io/NSIS-Forums/html/t-303468.html
  422. !define upgradecode {FC6FB3A2-65DE-41A9-AD91-D10A402BD641} ;Salt upgrade code
  423. StrCpy $0 0
  424. loop:
  425. System::Call 'MSI::MsiEnumRelatedProducts(t "${upgradecode}",i0,i r0,t.r1)i.r2'
  426. ${If} $2 = 0
  427. # Now $1 contains the product code
  428. DetailPrint product:$1
  429. push $R0
  430. StrCpy $R0 $1
  431. Call UninstallMSI
  432. pop $R0
  433. IntOp $0 $0 + 1
  434. goto loop
  435. ${Endif}
  436. # If custom config passed, verify its existence before continuing so we
  437. # don't uninstall an existing installation and then fail
  438. ${If} $ConfigType_State == "Custom Config"
  439. IfFileExists "$CustomConfig_State" customConfigExists 0
  440. Abort
  441. ${EndIf}
  442. customConfigExists:
  443. # Check for existing installation
  444. ReadRegStr $R0 HKLM \
  445. "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \
  446. "UninstallString"
  447. StrCmp $R0 "" checkOther
  448. # Found existing installation, prompt to uninstall
  449. MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
  450. "${PRODUCT_NAME} is already installed.$\n$\n\
  451. Click `OK` to remove the existing installation." \
  452. /SD IDOK IDOK uninst
  453. Abort
  454. checkOther:
  455. # Check for existing installation of full salt
  456. ReadRegStr $R0 HKLM \
  457. "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_OTHER}" \
  458. "UninstallString"
  459. StrCmp $R0 "" skipUninstall
  460. # Found existing installation, prompt to uninstall
  461. MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
  462. "${PRODUCT_NAME_OTHER} is already installed.$\n$\n\
  463. Click `OK` to remove the existing installation." \
  464. /SD IDOK IDOK uninst
  465. Abort
  466. uninst:
  467. # Get current Silent status
  468. StrCpy $R0 0
  469. ${If} ${Silent}
  470. StrCpy $R0 1
  471. ${EndIf}
  472. # Turn on Silent mode
  473. SetSilent silent
  474. # Don't remove all directories
  475. StrCpy $DeleteInstallDir 0
  476. # Uninstall silently
  477. Call uninstallSalt
  478. # Set it back to Normal mode, if that's what it was before
  479. ${If} $R0 == 0
  480. SetSilent normal
  481. ${EndIf}
  482. skipUninstall:
  483. Call getExistingMinionConfig
  484. ${If} $ExistingConfigFound == 0
  485. ${AndIf} $ConfigType_State == "Existing Config"
  486. StrCpy $ConfigType_State "Default Config"
  487. ${EndIf}
  488. IfSilent 0 +2
  489. Call BackupExistingConfig
  490. FunctionEnd
  491. # Time Stamp Definition
  492. !define /date TIME_STAMP "%Y-%m-%d-%H-%M-%S"
  493. Function BackupExistingConfig
  494. ${If} $ExistingConfigFound == 1 # If existing config found
  495. ${AndIfNot} $ConfigType_State == "Existing Config" # If not using Existing Config
  496. # Backup the minion config
  497. Rename "$INSTDIR\conf\minion" "$INSTDIR\conf\minion-${TIME_STAMP}.bak"
  498. IfFileExists "$INSTDIR\conf\minion.d" 0 +2
  499. Rename "$INSTDIR\conf\minion.d" "$INSTDIR\conf\minion.d-${TIME_STAMP}.bak"
  500. ${EndIf}
  501. # By this point there should be no existing config
  502. # It was either backed up or wasn't there to begin with
  503. ${If} $ConfigType_State == "Custom Config" # If we're using Custom Config
  504. ${AndIfNot} $CustomConfig_State == "" # If a custom config is passed
  505. # Check for a file name
  506. # Named file should be in the same directory as the installer
  507. CreateDirectory "$INSTDIR\conf"
  508. IfFileExists "$EXEDIR\$CustomConfig_State" 0 checkFullPath
  509. CopyFiles /SILENT /FILESONLY "$EXEDIR\$CustomConfig_State" "$INSTDIR\conf\minion"
  510. goto finished
  511. # Maybe it was a full path to a file
  512. checkFullPath:
  513. IfFileExists "$CustomConfig_State" 0 finished
  514. CopyFiles /SILENT /FILESONLY "$CustomConfig_State" "$INSTDIR\conf\minion"
  515. finished:
  516. ${EndIf}
  517. FunctionEnd
  518. Section -Post
  519. WriteUninstaller "$INSTDIR\uninst.exe"
  520. # Uninstall Registry Entries
  521. WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
  522. "DisplayName" "$(^Name)"
  523. WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
  524. "UninstallString" "$INSTDIR\uninst.exe"
  525. WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
  526. "DisplayIcon" "$INSTDIR\salt.ico"
  527. WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
  528. "DisplayVersion" "${PRODUCT_VERSION}"
  529. WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
  530. "URLInfoAbout" "${PRODUCT_WEB_SITE}"
  531. WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
  532. "Publisher" "${PRODUCT_PUBLISHER}"
  533. WriteRegStr HKLM "SYSTEM\CurrentControlSet\services\salt-minion" \
  534. "DependOnService" "nsi"
  535. # Set the estimated size
  536. ${GetSize} "$INSTDIR\bin" "/S=OK" $0 $1 $2
  537. IntFmt $0 "0x%08X" $0
  538. WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \
  539. "EstimatedSize" "$0"
  540. # Commandline Registry Entries
  541. WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "" "$INSTDIR\salt-call.bat"
  542. WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "Path" "$INSTDIR\bin\"
  543. WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "" "$INSTDIR\salt-minion.bat"
  544. WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "Path" "$INSTDIR\bin\"
  545. # Register the Salt-Minion Service
  546. 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"
  547. nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Description Salt Minion from saltstack.com"
  548. nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Start SERVICE_AUTO_START"
  549. nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion AppStopMethodConsole 24000"
  550. nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion AppStopMethodWindow 2000"
  551. ${IfNot} $ConfigType_State == "Existing Config" # If not using Existing Config
  552. Call updateMinionConfig
  553. ${EndIf}
  554. Push "C:\salt"
  555. Call AddToPath
  556. SectionEnd
  557. Function .onInstSuccess
  558. # If StartMinionDelayed is 1, then set the service to start delayed
  559. ${If} $StartMinionDelayed == 1
  560. nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Start SERVICE_DELAYED_AUTO_START"
  561. ${EndIf}
  562. # If start-minion is 1, then start the service
  563. ${If} $StartMinion == 1
  564. nsExec::Exec 'net start salt-minion'
  565. ${EndIf}
  566. FunctionEnd
  567. Function un.onInit
  568. # Load the parameters
  569. ${GetParameters} $R0
  570. # Uninstaller: Remove Installation Directory
  571. ClearErrors
  572. ${GetOptions} $R0 "/delete-install-dir" $R1
  573. IfErrors delete_install_dir_not_found
  574. StrCpy $DeleteInstallDir 1
  575. delete_install_dir_not_found:
  576. MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 \
  577. "Are you sure you want to completely remove $(^Name) and all of its components?" \
  578. /SD IDYES IDYES +2
  579. Abort
  580. FunctionEnd
  581. Section Uninstall
  582. Call un.uninstallSalt
  583. # Remove C:\salt from the Path
  584. Push "C:\salt"
  585. Call un.RemoveFromPath
  586. SectionEnd
  587. !macro uninstallSalt un
  588. Function ${un}uninstallSalt
  589. # Make sure we're in the right directory
  590. ${If} $INSTDIR == "c:\salt\bin\Scripts"
  591. StrCpy $INSTDIR "C:\salt"
  592. ${EndIf}
  593. # Stop and Remove salt-minion service
  594. nsExec::Exec 'net stop salt-minion'
  595. nsExec::Exec 'sc delete salt-minion'
  596. # Stop and remove the salt-master service
  597. nsExec::Exec 'net stop salt-master'
  598. nsExec::Exec 'sc delete salt-master'
  599. # Remove files
  600. Delete "$INSTDIR\uninst.exe"
  601. Delete "$INSTDIR\ssm.exe"
  602. Delete "$INSTDIR\salt*"
  603. Delete "$INSTDIR\vcredist.exe"
  604. RMDir /r "$INSTDIR\bin"
  605. # Remove Registry entries
  606. DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
  607. DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY_OTHER}"
  608. DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_CALL_REGKEY}"
  609. DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_CP_REGKEY}"
  610. DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_KEY_REGKEY}"
  611. DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_MASTER_REGKEY}"
  612. DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_MINION_REGKEY}"
  613. DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_RUN_REGKEY}"
  614. # Automatically close when finished
  615. SetAutoClose true
  616. # Prompt to remove the Installation directory
  617. ${IfNot} $DeleteInstallDir == 1
  618. MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 \
  619. "Would you like to completely remove $INSTDIR and all of its contents?" \
  620. /SD IDNO IDNO finished
  621. ${EndIf}
  622. # Make sure you're not removing Program Files
  623. ${If} $INSTDIR != 'Program Files'
  624. ${AndIf} $INSTDIR != 'Program Files (x86)'
  625. RMDir /r "$INSTDIR"
  626. ${EndIf}
  627. finished:
  628. FunctionEnd
  629. !macroend
  630. !insertmacro uninstallSalt ""
  631. !insertmacro uninstallSalt "un."
  632. Function un.onUninstSuccess
  633. HideWindow
  634. MessageBox MB_ICONINFORMATION|MB_OK \
  635. "$(^Name) was successfully removed from your computer." \
  636. /SD IDOK
  637. FunctionEnd
  638. ###############################################################################
  639. # Helper Functions
  640. ###############################################################################
  641. #------------------------------------------------------------------------------
  642. # Trim Function
  643. # - Trim whitespace from the beginning and end of a string
  644. # - Trims spaces, \r, \n, \t
  645. #
  646. # Usage:
  647. # Push " some string " ; String to Trim
  648. # Call Trim
  649. # Pop $0 ; Trimmed String: "some string"
  650. #
  651. # or
  652. #
  653. # ${Trim} $0 $1 ; Trimmed String, String to Trim
  654. #------------------------------------------------------------------------------
  655. Function Trim
  656. Exch $R1 # Original string
  657. Push $R2
  658. Loop:
  659. StrCpy $R2 "$R1" 1
  660. StrCmp "$R2" " " TrimLeft
  661. StrCmp "$R2" "$\r" TrimLeft
  662. StrCmp "$R2" "$\n" TrimLeft
  663. StrCmp "$R2" "$\t" TrimLeft
  664. GoTo Loop2
  665. TrimLeft:
  666. StrCpy $R1 "$R1" "" 1
  667. Goto Loop
  668. Loop2:
  669. StrCpy $R2 "$R1" 1 -1
  670. StrCmp "$R2" " " TrimRight
  671. StrCmp "$R2" "$\r" TrimRight
  672. StrCmp "$R2" "$\n" TrimRight
  673. StrCmp "$R2" "$\t" TrimRight
  674. GoTo Done
  675. TrimRight:
  676. StrCpy $R1 "$R1" -1
  677. Goto Loop2
  678. Done:
  679. Pop $R2
  680. Exch $R1
  681. FunctionEnd
  682. #------------------------------------------------------------------------------
  683. # Explode Function
  684. # - Splits a string based off the passed separator
  685. # - Each item in the string is pushed to the stack
  686. # - The last item pushed to the stack is the length of the array
  687. #
  688. # Usage:
  689. # Push "," ; Separator
  690. # Push "string,to,separate" ; String to explode
  691. # Call Explode
  692. # Pop $0 ; Number of items in the array
  693. #
  694. # or
  695. #
  696. # ${Explode} $0 $1 $2 ; Length, Separator, String
  697. #------------------------------------------------------------------------------
  698. Function Explode
  699. # Initialize variables
  700. Var /GLOBAL explString
  701. Var /GLOBAL explSeparator
  702. Var /GLOBAL explStrLen
  703. Var /GLOBAL explSepLen
  704. Var /GLOBAL explOffset
  705. Var /GLOBAL explTmp
  706. Var /GLOBAL explTmp2
  707. Var /GLOBAL explTmp3
  708. Var /GLOBAL explArrCount
  709. # Get input from user
  710. Pop $explString
  711. Pop $explSeparator
  712. # Calculates initial values
  713. StrLen $explStrLen $explString
  714. StrLen $explSepLen $explSeparator
  715. StrCpy $explArrCount 1
  716. ${If} $explStrLen <= 1 # If we got a single character
  717. ${OrIf} $explSepLen > $explStrLen # or separator is larger than the string,
  718. Push $explString # then we return initial string with no change
  719. Push 1 # and set array's length to 1
  720. Return
  721. ${EndIf}
  722. # Set offset to the last symbol of the string
  723. StrCpy $explOffset $explStrLen
  724. IntOp $explOffset $explOffset - 1
  725. # Clear temp string to exclude the possibility of appearance of occasional data
  726. StrCpy $explTmp ""
  727. StrCpy $explTmp2 ""
  728. StrCpy $explTmp3 ""
  729. # Loop until the offset becomes negative
  730. ${Do}
  731. # If offset becomes negative, it is time to leave the function
  732. ${IfThen} $explOffset == -1 ${|} ${ExitDo} ${|}
  733. # Remove everything before and after the searched part ("TempStr")
  734. StrCpy $explTmp $explString $explSepLen $explOffset
  735. ${If} $explTmp == $explSeparator
  736. # Calculating offset to start copy from
  737. IntOp $explTmp2 $explOffset + $explSepLen # Offset equals to the current offset plus length of separator
  738. StrCpy $explTmp3 $explString "" $explTmp2
  739. Push $explTmp3 # Throwing array item to the stack
  740. IntOp $explArrCount $explArrCount + 1 # Increasing array's counter
  741. StrCpy $explString $explString $explOffset 0 # Cutting all characters beginning with the separator entry
  742. StrLen $explStrLen $explString
  743. ${EndIf}
  744. ${If} $explOffset = 0 # If the beginning of the line met and there is no separator,
  745. # copying the rest of the string
  746. ${If} $explSeparator == "" # Fix for the empty separator
  747. IntOp $explArrCount $explArrCount - 1
  748. ${Else}
  749. Push $explString
  750. ${EndIf}
  751. ${EndIf}
  752. IntOp $explOffset $explOffset - 1
  753. ${Loop}
  754. Push $explArrCount
  755. FunctionEnd
  756. #------------------------------------------------------------------------------
  757. # StrStr Function
  758. # - find substring in a string
  759. #
  760. # Usage:
  761. # Push "this is some string"
  762. # Push "some"
  763. # Call StrStr
  764. # Pop $0 # "some string"
  765. #------------------------------------------------------------------------------
  766. !macro StrStr un
  767. Function ${un}StrStr
  768. Exch $R1 # $R1=substring, stack=[old$R1,string,...]
  769. Exch # stack=[string,old$R1,...]
  770. Exch $R2 # $R2=string, stack=[old$R2,old$R1,...]
  771. Push $R3 # $R3=strlen(substring)
  772. Push $R4 # $R4=count
  773. Push $R5 # $R5=tmp
  774. StrLen $R3 $R1 # Get the length of the Search String
  775. StrCpy $R4 0 # Set the counter to 0
  776. loop:
  777. StrCpy $R5 $R2 $R3 $R4 # Create a moving window of the string that is
  778. # the size of the length of the search string
  779. StrCmp $R5 $R1 done # Is the contents of the window the same as
  780. # search string, then done
  781. StrCmp $R5 "" done # Is the window empty, then done
  782. IntOp $R4 $R4 + 1 # Shift the windows one character
  783. Goto loop # Repeat
  784. done:
  785. StrCpy $R1 $R2 "" $R4
  786. Pop $R5
  787. Pop $R4
  788. Pop $R3
  789. Pop $R2
  790. Exch $R1 # $R1=old$R1, stack=[result,...]
  791. FunctionEnd
  792. !macroend
  793. !insertmacro StrStr ""
  794. !insertmacro StrStr "un."
  795. #------------------------------------------------------------------------------
  796. # AddToPath Function
  797. # - Adds item to Path for All Users
  798. # - Overcomes NSIS ReadRegStr limitation of 1024 characters by using Native
  799. # Windows Commands
  800. #
  801. # Usage:
  802. # Push "C:\path\to\add"
  803. # Call AddToPath
  804. #------------------------------------------------------------------------------
  805. !define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
  806. Function AddToPath
  807. Exch $0 # Path to add
  808. Push $1 # Current Path
  809. Push $2 # Results of StrStr / Length of Path + Path to Add
  810. Push $3 # Handle to Reg / Length of Path
  811. Push $4 # Result of Registry Call
  812. # Open a handle to the key in the registry, handle in $3, Error in $4
  813. System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
  814. # Make sure registry handle opened successfully (returned 0)
  815. IntCmp $4 0 0 done done
  816. # Load the contents of path into $1, Error Code into $4, Path length into $2
  817. System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
  818. # Close the handle to the registry ($3)
  819. System::Call "advapi32::RegCloseKey(i $3)"
  820. # Check for Error Code 234, Path too long for the variable
  821. IntCmp $4 234 0 +4 +4 # $4 == ERROR_MORE_DATA
  822. DetailPrint "AddToPath Failed: original length $2 > ${NSIS_MAX_STRLEN}"
  823. MessageBox MB_OK \
  824. "You may add C:\salt to the %PATH% for convenience when issuing local salt commands from the command line." \
  825. /SD IDOK
  826. Goto done
  827. # If no error, continue
  828. IntCmp $4 0 +5 # $4 != NO_ERROR
  829. # Error 2 means the Key was not found
  830. IntCmp $4 2 +3 # $4 != ERROR_FILE_NOT_FOUND
  831. DetailPrint "AddToPath: unexpected error code $4"
  832. Goto done
  833. StrCpy $1 ""
  834. # Check if already in PATH
  835. Push "$1;" # The string to search
  836. Push "$0;" # The string to find
  837. Call StrStr
  838. Pop $2 # The result of the search
  839. StrCmp $2 "" 0 done # String not found, try again with ';' at the end
  840. # Otherwise, it's already in the path
  841. Push "$1;" # The string to search
  842. Push "$0\;" # The string to find
  843. Call StrStr
  844. Pop $2 # The result
  845. StrCmp $2 "" 0 done # String not found, continue (add)
  846. # Otherwise, it's already in the path
  847. # Prevent NSIS string overflow
  848. StrLen $2 $0 # Length of path to add ($2)
  849. StrLen $3 $1 # Length of current path ($3)
  850. IntOp $2 $2 + $3 # Length of current path + path to add ($2)
  851. IntOp $2 $2 + 2 # Account for the additional ';'
  852. # $2 = strlen(dir) + strlen(PATH) + sizeof(";")
  853. # Make sure the new length isn't over the NSIS_MAX_STRLEN
  854. IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0
  855. DetailPrint "AddToPath Failed: new length $2 > ${NSIS_MAX_STRLEN}"
  856. MessageBox MB_OK \
  857. "You may add C:\salt to the %PATH% for convenience when issuing local salt commands from the command line." \
  858. /SD IDOK
  859. Goto done
  860. # Append dir to PATH
  861. DetailPrint "Add to PATH: $0"
  862. StrCpy $2 $1 1 -1 # Copy the last character of the existing path
  863. StrCmp $2 ";" 0 +2 # Check for trailing ';'
  864. StrCpy $1 $1 -1 # remove trailing ';'
  865. StrCmp $1 "" +2 # Make sure Path is not empty
  866. StrCpy $0 "$1;$0" # Append new path at the end ($0)
  867. # We can use the NSIS command here. Only 'ReadRegStr' is affected
  868. WriteRegExpandStr ${Environ} "PATH" $0
  869. # Broadcast registry change to open programs
  870. SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
  871. done:
  872. Pop $4
  873. Pop $3
  874. Pop $2
  875. Pop $1
  876. Pop $0
  877. FunctionEnd
  878. #------------------------------------------------------------------------------
  879. # RemoveFromPath Function
  880. # - Removes item from Path for All Users
  881. # - Overcomes NSIS ReadRegStr limitation of 1024 characters by using Native
  882. # Windows Commands
  883. #
  884. # Usage:
  885. # Push "C:\path\to\add"
  886. # Call un.RemoveFromPath
  887. #------------------------------------------------------------------------------
  888. Function un.RemoveFromPath
  889. Exch $0
  890. Push $1
  891. Push $2
  892. Push $3
  893. Push $4
  894. Push $5
  895. Push $6
  896. # Open a handle to the key in the registry, handle in $3, Error in $4
  897. System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
  898. # Make sure registry handle opened successfully (returned 0)
  899. IntCmp $4 0 0 done done
  900. # Load the contents of path into $1, Error Code into $4, Path length into $2
  901. System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
  902. # Close the handle to the registry ($3)
  903. System::Call "advapi32::RegCloseKey(i $3)"
  904. # Check for Error Code 234, Path too long for the variable
  905. IntCmp $4 234 0 +4 +4 # $4 == ERROR_MORE_DATA
  906. DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}"
  907. Goto done
  908. # If no error, continue
  909. IntCmp $4 0 +5 # $4 != NO_ERROR
  910. # Error 2 means the Key was not found
  911. IntCmp $4 2 +3 # $4 != ERROR_FILE_NOT_FOUND
  912. DetailPrint "AddToPath: unexpected error code $4"
  913. Goto done
  914. StrCpy $1 ""
  915. # Ensure there's a trailing ';'
  916. StrCpy $5 $1 1 -1 # Copy the last character of the path
  917. StrCmp $5 ";" +2 # Check for trailing ';', if found continue
  918. StrCpy $1 "$1;" # ensure trailing ';'
  919. # Check for our directory inside the path
  920. Push $1 # String to Search
  921. Push "$0;" # Dir to Find
  922. Call un.StrStr
  923. Pop $2 # The results of the search
  924. StrCmp $2 "" done # If results are empty, we're done, otherwise continue
  925. # Remove our Directory from the Path
  926. DetailPrint "Remove from PATH: $0"
  927. StrLen $3 "$0;" # Get the length of our dir ($3)
  928. StrLen $4 $2 # Get the length of the return from StrStr ($4)
  929. StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
  930. StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
  931. StrCpy $3 "$5$6" # Combine $5 and $6
  932. # Check for Trailing ';'
  933. StrCpy $5 $3 1 -1 # Load the last character of the string
  934. StrCmp $5 ";" 0 +2 # Check for ';'
  935. StrCpy $3 $3 -1 # remove trailing ';'
  936. # Write the new path to the registry
  937. WriteRegExpandStr ${Environ} "PATH" $3
  938. # Broadcast the change to all open applications
  939. SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
  940. done:
  941. Pop $6
  942. Pop $5
  943. Pop $4
  944. Pop $3
  945. Pop $2
  946. Pop $1
  947. Pop $0
  948. FunctionEnd
  949. #------------------------------------------------------------------------------
  950. # UninstallMSI Function
  951. # - Uninstalls MSI by product code
  952. #
  953. # Usage:
  954. # Push product code
  955. # Call UninstallMSI
  956. #
  957. # Source:
  958. # https://nsis.sourceforge.io/Uninstalling_a_previous_MSI_(Windows_installer_package)
  959. #------------------------------------------------------------------------------
  960. Function UninstallMSI
  961. ; $R0 === product code
  962. MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
  963. "${PRODUCT_NAME} is already installed via MSI.$\n$\n\
  964. Click `OK` to remove the existing installation." \
  965. /SD IDOK IDOK UninstallMSI
  966. Abort
  967. UninstallMSI:
  968. ExecWait '"msiexec.exe" /x $R0 /qb /quiet /norestart'
  969. FunctionEnd
  970. ###############################################################################
  971. # Specialty Functions
  972. ###############################################################################
  973. Function getExistingMinionConfig
  974. # Set Config Found Default Value
  975. StrCpy $ExistingConfigFound 0
  976. confFind:
  977. IfFileExists "$INSTDIR\conf\minion" confFound confNotFound
  978. confNotFound:
  979. ${If} $INSTDIR == "c:\salt\bin\Scripts"
  980. StrCpy $INSTDIR "C:\salt"
  981. goto confFind
  982. ${Else}
  983. goto confReallyNotFound
  984. ${EndIf}
  985. confFound:
  986. StrCpy $ExistingConfigFound 1
  987. FileOpen $0 "$INSTDIR\conf\minion" r
  988. confLoop:
  989. ClearErrors # clear Errors
  990. FileRead $0 $1 # read the next line
  991. IfErrors EndOfFile # error is probably EOF
  992. ${StrLoc} $2 $1 "master:" ">" # find `master:` starting at the beginning
  993. ${If} $2 == 0 # if it found it in the first position, then it is defined
  994. ${StrStrAdv} $2 $1 "master: " ">" ">" "0" "0" "0" # read everything after `master: `
  995. ${Trim} $2 $2 # trim white space
  996. ${If} $2 == "" # if it's empty, it's probably a list of masters
  997. masterLoop:
  998. ClearErrors # clear Errors
  999. FileRead $0 $1 # read the next line
  1000. IfErrors EndOfFile # error is probably EOF
  1001. ${StrStrAdv} $2 $1 "- " ">" ">" "0" "0" "0" # read everything after `- `
  1002. ${Trim} $2 $2 # trim white space
  1003. ${IfNot} $2 == "" # if the line is not empty, we found something
  1004. ${If} $ConfigMasterHost == "" # if the config setting is empty
  1005. StrCpy $ConfigMasterHost $2 # make the first item the new entry
  1006. ${Else}
  1007. StrCpy $ConfigMasterHost "$ConfigMasterHost,$2" # Append the new master, comma separated
  1008. ${EndIf}
  1009. Goto masterLoop # check the next one
  1010. ${EndIf}
  1011. ${Else}
  1012. StrCpy $ConfigMasterHost $2 # a single master entry
  1013. ${EndIf}
  1014. ${EndIf}
  1015. ${StrLoc} $2 $1 "id:" ">"
  1016. ${If} $2 == 0
  1017. ${StrStrAdv} $2 $1 "id: " ">" ">" "0" "0" "0"
  1018. ${Trim} $2 $2
  1019. StrCpy $ConfigMinionName $2
  1020. ${EndIf}
  1021. Goto confLoop
  1022. EndOfFile:
  1023. FileClose $0
  1024. confReallyNotFound:
  1025. # Set Default Config Values if not found
  1026. ${If} $ConfigMasterHost == ""
  1027. StrCpy $ConfigMasterHost "salt"
  1028. ${EndIf}
  1029. ${If} $ConfigMinionName == ""
  1030. StrCpy $ConfigMinionName "hostname"
  1031. ${EndIf}
  1032. FunctionEnd
  1033. Var cfg_line
  1034. Var chk_line
  1035. Var lst_check
  1036. Function updateMinionConfig
  1037. ClearErrors
  1038. FileOpen $0 "$INSTDIR\conf\minion" "r" # open target file for reading
  1039. GetTempFileName $R0 # get new temp file name
  1040. FileOpen $1 $R0 "w" # open temp file for writing
  1041. StrCpy $ConfigWriteMaster 1 # write the master config value
  1042. StrCpy $ConfigWriteMinion 1 # write the minion config value
  1043. loop: # loop through each line
  1044. FileRead $0 $cfg_line # read line from target file
  1045. IfErrors done # end if errors are encountered (end of line)
  1046. loop_after_read:
  1047. StrCpy $lst_check 0 # list check not performed
  1048. ${If} $MasterHost_State == "" # if master is empty
  1049. ${OrIf} $MasterHost_State == "salt" # or if master is 'salt'
  1050. StrCpy $ConfigWriteMaster 0 # no need to write master config
  1051. ${EndIf} # close if statement
  1052. ${If} $MinionName_State == "" # if minion is empty
  1053. ${OrIf} $MinionName_State == "hostname" # and if minion is not 'hostname'
  1054. StrCpy $ConfigWriteMinion 0 # no need to write minion config
  1055. ${EndIf} # close if statement
  1056. ${If} $ConfigWriteMaster == 1 # if we need to write master config
  1057. ${StrLoc} $3 $cfg_line "master:" ">" # where is 'master:' in this line
  1058. ${If} $3 == 0 # is it in the first...
  1059. ${OrIf} $3 == 1 # or second position (account for comments)
  1060. ${Explode} $9 "," $MasterHost_state # Split the hostname on commas, $9 is the number of items found
  1061. ${If} $9 == 1 # 1 means only a single master was passed
  1062. StrCpy $cfg_line "master: $MasterHost_State$\r$\n" # write the master
  1063. ${Else} # make a multi-master entry
  1064. StrCpy $cfg_line "master:" # make the first line "master:"
  1065. loop_explode: # start a loop to go through the list in the config
  1066. pop $8 # pop the next item off the stack
  1067. ${Trim} $8 $8 # trim any whitespace
  1068. StrCpy $cfg_line "$cfg_line$\r$\n - $8" # add it to the master variable ($2)
  1069. IntOp $9 $9 - 1 # decrement the list count
  1070. ${If} $9 >= 1 # if it's not 0
  1071. Goto loop_explode # do it again
  1072. ${EndIf} # close if statement
  1073. StrCpy $cfg_line "$cfg_line$\r$\n" # Make sure there's a new line at the end
  1074. # Remove remaining items in list
  1075. ${While} $lst_check == 0 # while list item found
  1076. FileRead $0 $chk_line # read line from target file
  1077. IfErrors done # end if errors are encountered (end of line)
  1078. ${StrLoc} $3 $chk_line " - " ">" # where is 'master:' in this line
  1079. ${If} $3 == "" # is it in the first...
  1080. StrCpy $lst_check 1 # list check performed and finished
  1081. ${EndIf}
  1082. ${EndWhile}
  1083. ${EndIf} # close if statement
  1084. StrCpy $ConfigWriteMaster 0 # master value written to config
  1085. ${EndIf} # close if statement
  1086. ${EndIf} # close if statement
  1087. ${If} $ConfigWriteMinion == 1 # if we need to write minion config
  1088. ${StrLoc} $3 $cfg_line "id:" ">" # where is 'id:' in this line
  1089. ${If} $3 == 0 # is it in the first...
  1090. ${OrIf} $3 == 1 # or the second position (account for comments)
  1091. StrCpy $cfg_line "id: $MinionName_State$\r$\n" # write the minion config setting
  1092. StrCpy $ConfigWriteMinion 0 # minion value written to config
  1093. ${EndIf} # close if statement
  1094. ${EndIf} # close if statement
  1095. FileWrite $1 $cfg_line # write changed or unchanged line to temp file
  1096. ${If} $lst_check == 1 # master not written to the config
  1097. StrCpy $cfg_line $chk_line
  1098. Goto loop_after_read # A loop was performed, skip the next read
  1099. ${EndIf} # close if statement
  1100. Goto loop # check the next line in the config file
  1101. done:
  1102. ClearErrors
  1103. # Does master config still need to be written
  1104. ${If} $ConfigWriteMaster == 1 # master not written to the config
  1105. ${Explode} $9 "," $MasterHost_state # split the hostname on commas, $9 is the number of items found
  1106. ${If} $9 == 1 # 1 means only a single master was passed
  1107. StrCpy $cfg_line "master: $MasterHost_State" # write the master
  1108. ${Else} # make a multi-master entry
  1109. StrCpy $cfg_line "master:" # make the first line "master:"
  1110. loop_explode_2: # start a loop to go through the list in the config
  1111. pop $8 # pop the next item off the stack
  1112. ${Trim} $8 $8 # trim any whitespace
  1113. StrCpy $cfg_line "$cfg_line$\r$\n - $8" # add it to the master variable ($2)
  1114. IntOp $9 $9 - 1 # decrement the list count
  1115. ${If} $9 >= 1 # if it's not 0
  1116. Goto loop_explode_2 # do it again
  1117. ${EndIf} # close if statement
  1118. ${EndIf} # close if statement
  1119. FileWrite $1 $cfg_line # write changed or unchanged line to temp file
  1120. ${EndIf} # close if statement
  1121. ${If} $ConfigWriteMinion == 1 # minion ID not written to the config
  1122. StrCpy $cfg_line "$\r$\nid: $MinionName_State" # write the minion config setting
  1123. FileWrite $1 $cfg_line # write changed or unchanged line to temp file
  1124. ${EndIf} # close if statement
  1125. FileClose $0 # close target file
  1126. FileClose $1 # close temp file
  1127. Delete "$INSTDIR\conf\minion" # delete target file
  1128. CopyFiles /SILENT $R0 "$INSTDIR\conf\minion" # copy temp file to target file
  1129. Delete $R0 # delete temp file
  1130. FunctionEnd
  1131. Function parseCommandLineSwitches
  1132. # Load the parameters
  1133. ${GetParameters} $R0
  1134. # Display Help
  1135. ClearErrors
  1136. ${GetOptions} $R0 "/?" $R1
  1137. IfErrors display_help_not_found
  1138. System::Call 'kernel32::GetStdHandle(i -11)i.r0'
  1139. System::Call 'kernel32::AttachConsole(i -1)i.r1'
  1140. ${If} $0 = 0
  1141. ${OrIf} $1 = 0
  1142. System::Call 'kernel32::AllocConsole()'
  1143. System::Call 'kernel32::GetStdHandle(i -11)i.r0'
  1144. ${EndIf}
  1145. FileWrite $0 "$\n"
  1146. FileWrite $0 "$\n"
  1147. FileWrite $0 "Help for Salt Minion installation$\n"
  1148. FileWrite $0 "===============================================================================$\n"
  1149. FileWrite $0 "$\n"
  1150. FileWrite $0 "/minion-name=$\t$\tA string value to set the minion name. Default value is$\n"
  1151. FileWrite $0 "$\t$\t$\t'hostname'. Setting the minion name causes the installer$\n"
  1152. FileWrite $0 "$\t$\t$\tto use the default config or a custom config if defined$\n"
  1153. FileWrite $0 "$\n"
  1154. FileWrite $0 "/master=$\t$\tA string value to set the IP address or hostname of the$\n"
  1155. FileWrite $0 "$\t$\t$\tmaster. Default value is 'salt'. You may pass a single$\n"
  1156. FileWrite $0 "$\t$\t$\tmaster or a comma-separated list of masters. Setting$\n"
  1157. FileWrite $0 "$\t$\t$\tthe master will cause the installer to use the default$\n"
  1158. FileWrite $0 "$\t$\t$\tconfig or a custom config if defined$\n"
  1159. FileWrite $0 "$\n"
  1160. FileWrite $0 "/start-minion=$\t$\t1 will start the minion service, 0 will not.$\n"
  1161. FileWrite $0 "$\t$\t$\tDefault is 1$\n"
  1162. FileWrite $0 "$\n"
  1163. FileWrite $0 "/start-minion-delayed$\tSet the minion start type to 'Automatic (Delayed Start)'$\n"
  1164. FileWrite $0 "$\n"
  1165. FileWrite $0 "/default-config$\t$\tOverwrite the existing config if present with the$\n"
  1166. FileWrite $0 "$\t$\t$\tdefault config for salt. Default is to use the existing$\n"
  1167. FileWrite $0 "$\t$\t$\tconfig if present. If /master and/or /minion-name is$\n"
  1168. FileWrite $0 "$\t$\t$\tpassed, those values will be used to update the new$\n"
  1169. FileWrite $0 "$\t$\t$\tdefault config$\n"
  1170. FileWrite $0 "$\n"
  1171. FileWrite $0 "$\t$\t$\tAny existing config will be backed up by appending$\n"
  1172. FileWrite $0 "$\t$\t$\ta timestamp and a .bak extension. That includes\n"
  1173. FileWrite $0 "$\t$\t$\tthe minion file and the minion.d directory$\n"
  1174. FileWrite $0 "$\n"
  1175. FileWrite $0 "/custom-config=$\t$\tA string value specifying the name of a custom config$\n"
  1176. FileWrite $0 "$\t$\t$\tfile in the same path as the installer or the full path$\n"
  1177. FileWrite $0 "$\t$\t$\tto a custom config file. If /master and/or /minion-name$\n"
  1178. FileWrite $0 "$\t$\t$\tis passed, those values will be used to update the new$\n"
  1179. FileWrite $0 "$\t$\t$\tcustom config$\n"
  1180. FileWrite $0 "$\n"
  1181. FileWrite $0 "$\t$\t$\tAny existing config will be backed up by appending$\n"
  1182. FileWrite $0 "$\t$\t$\ta timestamp and a .bak extension. That includes\n"
  1183. FileWrite $0 "$\t$\t$\tthe minion file and the minion.d directory$\n"
  1184. FileWrite $0 "$\n"
  1185. FileWrite $0 "/S$\t$\t$\tInstall Salt silently$\n"
  1186. FileWrite $0 "$\n"
  1187. FileWrite $0 "/?$\t$\t$\tDisplay this help screen$\n"
  1188. FileWrite $0 "$\n"
  1189. FileWrite $0 "-------------------------------------------------------------------------------$\n"
  1190. FileWrite $0 "$\n"
  1191. FileWrite $0 "Examples:$\n"
  1192. FileWrite $0 "$\n"
  1193. FileWrite $0 "${OutFile} /S$\n"
  1194. FileWrite $0 "$\n"
  1195. FileWrite $0 "${OutFile} /S /minion-name=myminion /master=master.mydomain.com /start-minion-delayed$\n"
  1196. FileWrite $0 "$\n"
  1197. FileWrite $0 "===============================================================================$\n"
  1198. FileWrite $0 "$\n"
  1199. System::Free $0
  1200. System::Free $1
  1201. System::Call 'kernel32::FreeConsole()'
  1202. # Give the user back the prompt
  1203. !define VK_RETURN 0x0D ; Enter Key
  1204. !define KEYEVENTF_EXTENDEDKEY 0x0001
  1205. !define KEYEVENTF_KEYUP 0x0002
  1206. System::Call "user32::keybd_event(i${VK_RETURN}, i0x45, i${KEYEVENTF_EXTENDEDKEY}|0, i0)"
  1207. System::Call "user32::keybd_event(i${VK_RETURN}, i0x45, i${KEYEVENTF_EXTENDEDKEY}|${KEYEVENTF_KEYUP}, i0)"
  1208. Abort
  1209. display_help_not_found:
  1210. # Set default value for Use Existing Config
  1211. StrCpy $ConfigType_State "Existing Config"
  1212. # Check for start-minion switches
  1213. # /start-service is to be deprecated, so we must check for both
  1214. ${GetOptions} $R0 "/start-service=" $R1
  1215. ${GetOptions} $R0 "/start-minion=" $R2
  1216. # Service: Start Salt Minion
  1217. ${IfNot} $R2 == ""
  1218. # If start-minion was passed something, then set it
  1219. StrCpy $StartMinion $R2
  1220. ${ElseIfNot} $R1 == ""
  1221. # If start-service was passed something, then set StartMinion to that
  1222. StrCpy $StartMinion $R1
  1223. ${Else}
  1224. # Otherwise default to 1
  1225. StrCpy $StartMinion 1
  1226. ${EndIf}
  1227. # Service: Minion Startup Type Delayed
  1228. ClearErrors
  1229. ${GetOptions} $R0 "/start-minion-delayed" $R1
  1230. IfErrors start_minion_delayed_not_found
  1231. StrCpy $StartMinionDelayed 1
  1232. start_minion_delayed_not_found:
  1233. # Minion Config: Master IP/Name
  1234. # If setting master, we don't want to use existing config
  1235. ${GetOptions} $R0 "/master=" $R1
  1236. ${IfNot} $R1 == ""
  1237. StrCpy $MasterHost_State $R1
  1238. StrCpy $ConfigType_State "Default Config"
  1239. ${ElseIf} $MasterHost_State == ""
  1240. StrCpy $MasterHost_State "salt"
  1241. ${EndIf}
  1242. # Minion Config: Minion ID
  1243. # If setting minion id, we don't want to use existing config
  1244. ${GetOptions} $R0 "/minion-name=" $R1
  1245. ${IfNot} $R1 == ""
  1246. StrCpy $MinionName_State $R1
  1247. StrCpy $ConfigType_State "Default Config"
  1248. ${ElseIf} $MinionName_State == ""
  1249. StrCpy $MinionName_State "hostname"
  1250. ${EndIf}
  1251. # Use Default Config
  1252. ${GetOptions} $R0 "/default-config" $R1
  1253. IfErrors default_config_not_found
  1254. StrCpy $ConfigType_State "Default Config"
  1255. default_config_not_found:
  1256. # Use Custom Config
  1257. # Set default value for Use Custom Config
  1258. StrCpy $CustomConfig_State ""
  1259. # Existing config will get a `.bak` extension
  1260. ${GetOptions} $R0 "/custom-config=" $R1
  1261. ${IfNot} $R1 == ""
  1262. # Custom Config was passed something, set it
  1263. StrCpy $CustomConfig_State $R1
  1264. StrCpy $ConfigType_State "Custom Config"
  1265. ${EndIf}
  1266. FunctionEnd