hyperlink.93
Goto Top

CMD-Fenster nach Task schließen

Hallo,

ich habe ein Skript was über einen Task bei jeder User Anmeldung läuft.
Der Task startet eine CMD (die wiederum ein PowerShell-Skript startet), welche der User am besten nicht mitkriegen soll.
Der Aufruf der CMD sieht wie folgt aus:
cmd.exe /C start /min C:\_Local\01_Skripte\ClearDownloads\ClearDownloads.cmd > C:\_Local\01_Skripte\ClearDownloads\ClearDownloads_Debug.log 2>&1
Nach dem Ausführen bleibt das CMD-Fenster in der Taskleiste offen.
In der Batch steht als letzte Zeile "exit 0", sodass eigentlich die CMD geschlossen werden müsste.
Das Skript läuft auch ohne Fehler.

Der Task kann leider nur ausgeführt werden, wenn der User angemeldet ist (die Option "Unabhängig von der Benutzeranmeldung ausführen" ist nicht möglich).

Hat jemand eine Idee wie man das lösen?

Content-ID: 395927

Url: https://administrator.de/forum/cmd-fenster-nach-task-schliessen-395927.html

Ausgedruckt am: 26.12.2024 um 09:12 Uhr

Stefan007
Stefan007 17.12.2018 um 07:33:56 Uhr
Goto Top
wo ist denn der Pfad zur PS Datei?
sabines
sabines 17.12.2018 aktualisiert um 07:38:00 Uhr
Goto Top
Moin,

was genau macht das Skript und was spricht dagegen es als Benutzer Anmelde Skript per GPO laufen zu lassen.
Oder den Task per GPO erstellen etc?
Wie rufst Du das PS auf?

Gruss
Xerebus
Xerebus 17.12.2018 um 08:24:30 Uhr
Goto Top
Das exit bezieht sich sicher auf die ClearDownloads.cmd, das wird ja geschlossen.
Also einfach noch ein exit an die bat...


cmd.exe /C start /min C:\_Local\01_Skripte\ClearDownloads\ClearDownloads.cmd > C:\_Local\01_Skripte\ClearDownloads\ClearDownloads_Debug.log 2>&1
exit
Hyperlink.93
Hyperlink.93 17.12.2018 aktualisiert um 08:53:22 Uhr
Goto Top
wo ist denn der Pfad zur PS Datei?
  • Die PS Datei liegt im selben Verzeichnis. Siehe auch meine Antwort auf die Frage(n) von Sabines.
Hyperlink.93
Hyperlink.93 17.12.2018 aktualisiert um 08:55:02 Uhr
Goto Top
was genau macht das Skript und was spricht dagegen es als Benutzer Anmelde Skript per GPO laufen zu lassen.
Oder den Task per GPO erstellen etc?

  • Das Skript räumt den Downloads Ordner bei den Usern auf, sodass der nicht voll gemüllt wird. Ich möchte aber nicht den Usern das Recht "als Job" anmelden geben. Daher geht auch das mit der GPO nicht.

Wie rufst Du das PS auf?

  • Der PS Aufruf ist wie folgt aufgebaut:
set RunScriptName=Clear_Downloads_Dir
set RunScriptType=ps1
::set RunScriptParameter=
[...]
powershell.exe %RunScriptFullPath% %RunScriptParameter%
[...]
Hyperlink.93
Hyperlink.93 17.12.2018 aktualisiert um 08:55:49 Uhr
Goto Top
Das exit bezieht sich sicher auf die ClearDownloads.cmd, das wird ja geschlossen.
Also einfach noch ein exit an die bat...

cmd.exe /C start /min C:\_Local\01_Skripte\ClearDownloads\ClearDownloads.cmd > C:\_Local\01_Skripte\ClearDownloads\ClearDownloads_Debug.log 2>&1
exit

  • Hab ich gerade getestet, bleibt aber dabei, dass das Fenster minimiert geöffnet bleibt face-sad
