Batchfile execute only when an RDP session is active - batch-file

Background:
I have stuff running automatically on my machine that does not work properly when an RDP session is active (it's because of different screen resolutions), and also not when the local machine is locked.
However, I (and several other people) are regularly working on that machine via RDP, but we are prone to forget to close the RDP session, so I created a scheduled task that runs when the PC enters idle mode that closes the RDP session and unlocks the local machine again.
The next problem was: The batch file also runs when there is no RDP connection active.
Using the power of google I found a way of making the batchfile at least quit immediately when the user is only logged in locally.
This is what my batch currently looks like
for /f "tokens=2,4" %%a in ('QUERY USER ^| FINDSTR ">"') DO (
set "consoleTemp=%%a"
set "connectionState=%%b"
set "consoleType=!consoleTemp:~0,7!"
)
SET consoleTypeCorrect=
IF "!consoleType!"=="console" goto closebatch
#echo =================================================
#echo === Remote session is closing in ONE MINUTE ===
#echo =================================================
timeout /t 60 /nobreak
for /f "skip=1 tokens=3" %%s in ('query user %USERNAME%') do (
%windir%\System32\tscon.exe %%s /dest:console
)
Endlocal
Exit
:closebatch
Endlocal
EXIT
The settings for the scheduled task above are like this:
https://imgur.com/a/GMprqvz
Now, this creates another problem: the monitor of the pc stays on, because every time the pc goes idle, the task is run, the batch is executed, which apparently prevents the monitor to go to "sleep".
I have also tried to disable the setting "wake the computer to run this task, but it doesn't change this behavior.
so my main question is: How can I prevent the monitor to remain active when this task is run? or is there an even easier way to achieve the whole thing I want to achieve with this?

This might work...but i've not tested it. At least it may help or give you some ideas.
The section for turning the screen off was taken from this answer https://stackoverflow.com/a/60499680/3004628
#echo off
setlocal enabledelayedexpansion
:: Get local computer SESSIONS info. If find disconnected RDP session, log it off.
:: %%a:SESSIONNAME %%b:USERNAME %%c:SESSIONID %%d:SESSIONSTATE
for /f "tokens=1-4" %%a in ('QUERY session') DO (
set "sessionName=%%a"
set "sessionName=!sessionName:>=!"
if "!sessionName:~0,3!"=="rdp" do (
if /I "%%d"=="Active" do (
set "activeUsers=!activeUsers!%%b, "
) else (
echo Logging of User:%%b
logoff %%c
timeout /t 5 /NOBREAK>
)
) else (
if /I "!sessionName!"=="console" do (
set "consoleID=%%c"
)
)
)
:: If an active console user was detected send a message to their screen.
if defined consoleID (
if defined activeUsers (
msg %consoleID% /W The RDP users "!activeUsers:~0,-2!" are still active. All other RDP sessions have been closed.
) else (
msg %consoleID% /W All other RDP sessions have been closed.
)
)
:: If no active console user detected, run command to turn screen off.
if not defined consoleID (
#Start "" "%__AppDir__%WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -Command "(Add-Type '[DllImport(\"user32.dll\")]public static extern int SendMessage(int hWnd,int hMsg,int wParam,int lParam);' -Name a -Pas)::SendMessage(-1,0x0112,0xF170,2)"
)
endlocal
exit /B

Related

How to check if a page is up or if user is connected to the domain

I need some help in regards to a batch scripting. The purpose of the script is to open a web page when the user login into windows.
The web page is hosted into our local servers.
My issue is that the page still open(Obviously it does not display anything) even though the user is not connected to the network.
Unfortunately Ping is restricted. I am trying to either check if the webpage is accessible or if the user is connected to the network in order to launch the page.
Any ideas?
thanks & regards
Found below script that is doing the job.
#set #x=0 /*
:: ChkHTTP.cmd
#echo off
setlocal
set "URL=http://10.0.0.23:8090/FeedBack/index.php"
cscript /nologo /e:jscript "%~f0" %URL% | find "200" > nul
if %ErrorLevel% EQU 0 (
start "" "C:\Program Files\Internet Explorer\iexplore.exe" -k ""http://10.0.0.23:8090/FeedBack/index.php""
) else (
echo
EXIT
)
goto :EOF
JScript */
var x=new ActiveXObject("Microsoft.XMLHTTP");
x.open("GET",WSH.Arguments(0));x.send();
while (x.ReadyState!=4) {WSH.Sleep(1)};
WSH.Echo(x.status)

How to debug task scheduler on win 10?

I'm trying to exectute the following bat every 15 minutes on my pc:
#ECHO OFF
SETLOCAL enabledelayedexpansion
SET host=http://dnsad.de/rest/
SET slideshowurl=http://dnsad.de/display/currentSlideshow/mac/
SET slideshowfolder=C:\Slideshow
SET ieprocess="iexplore.exe"
SET ignore_result=INFORMATION:
FOR /f "delims=" %%a IN ('getmac /v ^|find /i "Realtek"') DO (
FOR %%b IN (%%a) DO (
SET element=%%b
IF "!element:~2,1!!element:~5,1!!element:~8,1!"=="---" set mac=%%b
)
)
SET formattedmac=%mac:-=:%
SET macpath=%mac:-=_%
FOR /f "delims=" %%a IN ('curl -X GET %host%%formattedmac%') DO (
FOR %%b IN (%%a) DO (
SET update=%%b
)
)
IF "%update%"=="[true]" (
CD %ProgramFiles%\WinHTTrack\
httrack %slideshowurl%%formattedmac% -q -O "C:\Slideshow" -s0 -B -a
curl -X PUT %host%%formattedmac%
START iexplore -k %slideshowfolder%\dnsad.de\display\currentSlideshow\mac\%macpath%.html
)
EXIT
The script works as it should when executed. Im getting the device's mac address, getting the expected server responses from curl, WinHTTrack is backing up the data correctly, curl updates the server fields and then the internet explorer gets opened with the updated,local html.
When scheduled as Task with win 7 it works as it should as well. When running the bat from Task Scheduler on Win 10 the last thing it does is the curl PUT, but the Internet Exploerer is never opened. The task is marked as succesful.
I am logged in as admin on Win 7 and Win 10. I tested pretty much every setting within the taskscheduler. Nothing seems to be working. Why doesnt the internet explorer start ?
[EDIT]
It seems that the option "Run whether user is logged on or not" causes the problem. But here is the catch:
I'm displaying slideshows in Internet Explorer Kiosk Mode and need to get updated Data from my server to Display new Slideshows regularly. The mentioned option prevents the console from popping up when executing the bat file. If i "only execute if user is logged on" i do get the updated Data to display in Internet Explorer, but every 15 minutes a console window pops up for a second.
I tried exectuing with cmd /c "update" /min "PATH TO BAT" which dosesn't solve the problem.
As mentioned in my [Edit] the problem was the option "run whether user is logged on or not", which i used to prevent the command line window to pop up. When i use the option "only execute if user is logged on" i need to "wrap" the bat in a VBScript which doesnt open the cli. So by scheduling a vbs with the following lines:
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "cmd /c PATH\TO\BAT", 0, True
i can execute the bat without a flashing cli.

Task Scheduler is not supporting option "Run with highest Privilege" and "Run weather user is logged on or not"

I am trying to schedule Task on Task Scheduler, every thing is working fine unless I tick "Run with Highest privileges" or "Run weather user is logged on or not"
As soon as I tick this, scheduler stop triggering my Script.
Script- .Bat file using Power Shell command.
Can any one figure out what went wrong?
Edited- ( Changed file location from drive to network drive)
#Echo Off
:: SDate=DAYMONTHYEAR FORMAT of Systemdate
::set SDate=%date:~7,2%%date:~4,2%%date:~10,4%
::Variable for folder path
for /D %%d in ("\\Server\Schd File\AA\*") do (
for %%a in ("%%d\*.*") do (SET "FPath=%%~dpa"
Set "FName=%%~na" )
)
For /F "Tokens=4-9 Delims=-" %%A In ("%FName%") Do (
Set "Freq=%%B"
Set "ADate=%%F%%E%%D"
)
Set "DFormat=ddMMyyyy"
IF %Freq% == Daily (
For /F UseBackQ %%A In (
`Powershell "([datetime]::ParseExact('%ADate%','%DFormat%',[System.Globalization.CultureInfo]::CurrentCulture)).AddDays(-1).ToString('ddMMyyyy')"`
) Do Set "DateF=%%A"
)
IF %Freq% == Weekly (
For /F UseBackQ %%A In (
`Powershell "([datetime]::ParseExact('%ADate%','%DFormat%', [System.Globalization.CultureInfo]::CurrentCulture)).AddDays(-7).ToString('ddMMyyyy')"`
) Do Set "DateF=%%A"
)
IF %Freq% == Monthly (
For /F UseBackQ %%A In (
`Powershell "([datetime]::ParseExact('%ADate%','%DFormat%', [System.Globalization.CultureInfo]::CurrentCulture)).AddMonths(-1).ToString('MMMyyyy')"`
) Do Set "DateF=%%A"
)
mkdir "%FPath%%Freq%\%DateF%"
move "%FPath%\%FName%.*" "%FPath%%Freq%\%DateF%\"
GoTo :EOF
There was a major overhaul of Scheduled Tasks security in Vista and later to prevent hackers from installing a scheduled task that could access network resources.
When you set the task to run whether or not a user is logged on you must set the user credentials to a user with the permissions needed to run the task. That user must also have the local policy set to allow the user to run batch files.
Additionally, when a user is not logged on, task scheduler uses “Service-for-User” (S4U) authentication which denies the user access to any network functionality. Assuming your "D:\AA*" path is a local drive this may not be a problem but if it is a mapped network drive it will be a problem.
"Run with Highest privileges" does not grant higher privileges to the specified user but runs under a completely separate security token for the system Administrator account that is created when Windows is installed.
https://technet.microsoft.com/en-us/library/cc722152(v=ws.11).aspx
https://technet.microsoft.com/en-us/library/cc732613(v=ws.10).aspx
https://technet.microsoft.com/en-us/library/ee844140(v=ws.10).aspx
https://superuser.com/questions/640962/why-cant-a-task-scheduler-job-access-a-mapped-network-drive/782836#782836
The only solution I found to run a task overnight that needs network access was to leave the machine running and the user logged on.

batch file timeout command jumping to 10k, 30k, 40k seconds

I'm currently running a set of commands that utilizes the timeout function in my batch files. The timeout function uses a variable for how many seconds it should pause, and I think that may be causing issues, but I desperately need it to function properly.
I've got an update to my question which details more about what may be happening.
I used some suggestions that I had in the comments to try and fix my script, but it did not work.
Here is my script:
:connectToTheInternet
setlocal EnableDelayedExpansion
set timeout=2
echo checking internet connection
echo.
:connectToTheInternetRestart
ping -n 1 google.com | find /i "TTL=" >NUL && (
echo Internet connection already established, checking script versions.
echo.
goto scriptVersion
REM toupd
) || (
if "%COUNTER%"=="0" (
echo Creating wifi profile.
echo.
set /A COUNTER=1
goto createWifiProfile
)
SET /A "tries = (%COUNTER%-1)+1"
REM if failed endonfail times, give up
if "%COUNTER%"=="%endonfail%" (
echo Error: Could not connect to network %tries% times, stopping script.
echo.
goto endNoShutdown
)
echo.
echo Attempt #%COUNTER%.
echo.
REM raise waiting time between connections
SET /A "modulo = (%COUNTER%-1) %% 2"
if "%modulo%" EQU "0" (
set /A timeout=timeout+2
echo failed %tries% times in a row. Increasing wait time between actions to %timeout% seconds.
set /A COUNTER=COUNTER+1
) else (
set /A COUNTER=COUNTER+1
)
REM disconnect existing network
netsh wlan disconnect
netsh wlan delete profile name="%wifissid%"
timeout /t 1 /nobreak
echo.
REM attempt connection
netsh wlan add profile filename="connect.xml"
netsh wlan connect name="%wifissid%" ssid="%wifissid%" >NUL
echo.
echo Wait time is currently !timeout! seconds.
timeout /t !timeout! /nobreak
echo.
REM check pings
ping -n 1 google.com | find /i "TTL=" >NUL && (
echo Successfully connected. Checking script version.
echo.
goto scriptVersion
) || (
set /a COUNTER2=COUNTER+1
echo Connection attempt failed. Starting attempt #%COUNTER2% in 3 seconds.
echo.
timeout /t 3 /nobreak
cls
goto connectToTheInternetRestart
)
)
My problem is specifically the timeout /t !timeout! /nobreak which should wait for a variabled amount of time. The problem is, sometimes (it only happens when the device successfully connects to the internet, but not every time the device connects to the internet) the timeout jumps up to 10,000 seconds, 30,000 seconds or some other random high number (And they really are random, I've seen some at like 12,536 seconds.) When it should always be less than 12 based on the timeout variable. Yes, I mean seconds NOT milliseconds. As you can imagine, there is a big difference between 10k seconds (roughly 21 days) vs 10 seconds.
I have no idea what could be causing this, or how to solve it and would love some help.
Here's a left-field thought, brought about by your comment
(it only happens when the device successfully connects to the internet, but not every time the device connects to the internet)
Before it connects to the internet, is the date, time and timezone correct? Connecting will synchronise the time - which may muck up your timeouts!
Like I said: left-field, but...
choice seems not to be affected by the mentioned behaviour of timeout: "when changing the time from another cmd window while running a timeout 300, the "waiting for ..." prompt indeed changes the remaining time accordingly".
So instead of timeout /t !timeout! you can use
choice /n /c yn /d y /t !timeout!
/c yn is just for making it language independent.

stopping / starting services on an remote computer with wait for the result

I am writing a batch script which should stopp services on a remote computer, copy something and then start it again.
The fact, that sc doesn't wait for the service to return a full stop / start signal doesn't satisfy me, as I fear that the service might be inconsistend or failing, and then could damage the program code / database which is depending on those services.
therefore I searched for a workaround, to have something similiar to usage of net , and come around this:
sc \\remote_server stop Service1 >> %LOGFILE%
:askservice1
for /f "tokens=4" %%a in (' sc \\remote_server query Service ^|findstr STATE') do set ServiceResult=%%a
if %ServiceResult%=STOPPED (goto nextservice2)
goto askservice1
:nextservice2
sc \\remote_service stop Service2 >> %LOGFILE%
:askservice2
for /f "tokens=4" %%a in (' sc \\remote server query Service ^|findstr STATE') do set ServiceResult2=%%a
if %ServiceResult2%=STOPPED (goto nextservice3)
goto askservice2
this goes on for 6 services, then the copy will be done, and then the run should go other way round with starting up
as you can see, this is a. really strange and looks confusing and b, it could end in an endless loop if the service won't get to the state I am comparing to...
my questions would be, how can I terminate the goto after a few tries and just let it go to the next service ?
or do you have any other code for me that helps ? I am limited to use batch or powershell but as I've never used PS before, I couldn't understand the solutions I've found.
Try this and see if it works for you. I tested it on my local machine with 2 services and it worked well. You'll have to tweak some of the ping timeout settings and take out the echo for the file copy but overall it should give you a nice starting place.
#echo off
setlocal enabledelayedexpansion
set "stopstart=stop"
set "state=STOPPED"
set "remoteserver=REMSERV"
set "LogFile=Logfile.log"
if exist %LogFile% del /q %LogFile%
:Start
for %%S in (service1 service2 service3 service4 service5 service6) do (
sc \\%remoteserver% %stopstart% %%S>>%LogFile%
Call :WaitForService %remoteserver% %%S %state% ret && (
echo Service %%S %state%
set /a svc+=1) || (
Service %%S is !state!
)
)
if "%svc%" EQU "6" (
echo copy file now.
ping -n 10 127.0.0.1>nul
set "stopstart=start"
set "state=RUNNING"
goto :Start
)
if "%svc%" EQU "12" (Echo All services are now running.)
exit /b
:WaitForService <remoteserver> <service> <stopstart> <return>
setlocal
for /L %%a in (1,10,1) do (
for /f "tokens=4" %%a in ('
sc \\%~1 query %~2^|findstr "STATE"') do (
ping -n 2 -w 10000 127.0.0.1>nul
if "%%a" EQU "%~3" set %~4=%%a & exit /b 0
)
exit /b 1
)
What it's doing is setting some variables at the start then looping through all 6 of your services sending them to a subroutine that checks the wait state given to it. In the first iteration, it's STOPPED so it checks in a loop for the service to be stopped. Once it is STOPPED, it sends an exit code and we check that exit code to make sure the service stopped. At this point, we add a +1 to a variable to keep track of each service that has stopped. Once all 6 have stopped, we copy the file in question, flip the state of the services to RUNNING and run through the routine again waiting for each of the services to start. Once all of them are started, it Echo's all services are running and ends. You can probably expand upon it more by checking additional states and running through the WaitForService routine until everything has STOPPED if you need to but in my testing, the services just stopped and started without any hiccups.

Resources