Windows Task Scheduler Installer - c#

I have a little .exe written in c# .net that I want to run on the server every 24 hours. So naturally I would just use the Windows Task Schedular rather then doing the math myself. I have created the program, but I would like to create an installer that just set everything up. Is there a way to do this with like the Visual Studio set-up projects? If not is there like a powershell / batch script that could be used to run after installation?
Bottom Line: Automate the creation of the task.

You can use a powershell script or batch file to execute schtasks which is a command line interface to the task scheduler.
Then you simply need to run the script in order to setup the scheduled task.
There is also a managed wrapper that allows you to create schedules tasks in C#, if you would rather go that way.

I know this is an old question, but I figure this may help someone else:
You can use the following to run in cmd.exe
FOR /F %1 IN ("path to text file containing list of servers") do psexec.exe \\%1 -u
"username to execute schtasks under" -p "password" schtasks /Create /S %1
/RU "username that will run the task" /RP "password" /XML "xml file of
the task to install" /TN "name of the task"
This will loop through the list of servers in a text file (1 server per line) and use psexec to call schtasks on each server and install your task.

Related

How to Run a Batch File in a Windows Service with an API and Debug it?

I am attempting to run a batch file that utilizes the VMWare VIX API and VMRun.exe to power on/off virtual machines in VMWare Workstation. Currently my batch files work correctly when run from the command prompt. However, I can not successfully execute them from my Windows Service built in C# & .NET. I executed my batch files in my service in the following way:
string myBatchFile = ConfigurationManager.AppSettings.Get("MyBatchFile");
System.Diagnostics.ProcessStartInfo processBat = new System.Diagnostics.ProcessStartInfo(myBatchFile);
processBat.WindowStyle = ProcessWindowStyle.Normal;
processBat.ErrorDialog = true;
Process.Start(processBat);
I have been able to run a simple batch file that creates a text document from the service. The code for this batch file looks like this:
#echo off
echo Hello World>"C:\Users\MyPC\Documents\HelloWorld.txt"
This works as expected when executed by my Windows Service.
When I try to execute my VMWare batch file I am unsuccessful, and can not find any way to check log my output or debug it. My code for this batch file looks like this:
#echo off
set LOGFILE=batch.log
call :LOG > %LOGFILE%
exit /B
:LOG
cd "C:\PROGRA~2\VMware\VMWARE~2\"
vmrun.exe -T ws Start "C:\Users\MyPC\Documents\Virtual Machines\VM1\VM1.vmx"
PAUSE
I attempted to add a way for a log file to be created but nothing gets generated when I execute the batch file from the service. Any guidance would be greatly appreciated, thank you.

how to have a windows service self update?

