Need to remove tasks from Scheduled Tasks from NSIS installer while uninstalling - scheduled-tasks

I have created an installer using NSIS. Now I am facing an issue like my application can create a scheduled task, but when I am uninstalling it, it is not removing/deleting tasks that I have created from my application, and they are still visible in Schedule Tasks. And I am scheduling an Autorun task every time.
How do I delete an Autorun task from Schedule Tasks when I am uninstalling it?

The best option is probably to just let your application do it; ExecWait '"$instdir\myapp.exe" /uninstalltask'
You could also execute at.exe/schtasks.exe with the nsExec plugin.
Calling the task scheduler API directly is complicated and there are two versions you need to deal with:
!include LogicLib.nsh
;V1:
!define CLSID_CTaskScheduler {148BD52A-A2AB-11CE-B11F-00AA00530503}
!define IID_ITaskScheduler {148BD527-A2AB-11CE-B11F-00AA00530503}
;V2:
!define CLSID_TaskScheduler {0F87369F-A4E5-4CFC-BD3E-73E6154572DD}
!define IID_ITaskService {2FABA4C7-4DA9-4013-9697-20CC3FD40F85}
RequestExecutionLevel Admin
!define MyTaskFolder "\"
!define MyTaskName "Test"
Section
System::Call "ole32::CoCreateInstance(g '${CLSID_TaskScheduler}', i 0, i 5, g '${IID_ITaskService}', *i.r1)i.r0"
${If} $0 = 0
!define VARIANTBYVALPARAM_EMPTY "i0xcccc0000,i0xcccccccc,i0xcccccccc,i0xcccccccc"
System::Call "$1->10(${VARIANTBYVALPARAM_EMPTY},${VARIANTBYVALPARAM_EMPTY},${VARIANTBYVALPARAM_EMPTY},${VARIANTBYVALPARAM_EMPTY})i.r0"
${If} $0 = 0
System::Call '$1->7(w "${MyTaskFolder}", *i.r2)i.r0' ; ITaskService::GetFolder
${If} $0 = 0
System::Call '$2->15(w "${MyTaskName}", i0)i.r0' ; ITaskFolder::DeleteTask
System::Call 'kernel32::FormatMessage(i 0x00001000|0x00000100|0x00000200,i0,i$0,i0,*i.r9,i0,i0)'
System::Call '*$9(&t${NSIS_MAX_STRLEN}.r3)'
System::Call 'kernel32::LocalFree(i$9)'
DetailPrint "ITaskFolder::DeleteTask HRESULT=$0 ($3)"
System::Call '$2->2()' ; ITaskFolder::Release
${EndIf}
${EndIf}
System::Call '$1->2()' ; ITaskService::Release
${EndIf}
${IfThen} $0 = 0 ${|} Goto done ${|}
System::Call "ole32::CoCreateInstance(g '${CLSID_CTaskScheduler}', i 0, i 5, g '${IID_ITaskScheduler}', *i.r1)i.r0"
${If} $0 = 0
System::Call '$1->7(w "${MyTaskName}")i.r0' ; ITaskScheduler::Delete
System::Call 'kernel32::FormatMessage(i 0x00001000|0x00000100|0x00000200,i0,i$0,i0,*i.r9,i0,i0)'
System::Call '*$9(&t${NSIS_MAX_STRLEN}.r3)'
System::Call 'kernel32::LocalFree(i$9)'
DetailPrint " ITaskScheduler::Delete HRESULT=$0 ($3)"
System::Call '$1->2()' ; ITaskScheduler::Release
${EndIf}
done:
SectionEnd

Related

How to set a hotkey to run a command line?