Xerebus
Xerebus 17.12.2018 um 10:04:40 Uhr
Goto Top
In die ClearDownloads.cmd ans ende auch ein exit.
137846
137846 17.12.2018 aktualisiert um 11:06:27 Uhr
Goto Top
Zitat von @Hyperlink.93:

Das exit bezieht sich sicher auf die ClearDownloads.cmd, das wird ja geschlossen.
Also einfach noch ein exit an die bat...

cmd.exe /C start /min C:\_Local\01_Skripte\ClearDownloads\ClearDownloads.cmd > C:\_Local\01_Skripte\ClearDownloads\ClearDownloads_Debug.log 2>&1
exit

  • Hab ich gerade getestet, bleibt aber dabei, dass das Fenster minimiert geöffnet bleibt face-sad
Da fehlen Anführungszeichen nach dem Start für den Titel, les dir mal die Doku dazu durch!
https://ss64.com/nt/start.html
cmd.exe /C start "" /min ........  
Dann ist dort auch ein Exit überflüssig denn das sagt der Parameter /c ja schon aus. Im File selbst nat. ein Exit.

Wenn du das komplett unsichtbar machen willst, entweder GPO oder via VBS und Run Methode Hidden starten.

Wozu aber extra noch ein extra CMD Skript wenn du sowieso Powershell startest??? Starte doch gleich das PS Skript aus der Aufgabenplanung, damit kannst du alles abfackeln!

Gruß A.
Hyperlink.93
Hyperlink.93 17.12.2018 um 15:09:44 Uhr
Goto Top
Zitat von @137846:

Da fehlen Anführungszeichen nach dem Start für den Titel, les dir mal die Doku dazu durch!
https://ss64.com/nt/start.html
> cmd.exe /C start "" /min ........  
Dann ist dort auch ein Exit überflüssig denn das sagt der Parameter /c ja schon aus. Im File selbst nat. ein Exit.

Wenn du das komplett unsichtbar machen willst, entweder GPO oder via VBS und Run Methode Hidden starten.

Wozu aber extra noch ein extra CMD Skript wenn du sowieso Powershell startest??? Starte doch gleich das PS Skript aus der Aufgabenplanung, damit kannst du alles abfackeln!

Gruß A.

Leider klappt das auch nicht *seufz*...
Die Batch nutze ich um Fehler der PowerShell in das Debug.log zu schreiben, wenn ich die PowerShell direkt starte sehen ich die Fehlermeldungen nicht. Vor allem die Fehlermeldungen wenn die PowerShell aufgrund der Executionpolicy o.ä. gar nicht erst startet face-smile
137846
137846 17.12.2018 aktualisiert um 15:23:35 Uhr
Goto Top
Zitat von @Hyperlink.93:
Die Batch nutze ich um Fehler der PowerShell in das Debug.log zu schreiben, wenn ich die PowerShell direkt starte sehen ich die Fehlermeldungen nicht. Vor allem die Fehlermeldungen wenn die PowerShell aufgrund der Executionpolicy o.ä. gar nicht erst startet face-smile
Sorry aber das ist ebenfalls Blödsinn!
Außerdem gibt es -Executionpolicy ByPass
Hyperlink.93
Hyperlink.93 17.12.2018 um 15:31:27 Uhr
Goto Top
Zitat von @137846:

Sorry aber das ist ebenfalls Blödsinn!
Außerdem gibt es -Executionpolicy ByPass

Das ist korrekt aber für sämtliche Fälle eine Exception schreiben die dann den Status quasi abfragt und die Error Message in ein Log schreibt welches ich auswerten kann pro User bzw. pro passende Aktion ist einfach ätzend. Da ist der Fall mit dem CMD-Stderr einfacher... aber egal, darum geht es ja nicht, jeder hat seine Wege die er nutzt.
Mein Problem ist einfach, dass das CMD-Fenster nicht geschlossen wird.
137846
137846 17.12.2018 aktualisiert um 16:49:35 Uhr
Goto Top
Tja keiner kennt den Inhalt deiner Skripte. Hier geht das einwandfrei:

