martedì 15 maggio 2018

START SCHEDULED TASK (ALMOST) HIDDEN

I was working o a server with a lot of applications and script continuously run from task scheduler and interacting with the desktop with their windows and console windows.
The server admin want them to be visible for checking reason.

But this way it was very annoying to work on that server because continuously interrupted by application or script started that took the focus and stay ahead of my job.

The best (not perfect) way I found to mitigate this is to use powershell to run the applications or script minimized and without taking focus.

In addition, as powershell itself open his console I had to find a workaround for this

Here my solution:

- create personal powershell module with function Start-ProcessNoFocus
- create folder c:\psmodules for my personal powershell modules
- changed environment variable to add c:\psmodules
- put my powershell module in c:\psmodules
- created scheduled task that run simply "powershell"
- run the scheduled task , a powershell window appeared, in properties, layout, window position I set the Y position of the window to be 800, on my monitor this moved the windows near out of the botton margin of the screen
- closed powershell window
- changed task scheduler to run my application like this:

program:              powershell
add argument:      -windowstyle hidden Start-ProcessNoFocus c:\test\MyApplication.exe

The result is :
- a powershell window appears and disappears very quickly
- it starts the process "MyApplication.exe" minimized and without taking focus

it's not perfect but now I'm able to work on the server without being continuously interrupted by all those annoying scheduled tasks.


This it the Start-ProcessNoFocus function that I put in a Start-ProcessNoFocus module :

(credits: # http://www.daveamenta.com/2013-08/powershell-start-process-without-taking-focus/)

function Start-ProcessNoFocus($FilePath, $Arguments) {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
 
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION {
    public IntPtr hProcess;
    public IntPtr hThread;
    public uint dwProcessId;
    public uint dwThreadId;
}
 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO {
    public uint cb;
    public string lpReserved;
    public string lpDesktop;
    public string lpTitle;
    public uint dwX;
    public uint dwY;
    public uint dwXSize;
    public uint dwYSize;
    public uint dwXCountChars;
    public uint dwYCountChars;
    public uint dwFillAttribute;
    public STARTF dwFlags;
    public ShowWindow wShowWindow;
    public short cbReserved2;
    public IntPtr lpReserved2;
    public IntPtr hStdInput;
    public IntPtr hStdOutput;
    public IntPtr hStdError;
}
 
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES {
    public int length;
    public IntPtr lpSecurityDescriptor;
    public bool bInheritHandle;
}
 
[Flags]
public enum CreationFlags : int {
    NONE = 0,
    DEBUG_PROCESS = 0x00000001,
    DEBUG_ONLY_THIS_PROCESS = 0x00000002,
    CREATE_SUSPENDED = 0x00000004,
    DETACHED_PROCESS = 0x00000008,
    CREATE_NEW_CONSOLE = 0x00000010,
    CREATE_NEW_PROCESS_GROUP = 0x00000200,
    CREATE_UNICODE_ENVIRONMENT = 0x00000400,
    CREATE_SEPARATE_WOW_VDM = 0x00000800,
    CREATE_SHARED_WOW_VDM = 0x00001000,
    CREATE_PROTECTED_PROCESS = 0x00040000,
    EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
    CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
    CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
    CREATE_DEFAULT_ERROR_MODE = 0x04000000,
    CREATE_NO_WINDOW = 0x08000000,
}
 
[Flags]
public enum STARTF : uint {
    STARTF_USESHOWWINDOW = 0x00000001,
    STARTF_USESIZE = 0x00000002,
    STARTF_USEPOSITION = 0x00000004,
    STARTF_USECOUNTCHARS = 0x00000008,
    STARTF_USEFILLATTRIBUTE = 0x00000010,
    STARTF_RUNFULLSCREEN = 0x00000020,  // ignored for non-x86 platforms
    STARTF_FORCEONFEEDBACK = 0x00000040,
    STARTF_FORCEOFFFEEDBACK = 0x00000080,
    STARTF_USESTDHANDLES = 0x00000100,
}
 
public enum ShowWindow : short {
    SW_HIDE = 0,
    SW_SHOWNORMAL = 1,
    SW_NORMAL = 1,
    SW_SHOWMINIMIZED = 2,
    SW_SHOWMAXIMIZED = 3,
    SW_MAXIMIZE = 3,
    SW_SHOWNOACTIVATE = 4,
    SW_SHOW = 5,
    SW_MINIMIZE = 6,
    SW_SHOWMINNOACTIVE = 7,
    SW_SHOWNA = 8,
    SW_RESTORE = 9,
    SW_SHOWDEFAULT = 10,
    SW_FORCEMINIMIZE = 11,
    SW_MAX = 11
}
 
public static class Kernel32 {
    [DllImport("kernel32.dll", SetLastError=true)]
    public static extern bool CreateProcess(
        string lpApplicationName, 
        string lpCommandLine, 
        ref SECURITY_ATTRIBUTES lpProcessAttributes, 
        ref SECURITY_ATTRIBUTES lpThreadAttributes,
        bool bInheritHandles, 
        CreationFlags dwCreationFlags, 
        IntPtr lpEnvironment,
        string lpCurrentDirectory, 
        ref STARTUPINFO lpStartupInfo, 
        out PROCESS_INFORMATION lpProcessInformation);
}
"@
 
    $si = New-Object STARTUPINFO
    $pi = New-Object PROCESS_INFORMATION
 
    $si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
#    $si.wShowWindow = [ShowWindow]::SW_SHOWNOACTIVATE

# mia versione 4+2 ovvero non prendere il focus e starta in minimized
    $si.wShowWindow = 6
    $si.dwFlags = [STARTF]::STARTF_USESHOWWINDOW
 
    $pSec = New-Object SECURITY_ATTRIBUTES
    $tSec = New-Object SECURITY_ATTRIBUTES
    $pSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($pSec)
    $tSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($tSec)
 
    [Kernel32]::CreateProcess($FilePath, $Arguments, [ref] $pSec, [ref] $tSec, $false, [CreationFlags]::CREATE_NEW_CONSOLE, [IntPtr]::Zero, (pwd | select -exp Path), [ref] $si, [ref] $pi)
 
    #[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
}





Nessun commento:

Posta un commento