NSIS script to install an exe which requires a Registration Name and Key to be set - executable

Problem: I need to write a nsi for doing a series of tasks including creating a folder, some IE settings changes, Firewall changes and Installing an exe. The exe to be installed is a licensed copy and requires a Registration Name and Key which I have.
Scenario: I need to perform the same steps after installing the exe in more than 50 computers and I want to make the process free of manual errors.
I successfully wrote all steps but still to find how to install the exe, which prompts me for a Registration Name and Key.
Thanks
lazywizar

Can you explain how do you plan to handle the registration name and key, will you need a server to validate the installation ?
Anyway you have to make a custom page and create custom forms in this page. Something like :
Page custom CreatePage QuitPage
Where CreatePage is a function that creates the page ui
Example:
;;In the variables section
var regname_hdl
var regkey_hdl
Var regname_inpt_hdl
var regkey_inpt_hdl
var RegName
var RegKey
Function CreatePage
GetDlgItem $0 $hwndParent 3
EnableWindow $0 0
nsDialogs::Create 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
${NSD_CreateLabel} 0 0 100% 10u "Say something to user"
Pop $Label
${NSD_CreateLabel} 20u 20u 20% 20u "Enter Registration Name "
Pop $regname_inpt_hdl
${NSD_CreateLabel} 20u 40u 20% 20u "Enter Registration Key "
Pop $regkey_inpt_hdl
${NSD_CreateText} 30% 20u 30% 10u ""
Pop $regname_hdl
${NSD_CreatePassword} 30% 40u 30% 10u ""
Pop $regkey_hdl
nsDialogs::Show
FunctionEnd
Function QuitPage
${NSD_GetText} $reg_hdl $2
${NSD_GetText} $key_hdl $3
Push $3
Push $2
Pop $RegName
Pop $RegKey
${If} '$2' == ""
messageBox MB_ICONEXCLAMATION "Reg name is empty !"
Abort
${ElseIf} '$3' == ""
messageBox MB_ICONEXCLAMATION "Reg key is empty !"
Abort
${Else}
System::Alloc 9
Pop $4
;; Here you have to call some procedure to check if reg name and key are valid
;; let's say the procedure returns 1 for true and 0 for false and it stores the result in $1
${If} $1 == 0
messageBox MB_ICONEXCLAMATION "Installation denied !"
Abort
${EndIf}
${EndIf}
MessageBox MB_OK "Installation allowed !"
SetPluginUnload manual
System::Free 0
FunctionEnd

Related

Using Expect Script to read two columns from text file

I need to write a script on Expect to read a text file that contains two columns. Column one is the site name (dns) and the second is a router interface that will be used as the source-interface when I perform an FTP function from a Cisco router. Here is the content of the text file (myfile.txt):
site1 Gi0/0/0.44
site2 GigabitEthernet0/0
site3 GigabitEthernet0/0
site4 GigabitEthernet0/0/0
site5 GigabitEthernet0/0/0
Here is my code. It is only able to read the first column.
You will see a variable named "source-int", it has not been defined anywhere yet. I just put it in the script as a placeholder.
#!/usr/bin/expect
#
#
set workingdir cisco/rtr
puts stdout "Enter TACACS Username:"
gets stdin tacuserid
system stty -echo
puts stdout "Enter TACACS password:"
gets stdin tacpswd
puts stdout "\nEnter enable password:"
gets stdin enabpswd
system stty echo
#
set RTR [open "$workingdir/myfile.txt" r]
#
while {[gets $RTR dnsname] != -1} {
if {[ string range $dnsname 0 0 ] != "#"} {
send_user "The value of the router name is $dnsname\n"
set timeout 10
set count 0
log_file -a -noappend $workingdir/session_$dnsname\_$timestamp.log
send_log "### /START-SSH-SESSION/ IP: $dnsname # [exec date] ###\n"
spawn ssh -o StrictHostKeyChecking=no -l $tacuserid $dnsname
expect -ex "TACACS Password: "
send "$tacpswd\r"
expect ">"
send "enable\r"
expect "assword: "
send "$enabpswd\r"
expect "#"
send "config t\r"
expect "#"
send "no ip ftp passive\r"
expect "#"
send "ip ftp username anonymous\r"
expect "#"
send "ip ftp source-interface $souce-int\r"
expect "#"
send "ip ftp password cisco\r"
expect "#"
send "end\r"
expect "#"
send "copy ftp://10.10.10.1/out/customer/ACL.txt flash:\r"
expect "\?"
send "\r"
expect "#"
send "end\r"
expect "#"
send "exit\r"
send_log "\n"
send_log "### /END-SSH-SESSION/ IP: $dnsname # [exec date] ###\n"
log_file
sleep 5
}
}
exit
Any assistance is greatly appreciated.
Thanks!
You can use tcl's regexp command to split the line into 2 words.
if {[regexp {(\S+)\s+(\S+)} "$dnsname" dummy dns interface] == 1} {
puts "dns=$dns interface=$interface"
}
The regexp code \s matches a whitespace character, and \S a non-whitespace character. The + suffix matches 1 or more of the previous code. The () capture the wanted parts, and they are put by the command into the variables dns and interface.