All the solutions I can find on this topic are very old and none of them appear to answer my question...
I am trying to create a windows service that can self update (or auto update by some external trigger). In the past, I had created a windows service that was installed with InstallShield and we were able to update auto update the service in a hacky way by making the service write a batch script to the local machine and then run the batch script, which would stop the service, overwrite the service executable and other files with the new ones, and restart the service. This surprisingly worked.
However, I have updated the service to use InstallUtil.exe and this auto update script no longer works... I assume it's something to do with the way InstallShield handles the service install vs how InstallUtil does it... but I can only make guesses as I don't fully understand what each is doing to the registry.
Since I can't just overwrite the files and restart the service with the InstallUtil method, I thought I'd write a batch script that runs sc.exe to stop the service, uninstall it entirely, write the new files, install the new service files, and then start it... unfortunately, I can't seem to get sc.exe to run from a windows service automatically because it requires admin permissions... I tried to force it to self-elevate to admin using this snippet, but it doesn't appear to work as a service (it works fine if I run it from command line not as a service)
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
Does anyone know how I can cause a windows service to self update? I can look into updating to a .NET Core Worker service if there is some method of self update in .NET Core that I'm unaware of... Any ideas are much appreciated... it really shouldn't be this hard to accomplish...
For reference, here is the batch script I am currently using (ignore odd variables and such as I am dynamically replacing some of them, it works great when launched manually, just doesn't work when the service tries to run it):
#echo off
setlocal enableextensions enabledelayedexpansion
::make sure to run whole script as admin (this restarts scripts as admin if not already in admin mode)
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
pushd %networkDirectory%
::stop running service
for /F "tokens=3 delims=: " %%H in ('sc query %serviceName% ^| findstr " STATE"') do (
if /I "%%H" NEQ "STOPPED" (
net stop %serviceName%
if errorlevel 1 goto :stop
)
::delete existing service after stopping
sc delete %serviceName%
)
:: install updated service files
set "releaseDir=%networkDirectory%\Release"
set "programFilesCopyDir=%ProgramFiles%\{_companyDirectory}\%serviceName%\Release"
:: copy service Release dir to local system program files
xcopy "%releaseDir%" "%programFilesCopyDir%" /S /Y /Q
::execute the install
pushd "%programFilesCopyDir%"
CALL %serviceName%.exe --install
::start service
sc start %serviceName%
For anyone else trying to accomplish this that stumbles on this... I ended up finding a solution. I use the same script posted in my question above, but I wrote code to set up a scheduled task with Windows Task Scheduler. The scheduled task runs the above script as a one time scheduled task. This works like a charm.
I used this NuGet package to write the Task Scheduler code I needed:
https://www.nuget.org/packages/TaskScheduler/2.8.20?_src=template

Windows Task Scheduler is running my .exe multiple times

I have scheduled a Windows task using this command:
SchTasks /Create /SC MINUTE /mo 1 /TN PWSchedule /TR "C:\Program Files\Implant Sciences\B220\patches\batch\SanminaTaskSchedular.exe" /F
This is a batch file which creates a task and runs an .exe file.
The .exe file is a C# Windows Form Application which changes stuff in the database.
My problem is that I see multiple instances of Task Scheduler running in the taskbar/process. Does anyone know what is going on here?
/SC MINUTE means the task will be scheduled by every minute. If you want your task to be scheduled only once, you should use /SC ONCE.

Running multiple apps as Admin

I've need to add a function to my C# WPF application to fix up certain registry entries.
This would be done by calling regsvr32.exe /s mylib.dll. Now, this should be easy to do from what I see using the runas verb with a new Process object. (My dll does require admin rights due to some registry keys it writes to.)
But the problem is there are multiple DLLs, thus multiple invocations of regsvr32.exe, and it is not possible to put all the registrations into a single .dll. But were I to just runas multiple times, the user would get as many UAC dialogs as I start it... and I don't want that.
I want just a single dialog, and I really really want to avoid having a mystery extra fixer.exe file to have to do the launching instead. Now, I only know Windows Security stuff on a really basic level, but shouldn't it be possible to get an 'admin' token somehow (which gets me the UAC dialog) and use that to launch the different processes?
You can just use command line arguments, and shell to your own .exe running that process as an admin. When your application loads, check for those command line arguments...If they are there, register all of your dlls, then exit.
Or, you could write a batch file that registers all of the dlls, and shell to that with admin rights.
The issue here is security. You have three options:
Create a service account and run the application with service account privileges.
Prep the target machines that the application will run on with some sort of install package.
Use powershell to invoke regsvr32.exe with admin rights ->
function Run-Elevated ($scriptblock)
{
# TODO: make -NoExit a parameter
# TODO: just open PS (no -Command parameter) if $sb -eq ''
$sh = new-object -com 'Shell.Application'
$sh.ShellExecute('powershell', "-NoExit -Command $sb", '', 'runas')
}
I would opt for option 2, as registering dll's are more than an installation step. The registering of the dll crosses the boundary of the account privileges needed to run the main application. If your app is running on a domain environment an MSI could be rolled out to prep each machine?
If you want only one single UAC prompt, there is already an answer at Stackoverflow, look here.
This script elevates itself once, and you can execute a sequence of commands which all need elevated rights, so you don't get multiple UAC prompts anymore.
In your case, this means you can just append the invokations of
regsvr32.exe /s mylib1.dll
regsvr32.exe /s mylib2.dll
regsvr32.exe /s mylib3.dll
at the end of the script mentioned above, i.e.
:::::::::::::::::::::::::::::::::::::::::
:: Automatically check & get admin rights
:::::::::::::::::::::::::::::::::::::::::
#echo off
CLS
ECHO.
ECHO =============================
ECHO Running Admin shell
ECHO =============================
:checkPrivileges
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges )
:getPrivileges
if '%1'=='ELEV' (shift & goto gotPrivileges)
ECHO.
ECHO **************************************
ECHO Invoking UAC for Privilege Escalation
ECHO **************************************
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs"
ECHO UAC.ShellExecute "!batchPath!", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs"
"%temp%\OEgetPrivileges.vbs"
exit /B
:gotPrivileges
::::::::::::::::::::::::::::
:START
::::::::::::::::::::::::::::
setlocal & pushd .
REM The following code will cause Windows UAC to prompt only once
regsvr32.exe /s mylib1.dll
regsvr32.exe /s mylib2.dll
regsvr32.exe /s mylib3.dll
and the UAC dialog will only appear once.

Parameter Not Applied when Executing sqlcmd from CruiseControl.NET

OK, so here's the scenario.
CruiseControl.NET (Version : 1.5.7256.1) runs a project to rebuild a database. The CruiseControl.NET windows service is running as a windows user we created for CC.NET. There are several tasks in the project but they all run fine. However, one of the tasks that runs is a console based utility I wrote in C# that generates a batch file and then runs it via an instance of the .NET Process class.
The batch file is generated properly and the process runs fine in C#. However the batch file that runs, runs the sqlcmd command line utility for SQLServer (Version 2005 SP3). sqlcmd runs as expected, but one of the options for sqlcmd never gets applied... -I (turning quoted identifiers on).
e.g.
sqlcmd -U %1 -P %2 -S %3 -d %4 -i someScript.sql -k -b -I >> %LogFileName%
The odd thing is if I run this from a command prompt on the continuous integration server, it runs with -I being applied.
I'm very confused. I'd understand if the sqlcmd failed because the user executing the process didn't have enough privileges and I'd understand if something went wrong on the SQLServer side if the SQLServer authentication failed, but for it to work but not apply an option to sqlcmd is mystifying.
Could it be it's because -I is the last parameter? Perhaps there's a missing space there or something.. have you tried switching parameter order?
(also, why are you running a C# console app that create a batch file and the invokes it? Can't cc.net run this file itself?)

Categories

Resources