c:\Test.cmd
@echo off
echo BlaBlaBla
powershell -Executionpolicy ByPass -NoProfile -Command "write-host 'Das ist ein Test'; sleep 2"  
exit
Dann im Taskplaner:

screenshot

Fertig. Fenster schließt sich von selbst wie zu erwarten war.

Aber wie gesagt würde ich das gleich per VBS und Run-Methode gleich unsichtbar starten.
Set objShell = CreateObject("Wscript.Shell")  
objShell.Run "cmd /c C:\script.cmd",0,False  
oder direkt im Taskplaner mit Parameter -WindowStyle Hidden starten.

Du hast viele Möglichkeiten wie du siehst die alle funktionieren wenn man sie denn korrekt anwendet.

That's it.
Ciao.
Hyperlink.93
Hyperlink.93 18.12.2018 um 07:34:50 Uhr
Goto Top
Danke schon mal für die Hilfe, mir ist/war nicht bewusst wie wichtig dir/euch der Code ist, da ich denke das an dem nichts falsch ist.
Es läuft ja, nur bleibt das CMD-Fenster nach dem es fertig ist noch in der Taskleiste geöffnet. Ich dachte und tippe immer noch darauf das es nur ein Fehler im Aufruf sein könnte... aber mal sehen, vielleicht entdeckst du/ihr doch noch was...

Archiv-Ordner Prüfung:
if(!(Test-Path "$strArchivDir"))  
{
    WriteLog "error" $strLogFilePath "Archiv directory is not available" $bolOutputDisplay $true $ColorError  
    MakeDir "$strArchivDir"  

    if(!(Test-Path "$strArchivDir"))  
    {
        WriteLog "error" $strLogFilePath "Archiv directory can not created." $bolOutputDisplay $true $ColorError  
    }

    WriteLog "info" $strLogFilePath "Archiv directory is created." $bolOutputDisplay $true $ColorHighlight  
}

Prüfung auf Duplikate:
WriteLog "info" $strLogFilePath "Checking duplicated files"  

foreach($strFile in Get-ChildItem $strDownloadsDir | Where-Object {$_.Name -ne "_Archiv"})  
{
    if($strFile -match "\([0-9]\)")  
    {
    WriteLog "Info" $strLogFilePath "Duplicate found, filename: $strFile"  
    Remove-Item "$strDownloadsDir\$strFile" -Recurse -Force  
    $intCounter++
    }
    
    ### ONLY FOR WCP FILES ###
    if($strFile -like "start.ica")  
    {
    WriteLog "Info" $strLogFilePath "start.ica was found. It will deleted now."  
    Remove-Item "$strDownloadsDir\$strFile" -Recurse -Force  
    $intCounter++
    }
}
if($intCounter -eq 0)
{
    WriteLog "Info" $strLogFilePath "No file was deleted."  
}
else{
    WriteLog "Info" $strLogFilePath "$intCounter files are delted"  
}

WriteLog "" $strLogFilePath ""  

Prüfung des Alters der Datei:
WriteLog "info" $strLogFilePath "Checking if last access time for a file is older than 7 days"  

$intCounter=0

foreach($strfile in Get-ChildItem $strDownloadsDir | Where-Object {$_.Name -ne "_Archiv"})  
{
    If($strfile.LastAccessTime -lt ((Get-Date).AddDays(-7))){
        WriteLog "Info" $strLogFilePath "File: ""$strfile"" is older than 7 days"  
        foreach($strfileArchiv in Get-ChildItem $strArchivDir)
        {
            if($strfile.Name -eq $strfileArchiv.Name)
            {
                WriteLog "Info" $strLogFilePath "File: '$strfile' existing in the archiv folder."  
                Remove-Item $strArchivDir\$strfileArchiv
                WriteLog "Info" $strLogFilePath "File '$strfileArchiv' was removed."  
            }
        }
        Move-Item "$strDownloadsDir\$strfile" -Destination "$strArchivDir"  
        WriteLog "Info" $strLogFilePath "File: '$strfile' is moved to archiv"  
        $intCounter++
    } 
}
if($intCounter -eq 0)
{
    WriteLog "Info" $strLogFilePath "No file was older than 7 days, no files are moved."  
}
else{
    WriteLog "Info" $strLogFilePath "$intCounter files are moved to archiv"  
}