Automaticalli ignore error during NSIS installer and log the error message

I have an installer written in NSIS, and in one of it's part it tries to install some fonts, which fails:
The code part looks like this:
SetOverwrite ifnewer
File ".\target\fonts\*.*"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow (TrueType)" "arialn.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Bold (TrueType)" "arialnb.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Bold Italic (TrueType)" "arialnbi.ttf"
WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" "Arial Narrow Italic (TrueType)" "arialni.ttf"
GetTempFileName $R0
File /oname=$R0 ".\target\additions\fonts.dll"
Push "arialn.ttf"
CallInstDLL $R0 registerFont
Push "arialnb.ttf"
CallInstDLL $R0 registerFont
Push "arialnbi.ttf"
CallInstDLL $R0 registerFont
Push "arialni.ttf"
CallInstDLL $R0 registerFont
SetOverwrite on
DetailPrint "Fonts Installed"
This error message is not a big problem for me, so I can always ignore it.
I am wondering, how could I automatically ignore the error message popup for these font installation parts BUT log (DetailPrint) the error message?
That dialog is controlled by SetOverwrite but there is no way to get exactly what you want out of the box.
You need to ditch the File * command and instead handle each file manually.
If you don't care if the new file is older then you can use SetOverwrite try:
!include LogicLib.nsh
!macro TryExtractWithDetailPrint file
SetOverwrite try
ClearErrors
File "${file}"
${If} ${Errors}
DetailPrint 'Could not extract "${file}", ignoring error...'
${EndIf}
SetOverwrite lastused
!macroend
Section
SetOutPath $Fonts
!insertmacro TryExtractWithDetailPrint "c:\myfonts\font1.ttf"
!insertmacro TryExtractWithDetailPrint "c:\myfonts\font2.ttf"
SectionEnd
If you want to take the date stamps into account then you need to extract the new file to a temporary location and then decide if you need to try to overwrite by comparing the new and old files:
!macro Make64 high low result
System::Int64Op "${high}" << 32
IntFmt ${result} "%#x" "${low}" ; Must reformat as hex because we don't want negative numbers to be sign extended
System::Int64Op ${result} |
Pop ${result}
!macroend
!macro CompareFilesLastWrite oldfile newfile result
Push "${newfile}"
Push "${oldfile}"
Call CompareFilesLastWrite
Pop ${result}
!macroend
Function CompareFilesLastWrite
System::Store S
Pop $1 ; oldpath
Pop $2 ; newpath
GetFileTime $2 $R2 $R1
IntOp $R1 $R1 & 0xfc000000 ; Chop off the bottom because of FAT
GetFileTime $1 $2 $1
IntOp $1 $1 & 0xfc000000 ; Chop off the bottom because of FAT
!insertmacro Make64 $2 $1 $1 ; old
!insertmacro Make64 $R2 $R1 $2 ; new
System::Call 'KERNEL32::CompareFileTime(*lr1,*lr2)i.s'
System::Store L
FunctionEnd
!macro TryExtractIfNewer src dst
InitPluginsDir
Push $0
SetDateSave on ; Must be on for this to work
File "/oname=$PluginsDir\temp.tmp" "${src}"
!insertmacro CompareFilesLastWrite "${dst}" "$PluginsDir\temp.tmp" $0
${If} $0 < 0
SetOverwrite try
ClearErrors
File "/oname=${dst}" "${src}"
${If} ${Errors}
DetailPrint 'Could not extract "${dst}", ignoring error...'
${EndIf}
SetOverwrite lastused
${Else}
DetailPrint "Existing file is newer, skipping"
${EndIf}
Pop $0
!macroend
Section
!insertmacro TryExtractIfNewer "myfiles\myfont.ttf" "$fonts\myfont.ttf"
SectionEnd