I want SHIFT + Numpad + to run command line:
"C:\Program Files\foo\bar.exe" -path "F:\something\dir\blah\"
As per
Documentation > Function Reference > HotKeySet() and
Documentation > Function Reference > RunWait() :
Global Const $g_sKey = '+{NUMPADADD}', _
$g_sCmd = FileGetShortName("C:\Program Files\foo\bar.exe") & ' -path "F:\something\dir\blah"'
HotKeySet($g_sKey, RunCmd)
While True
Sleep(0)
WEnd
Func RunCmd()
RunWait(#ComSpec & ' /c ' & $g_sCmd)
EndFunc

Autoit Adobe aerender

I am rendering an Adobe After Effects Project with Autoit and aerender,
I put this line of code in the console:
aerender -project C:\aeProjects\projekt_1.aep -comp "Main" -output C:\aeProjects\output\asd.avi
Now how can I check if this proccess is done, so that I can resume safely other steps.
At the moment I just put a sleep but that is not a good practice I think.
You can use the ProcessExists function to do this.
Here is a simple example with a timeout option:
MsgBox(64, "RunCmdWait", RunCmdWait("notepad.exe"))
Func RunCmdWait($sRuncmd, $iTimeout = 10000)
Local $iPid = Run(#ComSpec & " /c " & $sRuncmd, #ScriptDir, #SW_HIDE, 6)
Local $hTimer = TimerInit() ; Begin the timer and store the handle in a variable.
While 1
Sleep(250)
;Returns 0 when the process is closed
If ProcessExists($iPid) = 0 Then
SetError(0)
ExitLoop
EndIf
;Returns 1 on time out error
If TimerDiff($hTimer) >= $iTimeout Then
SetError(1)
ExitLoop
EndIf
WEnd
Return #error
EndFunc ;==>RunCmdWait
Here is a example with StdoutRead if you need to read the output:
MsgBox(64, "StdoutRead", GetStdoutRead("dir"))
Func GetStdoutRead($sRuncmd)
Local $iPid = Run(#ComSpec & " /c " & $sRuncmd, #ScriptDir, #SW_HIDE, 6)
Local $sStdoutRead = ""
While ProcessExists($iPid)
$sStdoutRead &= StdoutRead($iPid)
WEnd
Return $sStdoutRead
EndFunc ;==>GetStdoutRead

Using a for loop to access Command Prompt

I want to call a function Christian.exe to the command line to act of a series of files that are indexed as "reentrant_008.sif" (8 is an example number).
"Christian.exe reentrant_00" & num & ".sif reentrant_00" & num & ".pgm" 0 2000 is the text that needs to be fed into the command prompt for the program to execute (num is an arbitrary number)
There are approximately 400 files, so I want to create a vbs code that calls the command prompt for each file until all the files have been accessed so far this is my code:
For
Dim cmdpath
num = CStr(i)
Set wshShell = WScript.CreateObject ("WSCript.shell")
If i < 10 Then
cmdpath = "Christian.exe reentrant_00" & num & ".sif reentrant_00" & num & ".pgm" 0 2000
Else
If i < 100 Then
cmdpath = "Christian.exe reentrant_0" & num & ".sif reentrant_0" & num & ".pgm" 0 2000
Else
cmdpath = "Christian.exe reentrant_" & num & ".sif reentrant_" & num & ".pgm" 0 2000
End If
End If
wshshell.run cmdpath
Next
Problem is that a new command prompt is being called for each file, which is slowing down my computer. How do I ensure that only one command window that addresses all my files is called?
If you look at the documentation for Run you will see two option arguments [intWindowStyle], [bWaitOnReturn]. If you want your EXE to wait before proceeding on the script change your call to this
wshshell.run cmdpath, 0, True
Where 0 will hide the window and True will wait for the program to finish before proceeding in the script. Depending on your needs you could change the number or remove it.
wshshell.run cmdpath,, True
Since you tagged your question with both vbscript and powershell I'm adding a PowerShell solution:
foreach ($i in 1..400) {
$num = "{0:d3}" -f $i
& Christian.exe "reentrant_${num}.sif" "reentrant_${num}.pgm" 0 2000
}
& is the call operator. I recommend using it whenever you run external commands in PowerShell, because otherwise you'll be in for a surprise when you try to run a command from a variable for the first time:
$christian = "Christian.exe"
$christian ... # <-- throws an error, because $christian contains a
# string, which is NOT automagically interpreted
# as a command by PowerShell
& $christian ... # <-- works
-f is the formatting operator, that allows you to create formatted string output. Since your command lines only differ by the zero-padding of the input and output files it's better to build the file names with pre-padded number strings.
I recommend doing the pre-padding in VBScript as well:
For i = 1 To 400
num = Right("000" & i, 3)
cmdpath = "Christian.exe reentrant_" & num & ".sif reentrant_" & num & _
".pgm" 0 2000
wshshell.run cmdpath, 0, True
Next

How to check if $4 is registered in IRC?

I am quite an expert when it comes to programming in the MSL language, however I am unfamiliar with raw commands and whatnot.
I am in development of a new script. In this script I would like to check if $4 in what a user says is a registered nick or not but I do not know how to do this.
Thank you very much for any help and/or advice in advanced.
Best Regards,
Tim
Update:
raw 307:*:{ set $+(%,%chan,-,%CheckNick) Registered }
on *:TEXT:*:#:{
if ($1 == !regtest) {
set %chan $remove($chan,$chr(35))
set %CheckNick $4
whois $4
}
if ($($+(%,%chan,-,%CheckNick),$4),5) != $null) {
do this...
}
else {
else message...
}
}
I got this to work to check however my if statement to check if the variable has been set or not is being ignored...
Edit:
I tried using this:
checkNickReg $chan $2 $nick
...And echoing this:
echo -a Target: $1
echo -a Nick: $2
echo -a Status: $3
echo -a Chan: $3 - $chan
I'm trying to get a response to the channel such as; $nick $+ , $1 is not registered/registered/registered but not logged in.
What I've posted above is obviously wrong as it doesn't work, however I've tried a few methods and I'm actually not sure how the data is passed on with out the likes of tokenizing or setting variables...
Reply
[01:59:06] <~MrTIMarshall> !isReged mr-dynomite
[01:59:08] <&TornHQ> : mr-dynomite status is: NOTLOGGED
EDIT: mr-dynomite is not currently on, should this not = does not exist or does this check even when their not on, if so this is bloody brillant!!!
[02:00:04] <~MrTIMarshall> !isReged MrTIMarshall
[02:00:04] <&TornHQ> : MrTIMarshall status is: LOGGEDIN
$4 does not seem to work and what is the difference between 'exists, not logged in' and 'recognized, not logged in'?
Also, how does the data get passed on without setting variables or tokenizing?
(P.S. Thank you so much for the help you have dedicated so far!)
Another Edit:
I've been taking an in depth look today, am I correct in thinking if 0 or 1 the user is either not on-line or not registered (in the comments it says 0 = does not exists / not online, 1 = not logged in whereas 2 also says not logged in but recognized of which I'm unsure as what recognized means. Otherwise I'm very grateful for this script help and whatnot I'm just unclear on the numbers...
Since you have not specified any particular network I wrote an outline for some common networks around (that actually have user authentication systems). You should be able to add many other networks following the pattern.
Basically you execute /checkNickReg <target> <nick> [optional extra data] and when the server replays with the registration info (if applicable) use the on isReged signal event to handle the reply. Everything else is pretty much transparent.
EDIT: Looks like the specified network you are using (Torn) uses the standard anope services. So I updated the code to support that network.
; triggers when you get nick registration info back
; $1 = Target
; $2 = Nick
; $3 = Status, can be: LOGGEDIN, RECOGNIZED, NOTLOGGED
; $4- = Everything else passed
on *:signal:isReged:{
echo -a Target: $1
echo -a Nick: $2
echo -a Status: $3
echo -a Else: $4-
}
; reg lookup routines
alias checkNickReg {
set %reg. $+ $network 1
set %reg.target. $+ $network $1
set %reg.nick. $+ $network $2
set %reg.other. $+ $network $3-
; Freenode uses: NickServ ACC <nick>
if ($network == Freenode) msg NickServ ACC $2
; Rizon/SwiftIRC/OFTC/Torn use: NickServ STATUS <nick>
elseif ($istok(Rizon SwiftIRC OFTC Torn, $network, 32)) msg NickServ STATUS $2
}
; listen for replays
on *:notice:*:*:{
if ($($+(%, reg., $network),2)) {
;
var %target = $($+(%, reg.target., $network),2)
var %nick = $($+(%, reg.nick., $network),2)
var %other = $($+(%, reg.other., $network),2)
;
unset %reg*. $+ $network
if (($network == FreeNode) && ($2 == ACC)) $&
|| (($istok(Rizon SwiftIRC OFTC Torn, $network, 32)) && ($1 == STATUS)) {
; FreeNode:
; 0 = does not exist
; 1 = exists, not logged in
; 2 = recognized, not logged in
; 3 = logged in
; Rizon/SwiftIRC/OFTC/Torn:
; 0 = does not exists / not online
; 1 = not logged in
; 2 = recognized, not logged in
; 3 = logged in
if ($3 < 2) var %status = NOTLOGGED
elseif ($3 == 2) var %status = RECOGNIZED
else var %status = LOGGEDIN
}
;send status signal
.signal isReged %target %nick %status %other
}
}
(Extra Note: It might be useful to add an extra check to make sure $nick is AuthServ/NickServ for security reasons.)
A simple usage example is:
; Just a basic example of how to call it.
on *:text:!isReged &:#:{
checkNickReg $chan $2 $nick
}
on *:signal:isReged:{
msg $1 $4: $2 status is: $3
}
Type !isReged <nick>
Edit: The data gets passed to the on isReged event via global variables. I set them in the checkNickReg alias and I clean them up in the on notice event. So you never see them because they get cleaned up. They are passed to the isReged signal event in $1-.
On most IRCDs, it's only exposed in the WHOIS response for a user, if at all. Running a WHOIS every time a user says something is inadvisable, especially because server admins may receive a notification every time it happens.