WriteLog "" $strLogFilePath ""  

Prüfung des Alters der archivierten Dateien:
WriteLog "Info" $strLogFilePath "Checking if files in archiv older than 1 month"  

$intCounter=0
foreach($strfile in Get-ChildItem $strArchivDir| Where-Object {$_.Name -notmatch "[0-9]{4}_[0-9]{2}_Archiv"})  
{
    If($strfile.LastAccessTime -lt ((Get-Date).AddMonths(-1))){
        WriteLog "Info" $strLogFilePath "File: '$strfile' is older than 1 month"  
        Compress-Archive "$strArchivDir\$strfile" -CompressionLevel Optimal -DestinationPath "$strArchivDir\$(Get-Date -Format yyyy_MM)_Archiv.zip" -Update  
        WriteLog "Info" $strLogFilePath "File: '$strfile' is moved to $(Get-Date -Format yyyy_MM)_Archiv.zip"  
        Remove-Item "$strArchivDir\$strfile" -Recurse -Force  
        WriteLog "Info" $strLogFilePath "File: ""$STR_dirArchiv\$strfile"" was removed."  
        $intCounter++
    }
}
if($intCounter -eq 0)
{
    WriteLog "Info" $strLogFilePath "No file was older than 1 month, no files are compressed."  
}
else{
    WriteLog "Info" $strLogFilePath "$intCounter files are compressed."  
}

WriteLog "" $strLogFilePath ""  

Reminder Message Box wenn Dateien älter 3 Monate sind:
WriteLog "Info" $strLogFilePath "Checking if the last archiv is older than 3 month"  

foreach($strArchiv in Get-ChildItem $strArchivDir | Where-Object {$_.Name -match "[0-9]{4}_[0-9]{2}_Archiv" -and $_.LastAccessTime -lt ((Get-Date).AddMonths(-3))}){  
    WriteLog "Info" $strLogFilePath "$strArchiv older than 3 Month."  
    $strMsgBox=[System.Windows.Forms.MessageBox]::Show(„Please check the Archiv ""$strArchiv"" in the directory ""$strArchivDir"", its older than 3 Month!“,“Check Archiv!“,4,[System.Windows.Forms.MessageBoxIcon]::Exclamation)  
    if($strMsgBox -eq "yes")  
    {
    WriteLog "Info" $strLogFilePath "User choose 'yes', archiv will be open."  
    Invoke-Item "$strArchivDir\$strArchiv"  
    }
    else
    {
    WriteLog "Info" $strLogFilePath "User choose 'no'"  
    }
    $intCounter++
}
if($intCounter -eq 0)
{
    WriteLog "Info" $strLogFilePath "No archiv was older than 3 month."  
}

End-Meldung des Skriptes (danach kommt keine einzige Zeile mehr):
WriteLog "info" $strLogFilePath "==================================================================" $bolOutputDisplay $true $ColorHighlight  
WriteLog "info" $strLogFilePath ("ENDE: " + $strScriptName + " - Abschluss am " + (GetDateTimeString)) $bolOutputDisplay $true $ColorHighlight  
WriteLog "info" $strLogFilePath "==================================================================" $bolOutputDisplay $true $ColorHighlight  