NSIS User input page

So I have a user input page using the code below and the text is being encrypted
How can I write this to a file
thae now can I read this from a file into a variable to decrypted it.
Then I want to display the decrypted message on screen in a Message box, but the \n\n needs to be converted to $\n before displaying so it displays correctly.
Example I enter in: (Note Control Enter gives you next line)
Hello World
It's a great day
When it decrypted is shows :
Hello World\n\nIt's a great day
ini File
[Settings]
NumFields=2
Title="Activation Code"
State=0
[Field 1]
Type=Text
Left=8
Right=-10
Top=12
Bottom=-15
flags=MULTILINE|VSCROLL
[Field 2]
Type=GroupBox
Left=0
Right=-1
Top=0
Bottom=-10
Text="Please enter in your Activation Code"
Code:
!include MUI.nsh
!include LogicLib.nsh
Page custom SetCustom ValidateCustom
Section Dummy
SectionEnd
Function SetCustom
ReserveFile ".\test.ini"
!insertmacro MUI_INSTALLOPTIONS_EXTRACT ".\test.ini"
!insertmacro MUI_INSTALLOPTIONS_DISPLAY ".\test.ini"
FunctionEnd
Function ValidateCustom
!insertmacro MUI_INSTALLOPTIONS_READ $R1 ".\test.ini" "Field 1" "State"
${If} $R1 == ""
Abort # Go back to page.
${Else}
Var /GLOBAL textencryt
blowfish::encrypt $R1 "1234password"
StrCpy $textencryt $8
MessageBox MB_OK "Encrypted string is:$\n $textencryt"
blowfish::decrypt $8 "1234password"
StrCpy $textencryt $8
MessageBox MB_OK "Decrypted string is:$\n $textencryt"
${EndIf}
FunctionEnd
New code: (With issues)
!insertmacro MUI_INSTALLOPTIONS_READ $R1 "test.ini" "Field 1" "State"
${If} $R1 == ""
Abort # Go back to page.
${Else}
Var /GLOBAL textencryt
blowfish::decrypt $R1 "1234password"
StrCpy $textencryt $8
MessageBox MB_OK "Decrypted string is:$\n $textencryt"
!insertmacro MUI_INSTALLOPTIONS_READ $8 "test.ini" "Field 1" "HWND"
System::Call 'USER32::SendMessage(i $8, i ${WM_GETTEXT}, i ${NSIS_MAX_STRLEN}, t.R1)'
MessageBox MB_OK $R1
The original message was
Example:
test user
code
12months
after being encrypted and I try and decrypt and looking at the results using
"MessageBox MB_OK "Decrypted string is:$\n $textencryt" returns the decrypted message with the \n\n in there. (Example: test user\n\ncode\n\12months) it should come out like:
Example:
test user
code
12months
You have two options.
You can use the INSTALLOPTIONS_READ_CONVERT helper function:
...
!insertmacro INSTALLOPTIONS_FUNCTION_READ_CONVERT
Function ValidateCustom
!insertmacro INSTALLOPTIONS_READ_CONVERT $R1 "test.ini" "Field 1" "State"
MessageBox MB_OK $R1
FunctionEnd
Or you can read the text directly from the control:
...
!include WinMessages.nsh
Function ValidateCustom
!insertmacro MUI_INSTALLOPTIONS_READ $R1 "test.ini" "Field 1" "HWND"
System::Call 'USER32::SendMessage(i $R1, i ${WM_GETTEXT}, i ${NSIS_MAX_STRLEN}, t.R1)'
MessageBox MB_OK $R1
FunctionEnd

Keep set -e setting inside || or &&

