Regular access to an interactive process (WatiN tests) using the task scheduler

I use the WatiN test suite that drives IE to periodically check the health for site monitoring purposes.

The suite works great when I call it interactively and / or when I set the task in the Task Scheduler to Run only when user logs on.

However, when I set it to "Run whether user was enabled or not" and check the "Run with highest privileges" checkbox (WatiN cannot talk satisfactorily with the browser under Windows Server 2008 and many other OS without administrator rights), WatiN does not can satisfactorily communicate with it instances of iexplore.exe (they start, but I get a timeout exception as detailed in this post). I have added a site that I am on Trusted Sites for both admin and non-admin IE contexts. I've tried with and without elevation, with and without ESC disabled, with and with and without Internet Zone Protected Mode disabled. Since my non-GUI tests are happy, I guess this is a limitation of the type of interactivity that is possible in the context of a non-interactive scheduled task, even when "Run with highest privileges".

Currently, my workaround requires that the [TS] session remains open at all times, ready for the scheduled task.

If I insisted on this, I would, at a minimum, add a heart rate notification to allow something to control what the task actually starts [for example if someone logs a session or reloads a field].

However, I'm looking for something more persistent - something that can regularly reference my WatiN tests [run using xunit-console.x86.exe v 1.5] on my Windows Server 2008 [x64] box, as well like Task Scheduler but with a proper interactive session.

I'd rather not use psexec or remcom if possible, and can't see how creating a windows service would do anything other than add another error, but I'd be interested to know about all the tested solutions out there.

+2


source to share


3 answers


I was able to run the Watin tests using a scheduled task in Run whether user is logged on or not. In my case, I tracked down the issue until m_Proc.MainWindowHandle is always 0 when IE is created from a scheduled task running without login. In the Watin sources this is in the IE.cs function: CreateIEPartiallyInitializedInNewProcess

My workaround is to manually enumerate top-level windows and find the window with className == "IEFrame" that belongs to the process, instead of using the Process.MainWindowHandle property.

Here is a code snippet. All pinvoke I copied directly from the Watin source.



   public static class IEBrowserHelper
    {
        private static Process CreateIExploreInNewProcess()
        {
            var arguments = "about:blank";

            arguments = "-noframemerging " + arguments;

            var m_Proc = Process.Start("IExplore.exe", arguments);
            if (m_Proc == null) throw new WatiN.Core.Exceptions.WatiNException("Could not start IExplore.exe process");

            return m_Proc;
        }
        class IeWindowFinder
        {
            #region Interop
            [DllImport("user32.dll", SetLastError = true)]
            static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
            public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
            [DllImport("user32.dll", SetLastError = true)]
            public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
            [DllImport("user32", EntryPoint = "GetClassNameA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
            internal static extern int GetClassName(IntPtr handleToWindow, StringBuilder className, int maxClassNameLength);
            #endregion

            readonly Process IeProcess;
            IntPtr HWnd = IntPtr.Zero;

            public IeWindowFinder(Process ieProcess)
            {
                this.IeProcess = ieProcess;
            }
            public IntPtr Find()
            {
                EnumWindows(FindIeWindowCallback, IntPtr.Zero);
                return HWnd;
            }

            bool FindIeWindowCallback(IntPtr hWnd, IntPtr lParam)
            {
                uint processId;
                GetWindowThreadProcessId(hWnd, out processId);
                if (processId == IeProcess.Id)
                {
                    int maxCapacity = 255;
                    var sbClassName = new StringBuilder(maxCapacity);
                    var lRes = GetClassName(hWnd, sbClassName, maxCapacity);
                    string className = lRes == 0 ? String.Empty : sbClassName.ToString();
                    if (className == "IEFrame")
                    {
                        this.HWnd = hWnd;
                        return false;
                    }
                }
                return true;
            }
        }

        public static WatiN.Core.IE CreateIEBrowser()
        {
            Process ieProcess = CreateIExploreInNewProcess();

            IeWindowFinder findWindow = new IeWindowFinder(ieProcess);

            var action = new WatiN.Core.UtilityClasses.TryFuncUntilTimeOut(TimeSpan.FromSeconds(WatiN.Core.Settings.AttachToBrowserTimeOut))
            {
                SleepTime = TimeSpan.FromMilliseconds(500)
            };

            IntPtr hWnd = action.Try(() =>
            {
                return findWindow.Find();
            });
            ieProcess.Refresh();
            return  WatiN.Core.IE.AttachTo<WatiN.Core.IE>(
                new WatiN.Core.Constraints.AttributeConstraint("hwnd", hWnd.ToString()), 5);
        }
    }

      

then instead of new IE () use IEBrowserHelper.CreateIEBrowser ()

+4


source


From the command line, you can schedule an interactive task like this:

C:\Users\someUser>schtasks /create /sc once /st 16:28 /tn someTask /tr cmd.exe

      



... where sc is the schedule, st is the start time, tn is the task name you choose (can be anything), and tr is the command you want to run. Obviously for a repeating task, you change sc to month, week, etc. Just enter "schtasks / create /?" for more information.

0


source



    using (IE browser = IEBrowserHelper.CreateIEBrowser ())
    {
    browser.GoTo ("www.yourwebaddress.com");
    browser.AutoClose = true;

    // Do the rest of your WaTin work in here ..
    }

The above shurik code works fine on Windows 2012 server too. First I needed to be logged in as Admin, now my task is running fine disconnected from RDP and logged out. I've provided the usage above to help others if they don't know how to use the class above.

You also need to include the following additional dependent namespace.

    using WatiN;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

-2


source







All Articles