Funktion WriteLog:
function WriteLog($strMessageType="info",$strPath,$strText,$bolOutputDisplay=$true,$bolAppend=$true,$strForeColor=$null)  
{
    $bolOutputFile = (-not($strPath -eq ""))  
	
    $conStrMessageError          = "ERROR    : "  
    $conStrMessageCriticalError  = "CRITICAL : "  
    $conStrMessageWarning        = "WARNING  : "  
    $conStrMessageInfo           = "INFO     : "  
    $conStrMessageOK             = "OK       : "  
    $conStrMessageCheck          = "CHECK    : "  
    $conStrMessageOffline        = "OFFLINE  : "  
    $conStrMessageFound          = "FOUND    : "  
    $conStrMessageNotFound       = "NOTFOUND : "  
    $conStrMessageDebug          = "DEBUG    : "  

	switch($strMessageType.trim().tolower())
	{
        "error"   
        { 
	        $strPrefix = $conStrMessageError
	    }
	    "critical"   
	    { 
            $strPrefix = $conStrMessageCriticalError
	    }
		"warning"   
        { 
	        $strPrefix = $conStrMessageWarning
        }
        "info"   
        { 
            $strPrefix = $conStrMessageInfo
        }
        "ok"   
        { 
            $strPrefix = $conStrMessageOK
        }
        "check"   
        { 
            $strPrefix = $conStrMessageCheck
        }
        "debug"   
        { 
            $strPrefix = $conStrMessageDebug
        }
        "offline"   
        { 
            $strPrefix = $conStrMessageOffline
        }
        "found"   
        { 
            $strPrefix = $conStrMessageFound
        }
        "notfound"   
        { 
            $strPrefix = $conStrMessageNotFound
        }
        ""  
        { 
            $strPrefix = ""  
        }
            "empty"  
        { 
            $strPrefix = ""  
        }
            "newline"   
        { 
            $strPrefix = ""  
        }
        default 
        { 
            write-host ("Ungültiger Meldungstyp '" + $strMessageType + "'")  
        }

    }

	if ($strPrefix -eq "")  
	{
		$strMessage = $strText
	}
	else
	{
		$strDatum = ("{0:dd.MM.yyyy HH:mm:ss}" -f (Get-Date))  
		$strMessage = $strDatum + " " + $strPrefix + $strText  
	}
	
	if ($bolOutputDisplay)
    {
        if ($strForeColor -eq $null)
        {
            Write-Host $strMessage
        }
        else
        {
            Write-Host $strMessage -foregroundcolor $strForeColor
        }
    }

    if ($bolOutputFile) 
	{
        if ($bolAppend)
        {
            $strMessage | Out-File -append -filepath $strPath
        }
        else
        {
            $strMessage | Out-File -filepath $strPath
        }
    }
}

Funktion GetDateTimeString:
function GetDateTimeString
{
	return ("{0:dd.MM.yyyy HH:mm:ss}" -f (Get-Date))  
}

Die Batch sieht wie folgt aus:
::------------------------------------------------------------------------------
::Initialization
::------------------------------------------------------------------------------
set RunScriptName=Clear_Downloads_Dir
set RunScriptType=ps1
::set RunScriptParameter=
:: Beispiel für Parameterangabe >> Set RunScriptParameter=$true 'Hello World' 
:: Die Reihenfolge im aufrufenden Skript der Parameter muss beachtet werden!

::------------------------------------------------------------------------------
::Fixe Variablen
::------------------------------------------------------------------------------
set Server=%Computername%
set WorkPath=%~d0%~p0

set RunScript=%RunScriptName%.%RunScriptType%
set RunScriptFullPath=%WorkPath%%RunScript%

set CallScriptName=%~n0
set CallScriptFullName=%~n0%~x0
set CallScriptFullPath=%0

set LogFileName=%CallScriptName%.log
set LogFilePath=%WorkPath%%LogFileName%

::------------------------------------------------------------------------------
::Get system date
::------------------------------------------------------------------------------
::english DaTime
  if "%DATE:~6,1%" EQU "/" (set File_Date=%DATE:~12,2%%DATE:~4,2%%DATE:~7,2%_) && (set DateTime=%date:~7,2%.%date:~4,2%.%date:~10% %time:~0,2%:%time:~3,2%:%time:~6,2%) && (echo Language english)  
::german DaTime
  if "%DATE:~2,1%" EQU "." (set File_Date=%DATE:~6%%DATE:~3,2%%DATE:~0,2%_) && (set DateTime=%date% %time:~0,2%:%time:~3,2%:%time:~6,2%) && (echo Language german)  