I have a simple script with a simple function which can lead to an error. Let's define this function, and make it broken:
brokenFunction () {
ls "non-existing-folder"
}
If we execute this function in a block detecting if it is broken, it works well:
brokenFunction || printf "It is broken\n"
prints "It is broken"
Now, let's make the function a bit more complex, by adding a correct command at the end :
#!/bin/sh
brokenFunction () {
ls "non-existing-folder"
printf "End of function\n"
}
brokenFunction || printf "It is broken\n"
This script prints :
$ ./script.sh
ls: cannot access 'non-existing-folder': No such file or directory
End of function
while I expected the function to stop before the printf statement, and the next block to display "It is broken".
And indeed, if I check the exit status code of brokenFunction, it is 0.
I tried adding set -e to the top of the script. The behavior is still the same, but the exit code of brokenFunction if called without || now becomes 2. If called with it, the status code is still 0.
Is there any way to keep the set -e setting inside a function called with ||?
EDIT: I just realized that the function in the example was useless. I encounter the same issue with a simple block and a condition.
#!/bin/sh
set -e
{
ls "non-existing-dir"
printf "End of block\n"
} || {
printf "It is broken\n"
}
prints
$ ./script.sh
ls: cannot access 'non-existing-dir': No such file or directory
End of block
As written in man bash, set -e is ignored in some contexts. A command before || or && is such a context.
trap looks like a possible solution here. A working alternative to the last script using trap would look like that:
#!/bin/sh
abort () {
printf "It is broken\n"
}
trap 'abort' ERR
(
set -e
false
printf "End of block\n"
)
trap - ERR
Some things have to be noticed here:
trap 'abort' ERR binds the abort function to any raised error ;
the broken block is executed in a sub-shell for 2 reasons. First is to keep the set -e setting inside the block and limit the border effects. Second is to exit this sub-shell on error (set -e effect), and not the whole script ;
trap - ERR at the end resets the trap binding, meaning the following part of the script is executed as before.
To test the border effects, we can add the previously non-working part :
#!/bin/sh
abort () {
printf "It is broken\n"
}
trap 'abort' ERR
(
set -e
false
printf "End of block\n"
)
trap - ERR
{
false
printf "End of second block\n"
} || {
printf "It is broken too\n"
}
prints:
It is broken
End of second block

using radio button followed by custom button in nsis

i have created an installer using NSIS. In that i have included 2 radio buttons. whenever user selects any of the radio buttons it immediately starts execution , but i want after selecting a radio button execution should start only after user presses a custom button say Next.
So how to add button(say Next) in my script and how can i connect my radio button selection with it ?
the partial code snippet is as follows:
Function mode_selection
nsDialogs::Create 1018
Pop $dialog
${NSD_CreateLabel} 0 10 75% 20u "Choose your preference....."
Pop $0
${NSD_CreateRadioButton} 20 60 100% 25u "Execution Mode"
Pop $hwnd
${NSD_AddStyle} $hwnd ${WS_GROUP}
${NSD_OnClick} $hwnd exec_mode
${NSD_CreateRadioButton} 20 90 100% 25u "Debug Mode "
Pop $hwnd
${NSD_OnClick} $hwnd debug_mode
nsDialogs::Show
FunctionEnd
Function exec_mode
;some code
FunctionEnd
Function debug_mode
;some code
FunctionEnd
!include nsDialogs.nsh
!include LogicLib.nsh
Page custom mode_selection
var hwndExecModeRadio
Function mode_selection
nsDialogs::Create 1018
Pop $0
${NSD_CreateLabel} 0 10 75% 20u "Choose your preference....."
Pop $0
${NSD_CreateRadioButton} 20 60 80% 25u "Execution Mode"
Pop $hwndExecModeRadio
${NSD_AddStyle} $hwndExecModeRadio ${WS_GROUP}
${NSD_CreateRadioButton} 20 90 80% 25u "Debug Mode "
Pop $0
${NSD_CreateButton} 20 150 -40 14u "Do it"
Pop $0
${NSD_OnClick} $0 perform_mode
nsDialogs::Show
FunctionEnd
Function perform_mode
${NSD_GetState} $hwndExecModeRadio $0
${If} $0 = ${BST_CHECKED}
Call exec_mode
${Else}
Call debug_mode
${EndIF}
FunctionEnd
Function exec_mode
MessageBox mb_ok "exec_mode"
FunctionEnd
Function debug_mode
MessageBox mb_ok "debug_mode"
FunctionEnd