Monthly Archives: December 2012

Running Command Line Process from c# code is Hanging / Locking and never Finishing

I created a WCF Service to allow remote machines to run command line scripts (in this case batch files) and then return the error and standard output as a string to the caller. The batch files worked fine when you ran them directly but whenever I ran them via the WCF service they kept hanging / locking and never completing. Mysterious.

I have since found out that this is because you have to redirect either or both of the standard out or error out to read in an asynchronous thread otherwise you get a deadlock when the buffer on one becomes full. Here is my code which does this and there is now no locking.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Diagnostics;
using System.Security;
using System.Security.Principal;
using System.Security.Permissions;
using System.IO;

namespace MyCompany.BatchScriptsService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    /// <summary>
    ///
    /// </summary>
    [ServiceBehavior(Namespace = "http://MyCompany.LaunchBatchScript")]
    public class LaunchBatchScriptService : ILaunchBatchScriptService
    {

        private StringBuilder allStandardOutput;

        public StringBuilder AllStandardOutput
        {
            get { return allStandardOutput; }
            set { allStandardOutput = value; }
        }

        private static readonly log4net.ILog log = log4net.LogManager.GetLogger
    (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Launches the batch script.
        /// </summary>
        /// <param name="batchScriptFilename">The batch script filename.</param>
        /// <param name="runAsUsername">The run as username.</param>
        /// <param name="runAsPassword">The run as password.</param>
        /// <param name="arguments">The arguments.</param>
        /// <returns></returns>
        public string LaunchBatchScript(LaunchBatchScriptDataContract inputVariables)
        {

            try
            {
                // Initiate the logging
                log4net.Config.XmlConfigurator.Configure();
                log.Info(String.Format("Start LaunchBatchScriptService call"));

                // Create a new process object
                Process p = new Process();

                // Redirect the output stream of the child process.
                p.StartInfo.UseShellExecute = false;

                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;

                if (inputVariables.BatchScriptFilename.Contains(" ") && !inputVariables.BatchScriptFilename.StartsWith("\""))
                {
                    // Ecapsulate in double quotes
                    inputVariables.BatchScriptFilename = String.Format("\"{0}\"", inputVariables.BatchScriptFilename);
                }

                p.StartInfo.FileName = inputVariables.BatchScriptFilename;
                log.Info(String.Format("Running script {0}", inputVariables.BatchScriptFilename));

                if (!String.IsNullOrEmpty(inputVariables.Arguments))
                {
                    p.StartInfo.Arguments = inputVariables.Arguments;
                }

                // This is where the output is redirected
                p.ErrorDataReceived += build_ErrorDataReceived;
                p.OutputDataReceived += build_ErrorDataReceived;

                // Initialise the StringBuilder Object
                AllStandardOutput = new StringBuilder();

                // Kick off the command
                bool isProcessStarted = p.Start();

                string output = "Process not started";

                if (isProcessStarted)
                {

                    log.Info(String.Format("Process Started Successfully"));
                    p.BeginOutputReadLine();
                    p.BeginErrorReadLine();

                    p.WaitForExit(); // wait for both threads to finish

                    output = AllStandardOutput.ToString();

                }

                log.Info(String.Format("Returning {0}", output));

                log.Info(String.Format("End LaunchBatchScriptService call"));
                return output;

            }
            catch (Exception ex)
            {
                log.Error(String.Format("There was a problem running the script: {0}",ex.Message));
                throw new FaultException(System.String.Format("There was a problem executing the script {0}: {1}", inputVariables.BatchScriptFilename, ex.Message));
            }
        }

        /// <summary>
        /// Handles the ErrorDataReceived event of the build control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Diagnostics.DataReceivedEventArgs"/> instance containing the event data.</param>
        public void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            string strMessage = e.Data;

            AllStandardOutput.Append(strMessage);
            AllStandardOutput.Append(System.Environment.NewLine);
        }
    }
}

Windows Updates and App Store Updates – No Internet Connection Through an Authenticated ISA Proxy Error Code 0x8024401c

Having connected my Windows 8 laptop to my company network, joined the domain and configured my proxy settings, I thought I’d cracked internet access and for the most part I had. However, the Windows Update and App Store download/installs still didn’t seem to have any connectivity failing with 0x8024401c. For the first part I had configured the proxy setting in IE (LAN settings) and then run the following code then rebooted.

netsh winhttp import proxy source=ie

This got most internet connectivity working in both IE and apps, but the app store downloads kept failing and the Windows Update just stayed still on 0%.

So back to the drawing board. I eventually came across an excellent forum post which described a slightly long winded solution but it did work and is I think the only solution unless you have admin access to your proxy service to allow unauthenticated exceptions. As a summary, here are the steps I took.

  1. Download and install CNTLM from SourceForge
  2. Edit %programfiles(x86)%\cntlm\cntlm.ini (note that your text editor needs to be opened as an admin)
  3. Change the user/domain/password parameters as per your windows domain account. Note that the forum post describes a more secure way of encrypting the password.
  4. Update the proxy server to use the address of your authenticated server
  5. Change the proxy setting in IE using the Connections / LAN setting to be localhost on port 3128
  6. Make sure IE can open web sites.
  7. Run the command again to copy the settings for your apps netsh winhttp import proxy source=ie
  8. Download and install the enable loopback tool. This is required because by default Windows 8 apps are prevented from sending traffic through a proxy running on your local machine. Open the app, select all apps and click apply. Note that everytime you install a new app, you will need to repeat this step.
  9. In the Local Security Policy -> Administrative Tools -> Network -Network Isolation, update and enable Internet proxy servers for apps (inputting 127.0.0.1:3128 as the domian proxy). Also enable “Proxy definitions are authoritive”)
  10. Shutdown the app you want to test using Task Manager (if it’s already open) and re-start it. You will also want to restart the windows update service in the “View Local Services” settings.

If you are still having problems it might also be worth stopping the Windows Update Services then deleting C:\Windows\SoftwareDistribution – note you may need to restart the computer to release any locks of files in this folder.

UPDATE – Microsoft have finally acknowledged the issue and have detailed a workaround at the proxy level. Even this fix isn’t ideal but hopefully the issue will be fixed permanently in a future Windows Update.