How to show DOS output when using vbscript Exec

I have the following VBScript:
Set Shell = WScript.CreateObject("WScript.Shell")
commandLine = puttyPath & "\plink.exe -v" & " -ssh" [plus additional commands here]
Set oExec = Shell.Exec(commandLine)
This causes a DOS window to appear but the output from plink.exe is not displayed. Is there any way to get the DOS window to display this output?
Windows scripting host lacks a system() command so you have to implement your own, IMHO my helper function is superior to stealthyninja's version since it waits for process exit and not just empty stdout and it also handles stderr:
Function ExecuteWithTerminalOutput(cmd)
Set sh = WScript.CreateObject("WScript.Shell")
Set exec = sh.Exec(cmd)
Do While exec.Status = 0
WScript.Sleep 100
WScript.StdOut.Write(exec.StdOut.ReadAll())
WScript.StdErr.Write(exec.StdErr.ReadAll())
Loop
ExecuteWithTerminalOutput = exec.Status
End Function
call ExecuteWithTerminalOutput("cmd.exe /c dir %windir%\*")
Try --
Set Shell = WScript.CreateObject("WScript.Shell")
commandLine = puttyPath & "\plink.exe -v" & " -ssh" [plus additional commands here]
Set oExec = Shell.Exec(commandLine)
Set oStdOut = oExec.StdOut
While Not oStdOut.AtEndOfStream
sLine = oStdOut.ReadLine
WScript.Echo sLine
Wend
The correct way is :
Set Shell = WScript.CreateObject("WScript.Shell")
commandLine = puttyPath & "\plink.exe -v" & " -ssh" [plus additional commands here]
Set oExec = Shell.Exec(commandLine)
Set oStdOut = oExec.StdOut
While Not oStdOut.AtEndOfStream
sLine = oStdOut.ReadLine
WScript.Echo sLine
Wend
Or:
Set Shell = WScript.CreateObject("WScript.Shell")
commandLine = puttyPath & "\plink.exe -v" & " -ssh" [plus additional commands here]
Set oExec = Shell.Exec(commandLine)
WScript.Echo oExec.StdOut.ReadAll