:: change blank to 0
  if "%DateTime:~11,1%" EQU " " set DateTime=%DateTime:~0,11%0%DateTime:~12%  

::------------------------------------------------------------------------------
::delete last logfile
::------------------------------------------------------------------------------
if exist %LogFilePath% del %LogFilePath%

::------------------------------------------------------------------------------
::Debug-Message
::------------------------------------------------------------------------------
call :Xecho "DEBUG-Info - Variable 'DaTime': %DaTime%"  
call :Xecho
call :Xecho "%Date% - %TIME:~0,5% : script ##%RunScriptName%## started"  

::------------------------------------------------------------------------------
::Script call
::------------------------------------------------------------------------------
call :Xecho "powershell.exe %RunScriptFullPath% %RunScriptParameter%"  
powershell.exe %RunScriptFullPath% %RunScriptParameter%

if %errorlevel% EQU 0 call :Xecho "Powershell command was successfull"  
if %errorlevel% NEQ 0 call :Xecho "Powershell command NOT was successfull!"  

call :Xecho
call :Xecho "-------------------------------------------------------------------------------"  
call :Xecho "Abschlussarbeiten"  
call :Xecho "-------------------------------------------------------------------------------"  
call :Xecho "%Date% - %TIME:~0,5% : script ##%RunScriptName%## finished"  
call :Xecho

goto :EOF

::------------------------------------------------------------------------------
::Xecho (Für Ausgabe am Bildschirm und in Logfile)
::------------------------------------------------------------------------------
:Xecho
::@echo _______Xecho
if LEER%1 EQU LEER goto Leerzeile
set str=%1
set str=%str:"=%  
@echo %str%
if exist %LogFilePath% @echo %str% >>%LogFilePath%
if not exist %LogFilePath% @echo %str% >%LogFilePath%
goto :EOF

:Leerzeile
echo.
echo.>>%LogFilePath%
goto :EOF
:Xecho_end

exit 0

Der Aufruf im Task Scheduler sieht wie folgt aus:
tasksched

Da nicht die komplette Zeile zusehen ist hier nochmal in Text-Form:
Programm/Skript: cmd.exe
Argumente: /C start "" /min C:\_Local\01_Skripte\ClearDownloads\ClearDownloads.bat > C:\_Local\01_Skripte\ClearDownloads\ClearDownloads_Debug.log 2>&1  
Starten in: C:\_Local\01_Skripte\ClearDownloads\

Die VBS Methode würde ja bedeuten (wenn ich es richtig verstanden habe), dass ich quasi noch ein drittes "Skript" brauche, korrekt?
Das würde ich gerne vermeiden.. und die PowerShell direkt starten hat halt wie gesagt gewisse Nachteile, wenn es um Fehlerbehandlungen geht.
In dem Skript wird es vielleicht nicht unbedingt notwendig sein, es gibt aber sicherlich auch Skripte die ggf. Fehler aufwerfen die man nicht sofort sieht oder beim Testen mitkriegt, welche dann durch den Aufruf über die CMD und dem Stderr ins Log analysiert und behoben werden können.
137846
Lösung 137846 18.12.2018 aktualisiert um 08:15:44 Uhr
Goto Top
goto :EOF
Das ist dein Problem in Zeile 64. Damit überspringt du nämlich das Exit 0 am Ende der Batch und deshalb bleibt das Fenster auch offen face-wink. Und genau deshalb wollte ich den Code sehen.
Also mach dir vor die letzte Zeile mit dem Exit noch eine Sprungmarke und springe diese an oder platziere das Exit an der Stelle
Hyperlink.93
Hyperlink.93 18.12.2018 um 08:24:55 Uhr
Goto Top
Ah okay... das hatte ich extra hinzugefügt am Ende weil ich mir dachte das es fehlt!
Jedoch nicht bedacht das goto :EOF das dann natürlich überspringt.

Danke :D
137846
137846 18.12.2018 aktualisiert um 09:19:46 Uhr
Goto Top
Keine Ursache. Frohe Festtage.