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}-Py${PYTHON_VERSION}-${CPUARCH}-Setup.exe" 15!define /date TIME_STAMP "%Y-%m-%d-%H-%M-%S" 16 17# Request admin rights 18RequestExecutionLevel admin 19 20# Import Libraries 21!include "FileFunc.nsh" 22!include "LogicLib.nsh" 23!include "MoveFileFolder.nsh" 24!include "MUI2.nsh" 25!include "nsDialogs.nsh" 26!include "StrFunc.nsh" 27!include "WinMessages.nsh" 28!include "WinVer.nsh" 29!include "x64.nsh" 30${StrLoc} 31${StrStrAdv} 32 33# Required by MoveFileFolder.nsh 34!insertmacro Locate 35 36!ifdef SaltVersion 37 !define PRODUCT_VERSION "${SaltVersion}" 38!else 39 !define PRODUCT_VERSION "Undefined Version" 40!endif 41 42!ifdef PythonVersion 43 !define PYTHON_VERSION "${PythonVersion}" 44!else 45 !define PYTHON_VERSION "3" 46!endif 47 48!if "$%PROCESSOR_ARCHITECTURE%" == "AMD64" 49 !define CPUARCH "AMD64" 50!else if "$%PROCESSOR_ARCHITEW6432%" == "AMD64" 51 !define CPUARCH "AMD64" 52!else 53 !define CPUARCH "x86" 54!endif 55 56# Part of the Trim function for Strings 57!define Trim "!insertmacro Trim" 58!macro Trim ResultVar String 59 Push "${String}" 60 Call Trim 61 Pop "${ResultVar}" 62!macroend 63 64# Part of the Explode function for Strings 65!define Explode "!insertmacro Explode" 66!macro Explode Length Separator String 67 Push "${Separator}" 68 Push "${String}" 69 Call Explode 70 Pop "${Length}" 71!macroend 72 73# Part of the StrContains function for Strings 74!define StrContains "!insertmacro StrContains" 75!macro StrContains OUT NEEDLE HAYSTACK 76 Push "${HAYSTACK}" 77 Push "${NEEDLE}" 78 Call StrContains 79 Pop "${OUT}" 80!macroend 81 82 83############################################################################### 84# Configure Pages, Ordering, and Configuration 85############################################################################### 86!define MUI_ABORTWARNING 87!define MUI_ICON "salt.ico" 88!define MUI_UNICON "salt.ico" 89!define MUI_WELCOMEFINISHPAGE_BITMAP "panel.bmp" 90!define MUI_UNWELCOMEFINISHPAGE_BITMAP "panel.bmp" 91 92 93# Welcome page 94!insertmacro MUI_PAGE_WELCOME 95 96# License page 97!insertmacro MUI_PAGE_LICENSE "LICENSE.txt" 98 99# Install location page 100!define MUI_PAGE_CUSTOMFUNCTION_SHOW pageCheckExistingInstall 101!insertmacro MUI_PAGE_DIRECTORY 102 103# Configure Minion page 104Page custom pageMinionConfig pageMinionConfig_Leave 105 106# Instfiles page 107!insertmacro MUI_PAGE_INSTFILES 108 109# Finish page (Customized) 110!define MUI_PAGE_CUSTOMFUNCTION_SHOW pageFinish_Show 111!define MUI_PAGE_CUSTOMFUNCTION_LEAVE pageFinish_Leave 112!insertmacro MUI_PAGE_FINISH 113 114# Uninstaller pages 115!insertmacro MUI_UNPAGE_INSTFILES 116 117# Language files 118!insertmacro MUI_LANGUAGE "English" 119 120 121############################################################################### 122# Custom Dialog Box Variables 123############################################################################### 124Var Dialog 125Var Label 126Var MinionStart_ChkBox 127Var MinionStartDelayed_ChkBox 128Var MasterHost_Cfg 129Var MasterHost_TxtBox 130Var MasterHost 131Var MinionName_Cfg 132Var MinionName_TxtBox 133Var MinionName 134Var ExistingConfigFound 135Var ConfigType_DropList 136Var ConfigType 137Var CustomConfig_TxtBox 138Var CustomConfig_Btn 139Var CustomConfig 140Var CustomConfigWarning_Lbl 141Var ExistingConfigWarning_Lbl 142Var DefaultConfigWarning_Lbl 143Var MoveExistingConfig_ChkBox 144Var MoveExistingConfig 145Var StartMinion 146Var StartMinionDelayed 147Var DeleteInstallDir 148Var DeleteRootDir 149Var ConfigWriteMinion 150Var ConfigWriteMaster 151# For new method installation 152Var RegInstDir 153Var RegRootDir 154Var RootDir 155Var SysDrive 156Var ExistingInstallation 157Var CustomLocation 158 159 160############################################################################### 161# Directory Picker Dialog Box 162############################################################################### 163Function pageCheckExistingInstall 164 # If this is an Existing Installation we want to disable the directory 165 # picker functionality 166 # https://nsis-dev.github.io/NSIS-Forums/html/t-166727.html 167 # Use the winspy tool (https://sourceforge.net/projects/winspyex/) to get 168 # the Control ID for the items you want to disable 169 # The Control ID is in the Details tab 170 # It is a Hex value that needs to be converted to an integer 171 ${If} $ExistingInstallation == 1 172 # 32770 is Class name used by all NSIS dialog boxes 173 FindWindow $R0 "#32770" "" $HWNDPARENT 174 # 1019 is the Destination Folder text field (0x3FB) 175 GetDlgItem $R1 $R0 1019 176 EnableWindow $R1 0 177 # 1001 is the Browse button (0x3E9) 178 GetDlgItem $R1 $R0 1001 179 EnableWindow $R1 0 180 # Disabling the Location Picker causes the buttons to behave incorrectly 181 # Esc and Enter don't work. Nor can you use Alt+N and Alt+B. Setting 182 # the focus to the Next button seems to fix this 183 # Set focus on Next button (0x1) 184 GetDlgItem $R1 $HWNDPARENT 1 185 SendMessage $HWNDPARENT ${WM_NEXTDLGCTL} $R1 1 186 ${EndIf} 187FunctionEnd 188 189 190############################################################################### 191# Minion Settings Dialog Box 192############################################################################### 193Function pageMinionConfig 194 195 # Set Page Title and Description 196 !insertmacro MUI_HEADER_TEXT "Minion Settings" "Set the Minion Master and ID" 197 nsDialogs::Create 1018 198 Pop $Dialog 199 200 ${If} $Dialog == error 201 Abort 202 ${EndIf} 203 204 # Master IP or Hostname Dialog Control 205 ${NSD_CreateLabel} 0 0 100% 9u "&Master IP or Hostname:" 206 Pop $Label 207 208 ${NSD_CreateText} 0 10u 100% 12u $MasterHost 209 Pop $MasterHost_TxtBox 210 211 # Minion ID Dialog Control 212 ${NSD_CreateLabel} 0 30u 100% 9u "Minion &Name:" 213 Pop $Label 214 215 ${NSD_CreateText} 0 40u 100% 12u $MinionName 216 Pop $MinionName_TxtBox 217 218 # Config Drop List 219 ${NSD_CreateDropList} 0 60u 25% 36u "" 220 Pop $ConfigType_DropList 221 ${NSD_CB_AddString} $ConfigType_DropList "Default Config" 222 ${NSD_CB_AddString} $ConfigType_DropList "Custom Config" 223 ${NSD_OnChange} $ConfigType_DropList pageMinionConfig_OnChange 224 225 # Add Existing Config Warning Label 226 ${NSD_CreateLabel} 0 75u 100% 50u "The values above are taken from an \ 227 existing configuration found in `$RootDir\conf\minion`.$\n\ 228 $\n\ 229 Clicking `Install` will leave the existing config unchanged." 230 Pop $ExistingConfigWarning_Lbl 231 CreateFont $0 "Arial" 10 500 /ITALIC 232 SendMessage $ExistingConfigWarning_Lbl ${WM_SETFONT} $0 1 233 SetCtlColors $ExistingConfigWarning_Lbl 0xBB0000 transparent 234 235 # Add Checkbox to move root_dir 236 ${NSD_CreateCheckBox} 0 125u 100% 10u \ 237 " Move &existing root directory (C:\salt) to %ProgramData%\Salt." 238 Pop $MoveExistingConfig_ChkBox 239 CreateFont $0 "Arial" 10 500 240 SendMessage $MoveExistingConfig_ChkBox ${WM_SETFONT} $0 1 241 ${If} $MoveExistingConfig == 1 242 ${NSD_Check} $MoveExistingConfig_ChkBox 243 ${EndIf} 244 245 # Add Default Config Warning Label 246 ${NSD_CreateLabel} 0 75u 100% 60u "Clicking `Install` will backup the \ 247 the existing minion config file and minion.d directories. The values \ 248 above will be used in the new default config.$\n\ 249 $\n\ 250 NOTE: If Master IP is set to `salt` and Minion Name is set to \ 251 `hostname` no changes will be made." 252 Pop $DefaultConfigWarning_Lbl 253 CreateFont $0 "Arial" 10 500 /ITALIC 254 SendMessage $DefaultConfigWarning_Lbl ${WM_SETFONT} $0 1 255 SetCtlColors $DefaultConfigWarning_Lbl 0xBB0000 transparent 256 257 # Add Custom Config File Selector and Warning Label 258 ${NSD_CreateText} 26% 60u 64% 12u $CustomConfig 259 Pop $CustomConfig_TxtBox 260 ${NSD_CreateButton} 91% 60u 9% 12u "..." 261 Pop $CustomConfig_Btn 262 ${NSD_OnClick} $CustomConfig_Btn pageCustomConfigBtn_OnClick 263 264 ${If} $ExistingConfigFound == 0 265 ${NSD_CreateLabel} 0 75u 100% 60u "Values entered above will be used \ 266 in the custom config.$\n\ 267 $\n\ 268 NOTE: If Master IP is set to `salt` and Minion Name is set to \ 269 `hostname` no changes will be made." 270 ${Else} 271 ${NSD_CreateLabel} 0 75u 100% 60u "Clicking `Install` will backup the \ 272 the existing minion config file and minion.d directories. The \ 273 values above will be used in the custom config.$\n\ 274 $\n\ 275 NOTE: If Master IP is set to `salt` and Minion Name is set to \ 276 `hostname` no changes will be made." 277 ${Endif} 278 Pop $CustomConfigWarning_Lbl 279 CreateFont $0 "Arial" 10 500 /ITALIC 280 SendMessage $CustomConfigWarning_Lbl ${WM_SETFONT} $0 1 281 SetCtlColors $CustomConfigWarning_Lbl 0xBB0000 transparent 282 283 # If existing config found, add the Existing Config option to the Drop List 284 # If not, hide the Default Warning 285 ${If} $ExistingConfigFound == 1 286 ${NSD_CB_AddString} $ConfigType_DropList "Existing Config" 287 ${Else} 288 ShowWindow $DefaultConfigWarning_Lbl ${SW_HIDE} 289 ${Endif} 290 291 ${NSD_CB_SelectString} $ConfigType_DropList $ConfigType 292 ${NSD_SetText} $CustomConfig_TxtBox $CustomConfig 293 294 Call pageMinionConfig_OnChange 295 296 nsDialogs::Show 297 298FunctionEnd 299 300 301Function pageMinionConfig_OnChange 302 303 # You have to pop the top handle to keep the stack clean 304 Pop $R0 305 306 # Assign the current checkbox state to the variable 307 ${NSD_GetText} $ConfigType_DropList $ConfigType 308 309 # Update Dialog 310 ${Switch} $ConfigType 311 ${Case} "Existing Config" 312 # Enable Master/Minion and set values 313 EnableWindow $MasterHost_TxtBox 0 314 EnableWindow $MinionName_TxtBox 0 315 ${NSD_SetText} $MasterHost_TxtBox $MasterHost_Cfg 316 ${NSD_SetText} $MinionName_TxtBox $MinionName_Cfg 317 # Hide Custom File Picker 318 ShowWindow $CustomConfig_TxtBox ${SW_HIDE} 319 ShowWindow $CustomConfig_Btn ${SW_HIDE} 320 # Hide Warnings 321 ShowWindow $DefaultConfigWarning_Lbl ${SW_HIDE} 322 ShowWindow $CustomConfigWarning_Lbl ${SW_HIDE} 323 # Show Existing Warning 324 ShowWindow $ExistingConfigWarning_Lbl ${SW_SHOW} 325 ${If} $RootDir == "C:\salt" 326 ShowWindow $MoveExistingConfig_ChkBox ${SW_SHOW} 327 ${Else} 328 ShowWindow $MoveExistingConfig_ChkBox ${SW_HIDE} 329 ${EndIf} 330 ${Break} 331 ${Case} "Custom Config" 332 # Enable Master/Minion and set values 333 EnableWindow $MasterHost_TxtBox 1 334 EnableWindow $MinionName_TxtBox 1 335 ${NSD_SetText} $MasterHost_TxtBox $MasterHost 336 ${NSD_SetText} $MinionName_TxtBox $MinionName 337 # Show Custom File Picker 338 ShowWindow $CustomConfig_TxtBox ${SW_SHOW} 339 ShowWindow $CustomConfig_Btn ${SW_SHOW} 340 # Hide Warnings 341 ShowWindow $DefaultConfigWarning_Lbl ${SW_HIDE} 342 ShowWindow $ExistingConfigWarning_Lbl ${SW_HIDE} 343 ShowWindow $MoveExistingConfig_ChkBox ${SW_HIDE} 344 # Show Custom Warning 345 ShowWindow $CustomConfigWarning_Lbl ${SW_SHOW} 346 ${Break} 347 ${Case} "Default Config" 348 # Enable Master/Minion and set values 349 EnableWindow $MasterHost_TxtBox 1 350 EnableWindow $MinionName_TxtBox 1 351 ${NSD_SetText} $MasterHost_TxtBox $MasterHost 352 ${NSD_SetText} $MinionName_TxtBox $MinionName 353 # Hide Custom File Picker 354 ShowWindow $CustomConfig_TxtBox ${SW_HIDE} 355 ShowWindow $CustomConfig_Btn ${SW_HIDE} 356 # Hide Warnings 357 ShowWindow $ExistingConfigWarning_Lbl ${SW_HIDE} 358 ShowWindow $MoveExistingConfig_ChkBox ${SW_HIDE} 359 ShowWindow $CustomConfigWarning_Lbl ${SW_HIDE} 360 # Show Default Warning, if there is an existing config 361 ${If} $ExistingConfigFound == 1 362 ShowWindow $DefaultConfigWarning_Lbl ${SW_SHOW} 363 ${Endif} 364 ${Break} 365 ${EndSwitch} 366 367FunctionEnd 368 369# File Picker Definitions 370!define OFN_FILEMUSTEXIST 0x00001000 371!define OFN_DONTADDTOREC 0x02000000 372!define OPENFILENAME_SIZE_VERSION_400 76 373!define OPENFILENAME 'i,i,i,i,i,i,i,i,i,i,i,i,i,i,&i2,&i2,i,i,i,i' 374Function pageCustomConfigBtn_OnClick 375 376 Pop $0 377 System::Call '*(&t${NSIS_MAX_STRLEN})i.s' # Allocate OPENFILENAME.lpstrFile buffer 378 System::Call '*(${OPENFILENAME})i.r0' # Allocate OPENFILENAME struct 379 System::Call '*$0(${OPENFILENAME})(${OPENFILENAME_SIZE_VERSION_400}, \ 380 $hwndparent, , , , , , sr1, ${NSIS_MAX_STRLEN} , , , , \ 381 t"Select Custom Config File", \ 382 ${OFN_FILEMUSTEXIST} | ${OFN_DONTADDTOREC})' 383 384 # Populate file name field 385 ${NSD_GetText} $CustomConfig_TxtBox $2 386 System::Call "*$1(&t${NSIS_MAX_STRLEN}r2)" ; Set lpstrFile to the old path (if any) 387 388 # Open the dialog 389 System::Call 'COMDLG32::GetOpenFileName(ir0)i.r2' 390 391 # Get file name field 392 ${If} $2 <> 0 393 System::Call "*$1(&t${NSIS_MAX_STRLEN}.r2)" 394 ${NSD_SetText} $CustomConfig_TxtBox $2 395 ${EndIf} 396 397 # Free resources 398 System::Free $1 399 System::Free $0 400 401FunctionEnd 402 403 404Function pageMinionConfig_Leave 405 406 # Save the State 407 ${NSD_GetText} $MasterHost_TxtBox $MasterHost 408 ${NSD_GetText} $MinionName_TxtBox $MinionName 409 ${NSD_GetText} $ConfigType_DropList $ConfigType 410 ${NSD_GetText} $CustomConfig_TxtBox $CustomConfig 411 ${NSD_GetState} $MoveExistingConfig_ChkBox $MoveExistingConfig 412 413 # Abort if config file not found 414 ${If} $ConfigType == "Custom Config" 415 IfFileExists "$CustomConfig" continue 0 416 MessageBox MB_OK|MB_ICONEXCLAMATION "File not found: $CustomConfig" /SD IDOK 417 Abort 418 ${EndIf} 419 420 ${If} $MoveExistingConfig == 1 421 422 # This makes the $APPDATA variable point to the ProgramData folder instead 423 # of the current user's roaming AppData folder 424 SetShellVarContext all 425 426 # Get directory status 427 ${DirState} "$APPDATA\Salt Project\Salt" $R0 # 0=Empty, 1=full, -1=Not Found 428 StrCmp $R0 "1" 0 move_files # Move files if directory empty or missing 429 MessageBox MB_OKCANCEL \ 430 "The $APPDATA\Salt Project\Salt directory is not empty.$\n\ 431 These files will need to be moved manually." \ 432 /SD IDOK IDCANCEL cancel 433 StrCpy $MoveExistingConfig 0 434 Goto continue 435 436 cancel: 437 ${NSD_UNCHECK} $MoveExistingConfig_ChkBox 438 Abort 439 440 move_files: 441 # Make sure the target directory exists 442 nsExec::Exec "md $APPDATA\Salt Project\Salt" 443 # Take ownership of the C:\salt directory 444 nsExec::Exec "takeown /F $RootDir /R" 445 # Move the C:\salt directory to the new location 446 StrCpy $switch_overwrite 0 447 !insertmacro MoveFolder "$RootDir" "$APPDATA\Salt Project\Salt" "*.*" 448 # Make RootDir the new location 449 StrCpy $RootDir "$APPDATA\Salt Project\Salt" 450 451 ${EndIf} 452 453 continue: 454 Call BackupExistingConfig 455 456FunctionEnd 457 458 459############################################################################### 460# Custom Finish Page 461############################################################################### 462Function pageFinish_Show 463 464 # Imports so the checkboxes will show up 465 !define SWP_NOSIZE 0x0001 466 !define SWP_NOMOVE 0x0002 467 !define HWND_TOP 0x0000 468 469 # Create Start Minion Checkbox 470 ${NSD_CreateCheckbox} 120u 90u 100% 12u "&Start salt-minion" 471 Pop $MinionStart_ChkBox 472 SetCtlColors $MinionStart_ChkBox "" "ffffff" 473 # This command required to bring the checkbox to the front 474 System::Call "User32::SetWindowPos(i, i, i, i, i, i, i) b ($MinionStart_ChkBox, ${HWND_TOP}, 0, 0, 0, 0, ${SWP_NOSIZE}|${SWP_NOMOVE})" 475 476 # Create Start Minion Delayed ComboBox 477 ${NSD_CreateCheckbox} 130u 102u 100% 12u "&Delayed Start" 478 Pop $MinionStartDelayed_ChkBox 479 SetCtlColors $MinionStartDelayed_ChkBox "" "ffffff" 480 # This command required to bring the checkbox to the front 481 System::Call "User32::SetWindowPos(i, i, i, i, i, i, i) b ($MinionStartDelayed_ChkBox, ${HWND_TOP}, 0, 0, 0, 0, ${SWP_NOSIZE}|${SWP_NOMOVE})" 482 483 # Load current settings for Minion 484 ${If} $StartMinion == 1 485 ${NSD_Check} $MinionStart_ChkBox 486 ${EndIf} 487 488 # Load current settings for Minion Delayed 489 ${If} $StartMinionDelayed == 1 490 ${NSD_Check} $MinionStartDelayed_ChkBox 491 ${EndIf} 492 493FunctionEnd 494 495 496Function pageFinish_Leave 497 498 # Assign the current checkbox states 499 ${NSD_GetState} $MinionStart_ChkBox $StartMinion 500 ${NSD_GetState} $MinionStartDelayed_ChkBox $StartMinionDelayed 501 502FunctionEnd 503 504 505############################################################################### 506# Installation Settings 507############################################################################### 508Name "${PRODUCT_NAME} ${PRODUCT_VERSION} (Python ${PYTHON_VERSION})" 509OutFile "${OutFile}" 510InstallDir "C:\Program Files\Salt Project\Salt" 511InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" "" 512ShowInstDetails show 513ShowUnInstDetails show 514 515 516Section -copy_prereqs 517 # Copy prereqs to the Plugins Directory 518 # These files are downloaded by build_pkg.bat 519 # This directory gets removed upon completion 520 SetOutPath "$PLUGINSDIR\" 521 File /r "..\prereqs\" 522SectionEnd 523 524# Check if the Windows 10 Universal C Runtime (KB2999226) is installed 525# Python 3 needs the updated ucrt on Windows 8.1 / 2012R2 and lower 526# They are installed via KB2999226, but we're not going to patch the system here 527# Instead, we're going to copy the .dll files to the \salt\bin directory 528Section -install_ucrt 529 530 Var /GLOBAL UcrtFileName 531 532 # Get the Major.Minor version Number 533 # Windows 10 introduced CurrentMajorVersionNumber 534 ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" \ 535 CurrentMajorVersionNumber 536 537 # Windows 10/2016 will return a value here, skip to the end if returned 538 StrCmp $R0 '' lbl_needs_ucrt 0 539 540 # Found Windows 10 541 detailPrint "KB2999226 does not apply to this machine" 542 goto lbl_done 543 544 lbl_needs_ucrt: 545 # UCRT only needed on Windows Server 2012R2/Windows 8.1 and below 546 # The first ReadRegStr command above should have skipped to lbl_done if on 547 # Windows 10 box 548 549 # Is the update already installed 550 ClearErrors 551 552 # Use WMI to check if it's installed 553 detailPrint "Checking for existing UCRT (KB2999226) installation" 554 nsExec::ExecToStack 'cmd /q /c wmic qfe get hotfixid | findstr "^KB2999226"' 555 # Clean up the stack 556 Pop $R0 # Gets the ErrorCode 557 Pop $R1 # Gets the stdout, which should be KB2999226 if it's installed 558 559 # If it returned KB2999226 it's already installed 560 StrCmp $R1 'KB2999226' lbl_done 561 562 detailPrint "UCRT (KB2999226) not found" 563 564 # Use RunningX64 here to get the Architecture for the system running the installer 565 # CPUARCH is defined when the installer is built and is based on the machine that 566 # built the installer, not the target system as we need here. 567 ${If} ${RunningX64} 568 StrCpy $UcrtFileName "ucrt_x64.zip" 569 ${Else} 570 StrCpy $UcrtFileName "ucrt_x86.zip" 571 ${EndIf} 572 573 ClearErrors 574 575 detailPrint "Unzipping UCRT dll files to $INSTDIR\bin" 576 CreateDirectory $INSTDIR\bin 577 nsisunz::UnzipToLog "$PLUGINSDIR\$UcrtFileName" "$INSTDIR\bin" 578 579 # Clean up the stack 580 Pop $R0 # Get Error 581 582 ${IfNot} $R0 == "success" 583 detailPrint "error: $R0" 584 Sleep 3000 585 ${Else} 586 detailPrint "UCRT dll files copied successfully" 587 ${EndIf} 588 589 lbl_done: 590 591SectionEnd 592 593 594# Check and install Visual C++ redist 2013 packages 595# Hidden section (-) to install VCRedist 596Section -install_vcredist_2013 597 598 Var /GLOBAL VcRedistName 599 Var /GLOBAL VcRedistGuid 600 Var /GLOBAL NeedVcRedist 601 602 # GUIDs can be found by installing them and then running the following command: 603 # wmic product where "Name like '%2013%minimum runtime%'" get Name, Version, IdentifyingNumber 604 !define VCREDIST_X86_NAME "vcredist_x86_2013" 605 !define VCREDIST_X86_GUID "{8122DAB1-ED4D-3676-BB0A-CA368196543E}" 606 !define VCREDIST_X64_NAME "vcredist_x64_2013" 607 !define VCREDIST_X64_GUID "{53CF6934-A98D-3D84-9146-FC4EDF3D5641}" 608 609 # Only install 64bit VCRedist on 64bit machines 610 ${If} ${CPUARCH} == "AMD64" 611 StrCpy $VcRedistName ${VCREDIST_X64_NAME} 612 StrCpy $VcRedistGuid ${VCREDIST_X64_GUID} 613 Call InstallVCRedist 614 ${Else} 615 # Install 32bit VCRedist on all machines 616 StrCpy $VcRedistName ${VCREDIST_X86_NAME} 617 StrCpy $VcRedistGuid ${VCREDIST_X86_GUID} 618 Call InstallVCRedist 619 ${EndIf} 620 621SectionEnd 622 623 624Function InstallVCRedist 625 # Check to see if it's already installed 626 Call MsiQueryProductState 627 ${If} $NeedVcRedist == "True" 628 detailPrint "System requires $VcRedistName" 629 MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 \ 630 "$VcRedistName is currently not installed. Would you like to install?" \ 631 /SD IDYES IDNO endVCRedist 632 633 # If an output variable is specified ($0 in the case below), 634 # ExecWait sets the variable with the exit code (and only sets the 635 # error flag if an error occurs; if an error occurs, the contents 636 # of the user variable are undefined). 637 # http://nsis.sourceforge.net/Reference/ExecWait 638 ClearErrors 639 detailPrint "Installing $VcRedistName..." 640 ExecWait '"$PLUGINSDIR\$VcRedistName.exe" /install /quiet /norestart' $0 641 IfErrors 0 CheckVcRedistErrorCode 642 MessageBox MB_OK|MB_ICONEXCLAMATION \ 643 "$VcRedistName failed to install. Try installing the package manually." \ 644 /SD IDOK 645 detailPrint "An error occurred during installation of $VcRedistName" 646 647 CheckVcRedistErrorCode: 648 # Check for Reboot Error Code (3010) 649 ${If} $0 == 3010 650 MessageBox MB_OK|MB_ICONINFORMATION \ 651 "$VcRedistName installed but requires a restart to complete." \ 652 /SD IDOK 653 detailPrint "Reboot and run Salt install again" 654 655 # Check for any other errors 656 ${ElseIfNot} $0 == 0 657 MessageBox MB_OK|MB_ICONEXCLAMATION \ 658 "$VcRedistName failed with ErrorCode: $0. Try installing the package manually." \ 659 /SD IDOK 660 detailPrint "An error occurred during installation of $VcRedistName" 661 detailPrint "Error: $0" 662 ${EndIf} 663 664 endVCRedist: 665 666 ${EndIf} 667 668FunctionEnd 669 670 671Section "MainSection" SEC01 672 673 SetOutPath "$INSTDIR\" 674 SetOverwrite off 675 CreateDirectory "$RootDir\conf\pki\minion" 676 CreateDirectory "$RootDir\conf\minion.d" 677 CreateDirectory "$RootDir\var\cache\salt\minion\extmods\grains" 678 CreateDirectory "$RootDir\var\cache\salt\minion\proc" 679 CreateDirectory "$RootDir\var\log\salt\minion" 680 CreateDirectory "$RootDir\var\run" 681 File /r "..\buildenv\" 682 nsExec::Exec 'icacls $RootDir /inheritance:r /grant:r "*S-1-5-32-544":(OI)(CI)F /grant:r "*S-1-5-18":(OI)(CI)F' 683 684SectionEnd 685 686 687Function .onInit 688 689 InitPluginsDir 690 Call parseInstallerCommandLineSwitches 691 692 # Uninstall msi-installed salt 693 # Source: https://nsis-dev.github.io/NSIS-Forums/html/t-303468.html 694 !define upgradecode {FC6FB3A2-65DE-41A9-AD91-D10A402BD641} ;Salt upgrade code 695 StrCpy $0 0 696 loop: 697 System::Call 'MSI::MsiEnumRelatedProducts(t "${upgradecode}",i0,i r0,t.r1)i.r2' 698 ${If} $2 = 0 699 # Now $1 contains the product code 700 DetailPrint product:$1 701 push $R0 702 StrCpy $R0 $1 703 Call UninstallMSI 704 pop $R0 705 IntOp $0 $0 + 1 706 goto loop 707 ${Endif} 708 709 # If custom config passed, verify its existence before continuing so we 710 # don't uninstall an existing installation and then fail 711 ${If} $ConfigType == "Custom Config" 712 IfFileExists "$CustomConfig" customConfigExists 0 713 Abort 714 ${EndIf} 715 716 customConfigExists: 717 # Check for existing installation 718 ReadRegStr $R0 HKLM \ 719 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" \ 720 "UninstallString" 721 StrCmp $R0 "" checkOther # If it's empty, not installed 722 723 # Set InstDir to the parent directory so that we can uninstall it 724 ${GetParent} $R0 $INSTDIR 725 726 # Found existing installation, prompt to uninstall 727 MessageBox MB_OKCANCEL|MB_USERICON \ 728 "${PRODUCT_NAME} is already installed.$\n$\n\ 729 Click `OK` to remove the existing installation." \ 730 /SD IDOK IDOK uninst 731 Abort 732 733 checkOther: 734 # Check for existing installation of full salt 735 ReadRegStr $R0 HKLM \ 736 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME_OTHER}" \ 737 "UninstallString" 738 StrCmp $R0 "" skipUninstall # If it's empty, not installed 739 740 # Set InstDir to the parent directory so that we can uninstall it 741 ${GetParent} $R0 $INSTDIR 742 743 # Found existing installation, prompt to uninstall 744 MessageBox MB_OKCANCEL|MB_USERICON \ 745 "${PRODUCT_NAME_OTHER} is already installed.$\n$\n\ 746 Click `OK` to remove the existing installation." \ 747 /SD IDOK IDOK uninst 748 Abort 749 750 uninst: 751 752 # Get current Silent status 753 StrCpy $R0 0 754 ${If} ${Silent} 755 StrCpy $R0 1 756 ${EndIf} 757 758 # Turn on Silent mode 759 SetSilent silent 760 761 # Don't remove all directories when upgrading (old method) 762 StrCpy $DeleteInstallDir 0 763 764 # Don't remove RootDir when upgrading (new method) 765 StrCpy $DeleteRootDir 0 766 767 # Uninstall silently 768 Call uninstallSalt 769 770 # Set it back to Normal mode, if that's what it was before 771 ${If} $R0 == 0 772 SetSilent normal 773 ${EndIf} 774 775 skipUninstall: 776 777 Call getExistingInstallation 778 779 Call getExistingMinionConfig 780 781 ${If} $ExistingConfigFound == 0 782 ${AndIf} $ConfigType == "Existing Config" 783 StrCpy $ConfigType "Default Config" 784 ${EndIf} 785 786 IfSilent 0 +2 787 ${If} $ConfigType == "Existing Config" 788 ${AndIf} $MoveExistingConfig == 0 789 Call BackupExistingConfig 790 ${EndIf} 791 792FunctionEnd 793 794Function getExistingInstallation 795 # Try to detect an existing installation. There are three possible scenarios 796 # 1. Existing New Method Installation 797 # 2. Existing Old Method Installation 798 # 3. New Installation 799 # The results of this function will determine if the user is allowed to set 800 # the install location in the GUI. If there is an existing installation 801 # present, the location picker will be grayed out 802 # This function also sets the RootDir and INSTDIR variables used by the 803 # installer. 804 805 # Reset ExistingInstallation 806 StrCpy $ExistingInstallation 0 807 808 # Get ProgramFiles 809 # Use RunningX64 here to get the Architecture for the system running the 810 # installer. CPUARCH is defined when the installer is built and is based on 811 # the machine that built the installer, not the target system 812 # There are 3 scenarios here: 813 ${If} ${RunningX64} 814 ${If} ${CPUARCH} == "AMD64" 815 # 64 bit Salt on 64 bit system (C:\Program Files) 816 StrCpy $INSTDIR "$ProgramFiles64\Salt Project\Salt" 817 ${Else} 818 # 32 bit Salt on 64 bit system (C:\Program Files (x86)) 819 StrCpy $INSTDIR "$ProgramFiles32\Salt Project\Salt" 820 ${EndIf} 821 ${Else} 822 # 32 bit Salt on 32 bit system (C:\Program Files) 823 StrCpy $INSTDIR "$ProgramFiles\Salt Project\Salt" 824 ${EndIf} 825 826 # This makes the $APPDATA variable point to the ProgramData folder instead 827 # of the current user's roaming AppData folder 828 SetShellVarContext all 829 830 # Set default location of for salt config 831 StrCpy $RootDir "$APPDATA\Salt Project\Salt" 832 833 # The NSIS installer is a 32bit application and will use the WOW6432Node in 834 # the registry by default. We need to look in the 64 bit location on 64 bit 835 # systems 836 ${If} ${RunningX64} 837 # This would only apply if we are installing the 64 bit version of Salt 838 ${If} ${CPUARCH} == "AMD64" 839 # https://nsis.sourceforge.io/Docs/Chapter4.html#setregview 840 SetRegView 64 # View the 64 bit portion of the registry 841 ${EndIf} 842 ${EndIf} 843 844 # Check for existing new method installation from registry 845 # Look for `install_dir` in HKLM\SOFTWARE\Salt Project\Salt 846 ReadRegStr $R0 HKLM "SOFTWARE\Salt Project\Salt" "install_dir" 847 StrCmp $R0 "" checkOldInstallation 848 StrCpy $ExistingInstallation 1 849 # Set INSTDIR to the location in the registry 850 StrCpy $INSTDIR $R0 851 # Set RootDir, if defined 852 ReadRegStr $R0 HKLM "SOFTWARE\Salt Project\Salt" "root_dir" 853 StrCmp $R0 "" finished 854 StrCpy $RootDir $R0 855 Goto finished 856 857 # Check for existing old method installation 858 # Look for `python.exe` in C:\salt\bin 859 checkOldInstallation: 860 IfFileExists "C:\salt\bin\python.exe" 0 newInstallation 861 StrCpy $ExistingInstallation 1 862 StrCpy $INSTDIR "C:\salt" 863 StrCpy $RootDir "C:\salt" 864 Goto finished 865 866 # This is a new installation 867 # Check if custom location was passed via command line 868 newInstallation: 869 ${IfNot} $CustomLocation == "" 870 StrCpy $INSTDIR $CustomLocation 871 ${EndIf} 872 873 finished: 874 SetRegView 32 # View the 32 bit portion of the registry 875 876FunctionEnd 877 878 879# Time Stamp Definition 880Function BackupExistingConfig 881 882 ${If} $ExistingConfigFound == 1 # If existing config found 883 ${AndIfNot} $ConfigType == "Existing Config" # If not using Existing Config 884 885 # Backup the minion config 886 Rename "$RootDir\conf\minion" "$RootDir\conf\minion-${TIME_STAMP}.bak" 887 IfFileExists "$RootDir\conf\minion.d" 0 +2 888 Rename "$RootDir\conf\minion.d" "$RootDir\conf\minion.d-${TIME_STAMP}.bak" 889 890 ${EndIf} 891 892 # By this point there should be no existing config 893 # It was either backed up or wasn't there to begin with 894 ${If} $ConfigType == "Custom Config" # If we're using Custom Config 895 ${AndIfNot} $CustomConfig == "" # If a custom config is passed 896 897 # Check for a file name 898 # Named file should be in the same directory as the installer 899 CreateDirectory "$RootDir\conf" 900 IfFileExists "$EXEDIR\$CustomConfig" 0 checkFullPath 901 CopyFiles /SILENT /FILESONLY "$EXEDIR\$CustomConfig" "$RootDir\conf\minion" 902 goto finished 903 904 # Maybe it was a full path to a file 905 checkFullPath: 906 IfFileExists "$CustomConfig" 0 finished 907 CopyFiles /SILENT /FILESONLY "$CustomConfig" "$RootDir\conf\minion" 908 909 finished: 910 911 ${EndIf} 912 913FunctionEnd 914 915 916Section -Post 917 918 WriteUninstaller "$INSTDIR\uninst.exe" 919 920 # Write Uninstall Registry Entries 921 WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ 922 "DisplayName" "$(^Name)" 923 WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ 924 "UninstallString" "$INSTDIR\uninst.exe" 925 WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ 926 "DisplayIcon" "$INSTDIR\salt.ico" 927 WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ 928 "DisplayVersion" "${PRODUCT_VERSION}" 929 WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ 930 "URLInfoAbout" "${PRODUCT_WEB_SITE}" 931 WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ 932 "Publisher" "${PRODUCT_PUBLISHER}" 933 WriteRegStr HKLM "SYSTEM\CurrentControlSet\services\salt-minion" \ 934 "DependOnService" "nsi" 935 936 # Set the estimated size 937 ${GetSize} "$INSTDIR\bin" "/S=OK" $0 $1 $2 938 IntFmt $0 "0x%08X" $0 939 WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" \ 940 "EstimatedSize" "$0" 941 942 # Write Commandline Registry Entries 943 WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "" "$INSTDIR\salt-call.bat" 944 WriteRegStr HKLM "${PRODUCT_CALL_REGKEY}" "Path" "$INSTDIR\bin\" 945 WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "" "$INSTDIR\salt-minion.bat" 946 WriteRegStr HKLM "${PRODUCT_MINION_REGKEY}" "Path" "$INSTDIR\bin\" 947 948 # The NSIS installer is a 32bit application and will use the WOW6432Node in 949 # the registry by default. We need to look in the 64 bit location on 64 bit 950 # systems 951 ${If} ${RunningX64} 952 # This would only apply if we are installing the 64 bit version of Salt 953 ${If} ${CPUARCH} == "AMD64" 954 # https://nsis.sourceforge.io/Docs/Chapter4.html#setregview 955 SetRegView 64 # View 64 bit portion of the registry 956 ${EndIf} 957 ${EndIf} 958 959 # Write Salt Configuration Registry Entries 960 # We want to write EXPAND_SZ string types to allow us to use environment 961 # variables. It's OK to use EXPAND_SZ even if you don't use an environment 962 # variable so we'll just do that whether it's new location or old. 963 964 # Check for Program Files 965 # Set the current setting for INSTDIR... we'll only change it if it contains 966 # Program Files 967 StrCpy $RegInstDir $INSTDIR 968 969 # Check Program Files (x86) first 970 ${StrContains} $0 "Program Files (x86)" $INSTDIR 971 StrCmp $0 "" +2 # If it's empty, skip the next line 972 StrCpy $RegInstDir "%ProgramFiles(x86)%\Salt Project\Salt" 973 974 # Check normal Program Files next 975 ${StrContains} $0 "Program Files" $INSTDIR 976 StrCmp $0 "" +2 # If it's empty, skip the next line 977 StrCpy $RegInstDir "%ProgramFiles%\Salt Project\Salt" 978 979 # Check for ProgramData 980 # Set the current setting for RootDir. we'll only change it if it contains 981 # ProgramData 982 StrCpy $RegRootDir $RootDir 983 984 ${StrContains} $0 "ProgramData" $INSTDIR 985 StrCmp $0 "" +2 # If it's empty, skip the next line 986 StrCpy $RegRootDir "%ProgramData%\Salt Project\Salt" 987 988 WriteRegExpandStr HKLM "SOFTWARE\Salt Project\Salt" "install_dir" "$RegInstDir" 989 WriteRegExpandStr HKLM "SOFTWARE\Salt Project\Salt" "root_dir" "$RegRootDir" 990 991 # Puts the nullsoft installer back to its default 992 SetRegView 32 # Set it back to the 32 bit portion of the registry 993 994 # Register the Salt-Minion Service 995 nsExec::Exec `$INSTDIR\bin\ssm.exe install salt-minion "$INSTDIR\bin\python.exe" -E -s """$INSTDIR\bin\Scripts\salt-minion""" -c """$RootDir\conf""" -l quiet` 996 nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Description Salt Minion from saltstack.com" 997 nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Start SERVICE_AUTO_START" 998 nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion AppStopMethodConsole 24000" 999 nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion AppStopMethodWindow 2000" 1000 nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion AppRestartDelay 60000" 1001 1002 # There is a default minion config laid down in the $INSTDIR directory 1003 ${Switch} $ConfigType 1004 ${Case} "Existing Config" 1005 # If this is an Existing Config, we just remove it 1006 RMDir /r "$INSTDIR\conf" 1007 ${Break} 1008 ${Case} "Custom Config" 1009 # If this is a Custom Config, we remove it and update the custom config 1010 RMDir /r "$INSTDIR\conf" 1011 Call updateMinionConfig 1012 ${Break} 1013 ${Case} "Default Config" 1014 # If this is the default config, we move it and update it 1015 StrCpy $switch_overwrite 1 1016 1017 # This makes the $APPDATA variable point to the ProgramData folder instead 1018 # of the current user's roaming AppData folder 1019 SetShellVarContext all 1020 1021 !insertmacro MoveFolder "$INSTDIR\conf" "$APPDATA\Salt Project\Salt\conf" "*.*" 1022 Call updateMinionConfig 1023 ${Break} 1024 ${EndSwitch} 1025 1026 # Add $INSTDIR in the Path 1027 EnVar::SetHKLM 1028 EnVar::AddValue Path "$INSTDIR" 1029 1030SectionEnd 1031 1032 1033Function .onInstSuccess 1034 1035 # If StartMinionDelayed is 1, then set the service to start delayed 1036 ${If} $StartMinionDelayed == 1 1037 nsExec::Exec "$INSTDIR\bin\ssm.exe set salt-minion Start SERVICE_DELAYED_AUTO_START" 1038 ${EndIf} 1039 1040 # If start-minion is 1, then start the service 1041 ${If} $StartMinion == 1 1042 nsExec::Exec 'net start salt-minion' 1043 ${EndIf} 1044 1045FunctionEnd 1046 1047 1048Function un.onInit 1049 1050 Call un.parseUninstallerCommandLineSwitches 1051 1052 MessageBox MB_USERICON|MB_YESNO|MB_DEFBUTTON1 \ 1053 "Are you sure you want to completely remove $(^Name) and all of its components?" \ 1054 /SD IDYES IDYES +2 1055 Abort 1056 1057FunctionEnd 1058 1059 1060Section Uninstall 1061 1062 Call un.uninstallSalt 1063 1064 # Remove $INSTDIR from the Path 1065 EnVar::SetHKLM 1066 EnVar::DeleteValue Path "$INSTDIR" 1067 1068SectionEnd 1069 1070 1071!macro uninstallSalt un 1072Function ${un}uninstallSalt 1073 1074 # WARNING: Any changes made here need to be reflected in the MSI uninstaller 1075 1076 # Make sure we're in the right directory 1077 ${If} $INSTDIR == "c:\salt\bin\Scripts" 1078 StrCpy $INSTDIR "C:\salt" 1079 ${EndIf} 1080 # $ProgramFiles is different depending on the CPU Architecture 1081 # x86 : C:\Program Files 1082 # x64 : C:\Program Files (x86) 1083 ${If} $INSTDIR == "$ProgramFiles\Salt Project\Salt\bin\Scripts" 1084 StrCpy $INSTDIR "$ProgramFiles\Salt Project\Salt" 1085 ${EndIf} 1086 # $ProgramFiles64 is the C:\Program Files directory 1087 ${If} $INSTDIR == "$ProgramFiles64\Salt Project\Salt\bin\Scripts" 1088 StrCpy $INSTDIR "$ProgramFiles64\Salt Project\Salt" 1089 ${EndIf} 1090 1091 # The NSIS installer is a 32bit application and will use the WOW6432Node in 1092 # the registry by default. We need to look in the 64 bit location on 64 bit 1093 # systems 1094 ${If} ${RunningX64} 1095 # This would only apply if we are installing the 64 bit version of Salt 1096 ${If} ${CPUARCH} == "AMD64" 1097 # https://nsis.sourceforge.io/Docs/Chapter4.html#setregview 1098 SetRegView 64 # View 64 bit portion of the registry 1099 ${EndIf} 1100 ${EndIf} 1101 1102 # Get Root Directory from the Registry 1103 ReadRegStr $RootDir HKLM "SOFTWARE\Salt Project\Salt" "root_dir" 1104 SetRegView 32 # Set it back to the 32 bit portion (default) 1105 1106 # Stop and Remove salt-minion service 1107 nsExec::Exec 'net stop salt-minion' 1108 nsExec::Exec 'sc delete salt-minion' 1109 1110 # Stop and remove the salt-master service 1111 nsExec::Exec 'net stop salt-master' 1112 nsExec::Exec 'sc delete salt-master' 1113 1114 # Remove files 1115 Delete "$INSTDIR\uninst.exe" 1116 # TODO: The service needs to be unregistered before removing SSM 1117 Delete "$INSTDIR\ssm.exe" 1118 Delete "$INSTDIR\salt*" 1119 Delete "$INSTDIR\vcredist.exe" 1120 RMDir /r "$INSTDIR\bin" 1121 1122 # Remove Registry entries 1123 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" 1124 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY_OTHER}" 1125 1126 # Remove Command Line Registry entries 1127 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_CALL_REGKEY}" 1128 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_CP_REGKEY}" 1129 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_KEY_REGKEY}" 1130 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_MASTER_REGKEY}" 1131 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_MINION_REGKEY}" 1132 DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_RUN_REGKEY}" 1133 1134 # Remove Salt Configuration Registry entries 1135 # The NSIS installer is a 32bit application and will use the WOW6432Node in 1136 # the registry by default. We need to look in the 64 bit location on 64 bit 1137 # systems 1138 ${If} ${RunningX64} 1139 # This would only apply if we are installing the 64 bit version of Salt 1140 ${If} ${CPUARCH} == "AMD64" 1141 # https://nsis.sourceforge.io/Docs/Chapter4.html#setregview 1142 SetRegView 64 # View 64 bit portion of the registry 1143 ${EndIf} 1144 ${EndIf} 1145 DeleteRegKey HKLM "SOFTWARE\Salt Project" 1146 SetRegView 32 # Set it back to the 32 bit portion (default) 1147 1148 # SystemDrive is not a built in NSIS constant, so we need to get it from 1149 # the environment variables 1150 ReadEnvStr $0 "SystemDrive" # Get the SystemDrive env var 1151 StrCpy $SysDrive "$0\" 1152 1153 # Automatically close when finished 1154 SetAutoClose true 1155 1156 # Old Method Installation 1157 ${If} $INSTDIR == "C:\salt" 1158 1159 # Prompt to remove the Installation Directory. This is because that 1160 # directory is also the root_dir which includes the config and pki 1161 # directories 1162 ${IfNot} $DeleteInstallDir == 1 1163 MessageBox MB_YESNO|MB_DEFBUTTON2|MB_USERICON \ 1164 "Would you like to completely remove $INSTDIR and all of its contents?" \ 1165 /SD IDNO IDNO finished 1166 ${EndIf} 1167 1168 SetOutPath "$SysDrive" # Can't remove CWD 1169 RMDir /r "$INSTDIR" 1170 1171 ${Else} 1172 1173 # New Method Installation 1174 # This makes the $APPDATA variable point to the ProgramData folder instead 1175 # of the current user's roaming AppData folder 1176 SetShellVarContext all 1177 1178 # We can always remove the Installation Directory on New Method Installs 1179 # because it only contains binary data 1180 1181 # Remove INSTDIR 1182 # Make sure you're not removing important system directory such as 1183 # Program Files, C:\Windows, or C: 1184 ${If} $INSTDIR != $ProgramFiles 1185 ${AndIf} $INSTDIR != $ProgramFiles64 1186 ${AndIf} $INSTDIR != $SysDrive 1187 ${AndIf} $INSTDIR != $WinDir 1188 SetOutPath "$SysDrive" # Can't remove CWD 1189 RMDir /r $INSTDIR 1190 ${EndIf} 1191 1192 # Remove INSTDIR (The parent) 1193 # For example, though salt is installed in ProgramFiles\Salt Project\Salt 1194 # We want to remove ProgramFiles\Salt Project 1195 # Only delete Salt Project directory if it's in Program Files 1196 # Otherwise, we can't guess where the user may have installed salt 1197 ${GetParent} $INSTDIR $0 # Get parent directory (Salt Project) 1198 ${If} $0 == "$ProgramFiles\Salt Project" # Make sure it's not ProgramFiles 1199 ${OrIf} $0 == "$ProgramFiles64\Salt Project" # Make sure it's not Program Files (x86) 1200 SetOutPath "$SysDrive" # Can't remove CWD 1201 RMDir /r $0 1202 ${EndIf} 1203 1204 # Prompt for the removal of the Root Directory which contains the config 1205 # and pki directories 1206 ${IfNot} $DeleteRootDir == 1 1207 MessageBox MB_YESNO|MB_DEFBUTTON2|MB_USERICON \ 1208 "Would you like to completely remove the Root Directory ($RootDir) and all of its contents?" \ 1209 /SD IDNO IDNO finished 1210 ${EndIf} 1211 1212 # Remove the Salt Project directory in ProgramData 1213 # The Salt Project directory will only ever be in ProgramData 1214 # It is not user selectable 1215 ${GetParent} $RootDir $0 # Get parent directory 1216 ${If} $0 == "$APPDATA\Salt Project" # Make sure it's not ProgramData 1217 SetOutPath "$SysDrive" # Can't remove CWD 1218 RMDir /r $0 1219 ${EndIf} 1220 1221 ${EndIf} 1222 1223 finished: 1224 1225FunctionEnd 1226!macroend 1227 1228 1229!insertmacro uninstallSalt "" 1230!insertmacro uninstallSalt "un." 1231 1232 1233Function un.onUninstSuccess 1234 HideWindow 1235 MessageBox MB_OK|MB_USERICON \ 1236 "$(^Name) was successfully removed from your computer." \ 1237 /SD IDOK 1238FunctionEnd 1239 1240 1241############################################################################### 1242# Helper Functions 1243############################################################################### 1244Function MsiQueryProductState 1245 # Used for detecting VCRedist Installation 1246 !define INSTALLSTATE_DEFAULT "5" 1247 1248 StrCpy $NeedVcRedist "False" 1249 System::Call "msi::MsiQueryProductStateA(t '$VcRedistGuid') i.r0" 1250 StrCmp $0 ${INSTALLSTATE_DEFAULT} +2 0 1251 StrCpy $NeedVcRedist "True" 1252 1253FunctionEnd 1254 1255#------------------------------------------------------------------------------ 1256# Trim Function 1257# - Trim whitespace from the beginning and end of a string 1258# - Trims spaces, \r, \n, \t 1259# 1260# Usage: 1261# Push " some string " ; String to Trim 1262# Call Trim 1263# Pop $0 ; Trimmed String: "some string" 1264# 1265# or 1266# 1267# ${Trim} $0 $1 ; Trimmed String, String to Trim 1268#------------------------------------------------------------------------------ 1269Function Trim 1270 1271 Exch $R1 # Original string 1272 Push $R2 1273 1274 Loop: 1275 StrCpy $R2 "$R1" 1 1276 StrCmp "$R2" " " TrimLeft 1277 StrCmp "$R2" "$\r" TrimLeft 1278 StrCmp "$R2" "$\n" TrimLeft 1279 StrCmp "$R2" "$\t" TrimLeft 1280 GoTo Loop2 1281 TrimLeft: 1282 StrCpy $R1 "$R1" "" 1 1283 Goto Loop 1284 1285 Loop2: 1286 StrCpy $R2 "$R1" 1 -1 1287 StrCmp "$R2" " " TrimRight 1288 StrCmp "$R2" "$\r" TrimRight 1289 StrCmp "$R2" "$\n" TrimRight 1290 StrCmp "$R2" "$\t" TrimRight 1291 GoTo Done 1292 TrimRight: 1293 StrCpy $R1 "$R1" -1 1294 Goto Loop2 1295 1296 Done: 1297 Pop $R2 1298 Exch $R1 1299 1300FunctionEnd 1301 1302 1303#------------------------------------------------------------------------------ 1304# Explode Function 1305# - Splits a string based off the passed separator 1306# - Each item in the string is pushed to the stack 1307# - The last item pushed to the stack is the length of the array 1308# 1309# Usage: 1310# Push "," ; Separator 1311# Push "string,to,separate" ; String to explode 1312# Call Explode 1313# Pop $0 ; Number of items in the array 1314# 1315# or 1316# 1317# ${Explode} $0 $1 $2 ; Length, Separator, String 1318#------------------------------------------------------------------------------ 1319Function Explode 1320 # Initialize variables 1321 Var /GLOBAL explString 1322 Var /GLOBAL explSeparator 1323 Var /GLOBAL explStrLen 1324 Var /GLOBAL explSepLen 1325 Var /GLOBAL explOffset 1326 Var /GLOBAL explTmp 1327 Var /GLOBAL explTmp2 1328 Var /GLOBAL explTmp3 1329 Var /GLOBAL explArrCount 1330 1331 # Get input from user 1332 Pop $explString 1333 Pop $explSeparator 1334 1335 # Calculates initial values 1336 StrLen $explStrLen $explString 1337 StrLen $explSepLen $explSeparator 1338 StrCpy $explArrCount 1 1339 1340 ${If} $explStrLen <= 1 # If we got a single character 1341 ${OrIf} $explSepLen > $explStrLen # or separator is larger than the string, 1342 Push $explString # then we return initial string with no change 1343 Push 1 # and set array's length to 1 1344 Return 1345 ${EndIf} 1346 1347 # Set offset to the last symbol of the string 1348 StrCpy $explOffset $explStrLen 1349 IntOp $explOffset $explOffset - 1 1350 1351 # Clear temp string to exclude the possibility of appearance of occasional data 1352 StrCpy $explTmp "" 1353 StrCpy $explTmp2 "" 1354 StrCpy $explTmp3 "" 1355 1356 # Loop until the offset becomes negative 1357 ${Do} 1358 # If offset becomes negative, it is time to leave the function 1359 ${IfThen} $explOffset == -1 ${|} ${ExitDo} ${|} 1360 1361 # Remove everything before and after the searched part ("TempStr") 1362 StrCpy $explTmp $explString $explSepLen $explOffset 1363 1364 ${If} $explTmp == $explSeparator 1365 # Calculating offset to start copy from 1366 IntOp $explTmp2 $explOffset + $explSepLen # Offset equals to the current offset plus length of separator 1367 StrCpy $explTmp3 $explString "" $explTmp2 1368 1369 Push $explTmp3 # Throwing array item to the stack 1370 IntOp $explArrCount $explArrCount + 1 # Increasing array's counter 1371 1372 StrCpy $explString $explString $explOffset 0 # Cutting all characters beginning with the separator entry 1373 StrLen $explStrLen $explString 1374 ${EndIf} 1375 1376 ${If} $explOffset = 0 # If the beginning of the line met and there is no separator, 1377 # copying the rest of the string 1378 ${If} $explSeparator == "" # Fix for the empty separator 1379 IntOp $explArrCount $explArrCount - 1 1380 ${Else} 1381 Push $explString 1382 ${EndIf} 1383 ${EndIf} 1384 1385 IntOp $explOffset $explOffset - 1 1386 ${Loop} 1387 1388 Push $explArrCount 1389FunctionEnd 1390 1391 1392#------------------------------------------------------------------------------ 1393# StrContains 1394# 1395# This function does a case sensitive searches for an occurrence of a substring in a string. 1396# It returns the substring if it is found. 1397# Otherwise it returns null(""). 1398# Written by kenglish_hi 1399# Adapted from StrReplace written by dandaman32 1400#------------------------------------------------------------------------------ 1401Function StrContains 1402 1403 # Initialize variables 1404 Var /GLOBAL STR_HAYSTACK 1405 Var /GLOBAL STR_NEEDLE 1406 Var /GLOBAL STR_CONTAINS_VAR_1 1407 Var /GLOBAL STR_CONTAINS_VAR_2 1408 Var /GLOBAL STR_CONTAINS_VAR_3 1409 Var /GLOBAL STR_CONTAINS_VAR_4 1410 Var /GLOBAL STR_RETURN_VAR 1411 1412 Exch $STR_NEEDLE 1413 Exch 1 1414 Exch $STR_HAYSTACK 1415 # Uncomment to debug 1416 #MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK ' 1417 StrCpy $STR_RETURN_VAR "" 1418 StrCpy $STR_CONTAINS_VAR_1 -1 1419 StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE 1420 StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK 1421 1422 loop: 1423 IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1 1424 StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1 1425 StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found 1426 StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done 1427 Goto loop 1428 1429 found: 1430 StrCpy $STR_RETURN_VAR $STR_NEEDLE 1431 Goto done 1432 1433 done: 1434 Pop $STR_NEEDLE # Prevent "invalid opcode" errors and keep the stack clean 1435 Exch $STR_RETURN_VAR 1436FunctionEnd 1437 1438 1439#------------------------------------------------------------------------------ 1440# UninstallMSI Function 1441# - Uninstalls MSI by product code 1442# 1443# Usage: 1444# Push product code 1445# Call UninstallMSI 1446# 1447# Source: 1448# https://nsis.sourceforge.io/Uninstalling_a_previous_MSI_(Windows_installer_package) 1449#------------------------------------------------------------------------------ 1450Function UninstallMSI 1451 ; $R0 === product code 1452 MessageBox MB_OKCANCEL|MB_ICONINFORMATION \ 1453 "${PRODUCT_NAME} is already installed via MSI.$\n$\n\ 1454 Click `OK` to remove the existing installation." \ 1455 /SD IDOK IDOK UninstallMSI 1456 Abort 1457 1458 UninstallMSI: 1459 ExecWait '"msiexec.exe" /x $R0 /qb /quiet /norestart' 1460 1461FunctionEnd 1462 1463 1464############################################################################### 1465# Specialty Functions 1466############################################################################### 1467Function getExistingMinionConfig 1468 1469 # Set Config Found Default Value 1470 StrCpy $ExistingConfigFound 0 1471 1472 # Find config, should be in $RootDir\conf\minion 1473 # Root dir is usually ProgramData\Salt Project\Salt\conf though it may be 1474 # C:\salt\conf if Salt was installed the old way 1475 IfFileExists "$RootDir\conf\minion" check_owner 1476 IfFileExists "C:\salt\conf\minion" old_location confNotFound 1477 1478 old_location: 1479 StrCpy $RootDir "C:\salt" 1480 1481 check_owner: 1482 # We need to verify the owner of the config directory (C:\salt\conf) to 1483 # ensure the config has not been modified by an unknown user. The 1484 # permissions and ownership of the directories is determined by the 1485 # installer used to install Salt. The NullSoft installer requests Admin 1486 # privileges so all directories are created with the Administrators 1487 # Group (S-1-5-32-544) as the owner. The MSI installer, however, runs in 1488 # the context of the Windows Installer service (msiserver), therefore 1489 # all directories are created with the Local System account (S-1-5-18) 1490 # as the owner. 1491 # 1492 # When Salt is launched it sets the root_dir (C:\salt) permissions as 1493 # follows: 1494 # - Owner: Administrators 1495 # - Allow Perms: 1496 # - Owner: Full Control 1497 # - System: Full Control 1498 # - Administrators: Full Control 1499 # 1500 # The conf_dir (C:\salt\conf) inherits Allow/Deny permissions from the 1501 # parent, but NOT Ownership. The owner will be the Administrators Group 1502 # if it was installed via NullSoft or the Local System account if it was 1503 # installed via the MSI. Therefore valid owners for the conf_dir are 1504 # both the Administrators group and the Local System account. 1505 # 1506 # An unprivileged account cannot change the owner of a directory by 1507 # default. So, if the owner of the conf_dir is either the Administrators 1508 # group or the Local System account, then we will trust it. Otherwise, 1509 # we will display an option to abort the installation or to backup the 1510 # untrusted config directory and continue with the default config. If 1511 # running the install with the silent option (/S) it will backup the 1512 # untrusted config directory and continue with the default config. 1513 1514 AccessControl::GetFileOwner /SID "$RootDir\conf" 1515 Pop $0 1516 1517 # Check for valid SIDs 1518 StrCmp $0 "S-1-5-32-544" correct_owner # Administrators Group (NullSoft) 1519 StrCmp $0 "S-1-5-18" correct_owner # Local System (MSI) 1520 MessageBox MB_YESNO "Insecure config found at $RootDir\conf. If you \ 1521 continue, the config directory will be renamed to \ 1522 $RootDir\conf.insecure and the default config will be used. \ 1523 Continue?" /SD IDYES IDYES insecure_config 1524 Abort 1525 1526 insecure_config: 1527 # Backing up insecure config 1528 Rename "$RootDir\conf" "$RootDir\conf.insecure-${TIME_STAMP}" 1529 Goto confNotFound 1530 1531 correct_owner: 1532 StrCpy $ExistingConfigFound 1 1533 FileOpen $0 "$RootDir\conf\minion" r 1534 1535 confLoop: 1536 ClearErrors # clear Errors 1537 FileRead $0 $1 # read the next line 1538 IfErrors EndOfFile # error is probably EOF 1539 ${StrLoc} $2 $1 "master:" ">" # find `master:` starting at the beginning 1540 ${If} $2 == 0 # if it found it in the first position, then it is defined 1541 ${StrStrAdv} $2 $1 "master: " ">" ">" "0" "0" "0" # read everything after `master: ` 1542 ${Trim} $2 $2 # trim white space 1543 ${If} $2 == "" # if it's empty, it's probably a list of masters 1544 masterLoop: 1545 ClearErrors # clear Errors 1546 FileRead $0 $1 # read the next line 1547 IfErrors EndOfFile # error is probably EOF 1548 ${StrStrAdv} $2 $1 "- " ">" ">" "0" "0" "0" # read everything after `- ` 1549 ${Trim} $2 $2 # trim white space 1550 ${IfNot} $2 == "" # if the line is not empty, we found something 1551 ${If} $MasterHost_Cfg == "" # if the config setting is empty 1552 StrCpy $MasterHost_Cfg $2 # make the first item the new entry 1553 ${Else} 1554 StrCpy $MasterHost_Cfg "$MasterHost_Cfg,$2" # Append the new master, comma separated 1555 ${EndIf} 1556 Goto masterLoop # check the next one 1557 ${EndIf} 1558 ${Else} 1559 StrCpy $MasterHost_Cfg $2 # a single master entry 1560 ${EndIf} 1561 ${EndIf} 1562 1563 ${StrLoc} $2 $1 "id:" ">" 1564 ${If} $2 == 0 1565 ${StrStrAdv} $2 $1 "id: " ">" ">" "0" "0" "0" 1566 ${Trim} $2 $2 1567 StrCpy $MinionName_Cfg $2 1568 ${EndIf} 1569 1570 Goto confLoop 1571 1572 EndOfFile: 1573 FileClose $0 1574 1575 confNotFound: 1576 1577 # Set Default Config Values if not found 1578 ${If} $MasterHost_Cfg == "" 1579 StrCpy $MasterHost_Cfg "salt" 1580 ${EndIf} 1581 ${If} $MinionName_Cfg == "" 1582 StrCpy $MinionName_Cfg "hostname" 1583 ${EndIf} 1584 1585FunctionEnd 1586 1587 1588Var cfg_line 1589Var chk_line 1590Var lst_check 1591Function updateMinionConfig 1592 1593 ClearErrors 1594 FileOpen $0 "$RootDir\conf\minion" "r" # open target file for reading 1595 GetTempFileName $R0 # get new temp file name 1596 FileOpen $1 $R0 "w" # open temp file for writing 1597 1598 StrCpy $ConfigWriteMaster 1 # write the master config value 1599 StrCpy $ConfigWriteMinion 1 # write the minion config value 1600 1601 loop: # loop through each line 1602 FileRead $0 $cfg_line # read line from target file 1603 IfErrors done # end if errors are encountered (end of line) 1604 1605 loop_after_read: 1606 StrCpy $lst_check 0 # list check not performed 1607 1608 ${If} $MasterHost == "" # if master is empty 1609 ${OrIf} $MasterHost == "salt" # or if master is 'salt' 1610 StrCpy $ConfigWriteMaster 0 # no need to write master config 1611 ${EndIf} # close if statement 1612 ${If} $MinionName == "" # if minion is empty 1613 ${OrIf} $MinionName == "hostname" # and if minion is not 'hostname' 1614 StrCpy $ConfigWriteMinion 0 # no need to write minion config 1615 ${EndIf} # close if statement 1616 1617 ${If} $ConfigWriteMaster == 1 # if we need to write master config 1618 1619 ${StrLoc} $3 $cfg_line "master:" ">" # where is 'master:' in this line 1620 ${If} $3 == 0 # is it in the first... 1621 ${OrIf} $3 == 1 # or second position (account for comments) 1622 1623 ${Explode} $9 "," $MasterHost_state # Split the hostname on commas, $9 is the number of items found 1624 ${If} $9 == 1 # 1 means only a single master was passed 1625 StrCpy $cfg_line "master: $MasterHost$\r$\n" # write the master 1626 ${Else} # make a multi-master entry 1627 StrCpy $cfg_line "master:" # make the first line "master:" 1628 1629 loop_explode: # start a loop to go through the list in the config 1630 pop $8 # pop the next item off the stack 1631 ${Trim} $8 $8 # trim any whitespace 1632 StrCpy $cfg_line "$cfg_line$\r$\n - $8" # add it to the master variable ($2) 1633 IntOp $9 $9 - 1 # decrement the list count 1634 ${If} $9 >= 1 # if it's not 0 1635 Goto loop_explode # do it again 1636 ${EndIf} # close if statement 1637 StrCpy $cfg_line "$cfg_line$\r$\n" # Make sure there's a new line at the end 1638 1639 # Remove remaining items in list 1640 ${While} $lst_check == 0 # while list item found 1641 FileRead $0 $chk_line # read line from target file 1642 IfErrors done # end if errors are encountered (end of line) 1643 ${StrLoc} $3 $chk_line " - " ">" # where is 'master:' in this line 1644 ${If} $3 == "" # is it in the first... 1645 StrCpy $lst_check 1 # list check performed and finished 1646 ${EndIf} 1647 ${EndWhile} 1648 1649 ${EndIf} # close if statement 1650 1651 StrCpy $ConfigWriteMaster 0 # master value written to config 1652 1653 ${EndIf} # close if statement 1654 ${EndIf} # close if statement 1655 1656 ${If} $ConfigWriteMinion == 1 # if we need to write minion config 1657 ${StrLoc} $3 $cfg_line "id:" ">" # where is 'id:' in this line 1658 ${If} $3 == 0 # is it in the first... 1659 ${OrIf} $3 == 1 # or the second position (account for comments) 1660 StrCpy $cfg_line "id: $MinionName$\r$\n" # write the minion config setting 1661 StrCpy $ConfigWriteMinion 0 # minion value written to config 1662 ${EndIf} # close if statement 1663 ${EndIf} # close if statement 1664 1665 FileWrite $1 $cfg_line # write changed or unchanged line to temp file 1666 1667 ${If} $lst_check == 1 # master not written to the config 1668 StrCpy $cfg_line $chk_line 1669 Goto loop_after_read # A loop was performed, skip the next read 1670 ${EndIf} # close if statement 1671 1672 Goto loop # check the next line in the config file 1673 1674 done: 1675 ClearErrors 1676 # Does master config still need to be written 1677 ${If} $ConfigWriteMaster == 1 # master not written to the config 1678 1679 ${Explode} $9 "," $MasterHost_state # split the hostname on commas, $9 is the number of items found 1680 ${If} $9 == 1 # 1 means only a single master was passed 1681 StrCpy $cfg_line "master: $MasterHost" # write the master 1682 ${Else} # make a multi-master entry 1683 StrCpy $cfg_line "master:" # make the first line "master:" 1684 1685 loop_explode_2: # start a loop to go through the list in the config 1686 pop $8 # pop the next item off the stack 1687 ${Trim} $8 $8 # trim any whitespace 1688 StrCpy $cfg_line "$cfg_line$\r$\n - $8" # add it to the master variable ($2) 1689 IntOp $9 $9 - 1 # decrement the list count 1690 ${If} $9 >= 1 # if it's not 0 1691 Goto loop_explode_2 # do it again 1692 ${EndIf} # close if statement 1693 ${EndIf} # close if statement 1694 FileWrite $1 $cfg_line # write changed or unchanged line to temp file 1695 1696 ${EndIf} # close if statement 1697 1698 ${If} $ConfigWriteMinion == 1 # minion ID not written to the config 1699 StrCpy $cfg_line "$\r$\nid: $MinionName" # write the minion config setting 1700 FileWrite $1 $cfg_line # write changed or unchanged line to temp file 1701 ${EndIf} # close if statement 1702 1703 FileClose $0 # close target file 1704 FileClose $1 # close temp file 1705 Delete "$RootDir\conf\minion" # delete target file 1706 CopyFiles /SILENT $R0 "$RootDir\conf\minion" # copy temp file to target file 1707 Delete $R0 # delete temp file 1708 1709FunctionEnd 1710 1711 1712Function un.parseUninstallerCommandLineSwitches 1713 1714 # Load the parameters 1715 ${GetParameters} $R0 1716 1717 # Display Help 1718 ClearErrors 1719 ${GetOptions} $R0 "/?" $R1 1720 IfErrors display_un_help_not_found 1721 1722 # Using a message box here 1723 # I couldn't get the console output to work with the uninstaller 1724 MessageBox MB_OK "\ 1725 Help for Salt Minion Uninstallation\ 1726 $\n\ 1727 $\n==============================================\ 1728 $\n\ 1729 $\n/delete-install-dir$\tDelete the installation directory that contains the\ 1730 $\n$\t$\tconfig and pki directories. Default is to not delete\ 1731 $\n$\t$\tthe installation directory\ 1732 $\n\ 1733 $\n$\t$\tThis applies to old method installations where\ 1734 $\n$\t$\tthe root directory and the installation directory\ 1735 $\n$\t$\tare the same (C:\salt)\ 1736 $\n\ 1737 $\n/delete-root-dir$\tDelete the root directory that contains the config\ 1738 $\n$\t$\tand pki directories. Default is to not delete the root\ 1739 $\n$\t$\tdirectory\ 1740 $\n\ 1741 $\n$\t$\tThis applies to new method installations where the\ 1742 $\n$\t$\troot directory is in ProgramData and the installation\ 1743 $\n$\t$\tdirectory is user defined, usually Program Files\ 1744 $\n\ 1745 $\n/S$\t$\tUninstall Salt silently\ 1746 $\n\ 1747 $\n/?$\t$\tDisplay this help screen\ 1748 $\n\ 1749 $\n--------------------------------------------------------------------------------------------\ 1750 $\n\ 1751 $\nExamples:\ 1752 $\n\ 1753 $\n$\tuninst.exe /S\ 1754 $\n\ 1755 $\n$\tuninst.exe /S /delete-root-dir\ 1756 $\n\ 1757 $\n==============================================" 1758 1759 Abort 1760 1761 display_un_help_not_found: 1762 1763 # Load the parameters 1764 ${GetParameters} $R0 1765 1766 # Uninstaller: Remove Installation Directory 1767 ClearErrors 1768 ${GetOptions} $R0 "/delete-install-dir" $R1 1769 IfErrors delete_install_dir_not_found 1770 StrCpy $DeleteInstallDir 1 1771 delete_install_dir_not_found: 1772 1773 # Uninstaller: Remove Root Directory 1774 ClearErrors 1775 ${GetOptions} $R0 "/delete-root-dir" $R1 1776 IfErrors delete_root_dir_not_found 1777 StrCpy $DeleteRootDir 1 1778 delete_root_dir_not_found: 1779 1780FunctionEnd 1781 1782 1783Function parseInstallerCommandLineSwitches 1784 1785 # Load the parameters 1786 ${GetParameters} $R0 1787 1788 # Display Help 1789 ClearErrors 1790 ${GetOptions} $R0 "/?" $R1 1791 IfErrors display_help_not_found 1792 1793 System::Call 'kernel32::GetStdHandle(i -11)i.r0' 1794 System::Call 'kernel32::AttachConsole(i -1)i.r1' 1795 ${If} $0 = 0 1796 ${OrIf} $1 = 0 1797 System::Call 'kernel32::AllocConsole()' 1798 System::Call 'kernel32::GetStdHandle(i -11)i.r0' 1799 ${EndIf} 1800 FileWrite $0 "$\n" 1801 FileWrite $0 "$\n" 1802 FileWrite $0 "Help for Salt Minion installation$\n" 1803 FileWrite $0 "===============================================================================$\n" 1804 FileWrite $0 "$\n" 1805 FileWrite $0 "/minion-name=$\t$\tA string value to set the minion name. Default value is$\n" 1806 FileWrite $0 "$\t$\t$\t'hostname'. Setting the minion name causes the installer$\n" 1807 FileWrite $0 "$\t$\t$\tto use the default config or a custom config if defined$\n" 1808 FileWrite $0 "$\n" 1809 FileWrite $0 "/master=$\t$\tA string value to set the IP address or hostname of the$\n" 1810 FileWrite $0 "$\t$\t$\tmaster. Default value is 'salt'. You may pass a single$\n" 1811 FileWrite $0 "$\t$\t$\tmaster or a comma-separated list of masters. Setting$\n" 1812 FileWrite $0 "$\t$\t$\tthe master will cause the installer to use the default$\n" 1813 FileWrite $0 "$\t$\t$\tconfig or a custom config if defined$\n" 1814 FileWrite $0 "$\n" 1815 FileWrite $0 "/start-minion=$\t$\t1 will start the minion service, 0 will not.$\n" 1816 FileWrite $0 "$\t$\t$\tDefault is 1$\n" 1817 FileWrite $0 "$\n" 1818 FileWrite $0 "/start-minion-delayed$\tSet the minion start type to 'Automatic (Delayed Start)'$\n" 1819 FileWrite $0 "$\n" 1820 FileWrite $0 "/default-config$\t$\tOverwrite the existing config if present with the$\n" 1821 FileWrite $0 "$\t$\t$\tdefault config for salt. Default is to use the existing$\n" 1822 FileWrite $0 "$\t$\t$\tconfig if present. If /master and/or /minion-name is$\n" 1823 FileWrite $0 "$\t$\t$\tpassed, those values will be used to update the new$\n" 1824 FileWrite $0 "$\t$\t$\tdefault config$\n" 1825 FileWrite $0 "$\n" 1826 FileWrite $0 "$\t$\t$\tAny existing config will be backed up by appending$\n" 1827 FileWrite $0 "$\t$\t$\ta timestamp and a .bak extension. That includes$\n" 1828 FileWrite $0 "$\t$\t$\tthe minion file and the minion.d directory$\n" 1829 FileWrite $0 "$\n" 1830 FileWrite $0 "/custom-config=$\t$\tA string value specifying the name of a custom config$\n" 1831 FileWrite $0 "$\t$\t$\tfile in the same path as the installer or the full path$\n" 1832 FileWrite $0 "$\t$\t$\tto a custom config file. If /master and/or /minion-name$\n" 1833 FileWrite $0 "$\t$\t$\tis passed, those values will be used to update the new$\n" 1834 FileWrite $0 "$\t$\t$\tcustom config$\n" 1835 FileWrite $0 "$\n" 1836 FileWrite $0 "$\t$\t$\tAny existing config will be backed up by appending$\n" 1837 FileWrite $0 "$\t$\t$\ta timestamp and a .bak extension. That includes$\n" 1838 FileWrite $0 "$\t$\t$\tthe minion file and the minion.d directory$\n" 1839 FileWrite $0 "$\n" 1840 FileWrite $0 "/install-dir=$\tSpecify the installation location for the Salt binaries.$\n" 1841 FileWrite $0 "$\t$\t$\tThis will be ignored for existing installations.$\n" 1842 FileWrite $0 "$\n" 1843 FileWrite $0 "/move-config$\t$\tIf config is found at C:\salt it will be moved to %ProgramData%$\n" 1844 FileWrite $0 "$\n" 1845 FileWrite $0 "/S$\t$\t$\tInstall Salt silently$\n" 1846 FileWrite $0 "$\n" 1847 FileWrite $0 "/?$\t$\t$\tDisplay this help screen$\n" 1848 FileWrite $0 "$\n" 1849 FileWrite $0 "-------------------------------------------------------------------------------$\n" 1850 FileWrite $0 "$\n" 1851 FileWrite $0 "Examples:$\n" 1852 FileWrite $0 "$\n" 1853 FileWrite $0 "$\t$EXEFILE /S$\n" 1854 FileWrite $0 "$\n" 1855 FileWrite $0 "$\t$EXEFILE /S /minion-name=myminion /master=master.mydomain.com /start-minion-delayed$\n" 1856 FileWrite $0 "$\n" 1857 FileWrite $0 "$\t$EXEFILE /S /minion-name=myminion /master=master.mydomain.com /install-dir=$\"C:\Software\salt$\"$\n" 1858 FileWrite $0 "$\n" 1859 FileWrite $0 "===============================================================================$\n" 1860 FileWrite $0 "$\n" 1861 System::Free $0 1862 System::Free $1 1863 System::Call 'kernel32::FreeConsole()' 1864 1865 # Give the user back the prompt 1866 !define VK_RETURN 0x0D ; Enter Key 1867 !define KEYEVENTF_EXTENDEDKEY 0x0001 1868 !define KEYEVENTF_KEYUP 0x0002 1869 System::Call "user32::keybd_event(i${VK_RETURN}, i0x45, i${KEYEVENTF_EXTENDEDKEY}|0, i0)" 1870 System::Call "user32::keybd_event(i${VK_RETURN}, i0x45, i${KEYEVENTF_EXTENDEDKEY}|${KEYEVENTF_KEYUP}, i0)" 1871 Abort 1872 1873 display_help_not_found: 1874 1875 # Set default value for Use Existing Config 1876 StrCpy $ConfigType "Existing Config" 1877 1878 # Check for start-minion switches 1879 # /start-service is to be deprecated, so we must check for both 1880 ${GetOptions} $R0 "/start-service=" $R1 1881 ${GetOptions} $R0 "/start-minion=" $R2 1882 1883 # Service: Start Salt Minion 1884 ${IfNot} $R2 == "" 1885 # If start-minion was passed something, then set it 1886 StrCpy $StartMinion $R2 1887 ${ElseIfNot} $R1 == "" 1888 # If start-service was passed something, then set StartMinion to that 1889 StrCpy $StartMinion $R1 1890 MessageBox MB_OK|MB_ICONINFORMATION "`/start-service` is being deprecated. Please use `/start-minion` instead." /SD IDOK 1891 ${Else} 1892 # Otherwise default to 1 1893 StrCpy $StartMinion 1 1894 ${EndIf} 1895 1896 # Service: Minion Startup Type Delayed 1897 ClearErrors 1898 ${GetOptions} $R0 "/start-minion-delayed" $R1 1899 IfErrors start_minion_delayed_not_found 1900 StrCpy $StartMinionDelayed 1 1901 start_minion_delayed_not_found: 1902 1903 # Minion Config: Master IP/Name 1904 # If setting master, we don't want to use existing config 1905 ${GetOptions} $R0 "/master=" $R1 1906 ${IfNot} $R1 == "" 1907 StrCpy $MasterHost $R1 1908 StrCpy $ConfigType "Default Config" 1909 ${ElseIf} $MasterHost == "" 1910 StrCpy $MasterHost "salt" 1911 ${EndIf} 1912 1913 # Minion Config: Minion ID 1914 # If setting minion id, we don't want to use existing config 1915 ${GetOptions} $R0 "/minion-name=" $R1 1916 ${IfNot} $R1 == "" 1917 StrCpy $MinionName $R1 1918 StrCpy $ConfigType "Default Config" 1919 ${ElseIf} $MinionName == "" 1920 StrCpy $MinionName "hostname" 1921 ${EndIf} 1922 1923 # Use Default Config 1924 ClearErrors 1925 ${GetOptions} $R0 "/default-config" $R1 1926 IfErrors default_config_not_found 1927 StrCpy $ConfigType "Default Config" 1928 default_config_not_found: 1929 1930 # Use Custom Config 1931 # Set default value for Use Custom Config 1932 StrCpy $CustomConfig "" 1933 # Existing config will get a `.bak` extension 1934 ${GetOptions} $R0 "/custom-config=" $R1 1935 ${IfNot} $R1 == "" 1936 # A Custom Config was passed, set it 1937 StrCpy $CustomConfig $R1 1938 StrCpy $ConfigType "Custom Config" 1939 ${EndIf} 1940 1941 # Set Install Location 1942 ClearErrors 1943 ${GetOptions} $R0 "/install-dir=" $R1 1944 ${IfNot} $R1 == "" 1945 # A Custom Location was passed, set it 1946 StrCpy $CustomLocation $R1 1947 ${EndIf} 1948 1949 # Set Move Config Option 1950 ClearErrors 1951 ${GetOptions} $R0 "/move-config" $R1 1952 IfErrors move_config_not_found 1953 StrCpy $MoveExistingConfig 1 1954 move_config_not_found: 1955 1956FunctionEnd 1957