title: Got "The system cannot find the file specified" when I run NETSH from CreateProcess but it works ok on Command Prompt?
body: <p>I have an <code>NT</code> service that calls a console program written in Delphi 7, let's call it <code>failover.exe</code> that in turn calls <code>NETSH</code> using a procedure I found:</p>
  
  <pre><code>procedure ExecConsoleApp(CommandLine: ansistring; Output, Errors: TStringList); 
  </code></pre>
  
  <p>Note: ExecConsoleApp uses CreateProcess, see the following link for full code: <a href="http://www.delphisources.ru/pages/faq/base/createprocess_console.html" rel="nofollow">http://www.delphisources.ru/pages/faq/base/createprocess_console.html</a></p>
  
  <p>I would pass the following to CommandLine before calling <code>ExecConsoleApp</code>: </p>
  
  <pre><code>cmd.exe /c "C:\Windows\system32\netsh.exe interface delete address "Wireless Network Connection" 192.168.0.36" 
  </code></pre>
  
  <p><code>ExecConsoleApp</code> will return an error: </p>
  
  <blockquote>
    <p>The system cannot find the file specified</p>
  </blockquote>
  
  <p>But if I were to run it in Command Prompt, it runs perfectly.</p>
  
  <p>The strange thing is that I remembered it working on the first attempt on that 2003 Server, but after that, it failed regardless of the number of times I tried.  In one of the attempt, I've also tried assigning logon as administrator user to the service but to no avail. Neither does fiddling with file security help.</p>
  
  <p>I don't have a Win 2003 server to test with in office, but I have tested it on XP and Win7 and <code>ExecConsoleApp</code> works perfectly, although on XP, I had to amend <code>ExecConsoleApp</code> to execute from <code>system32\wbem</code> in order for it work work:</p>
  
  <pre><code> Res := CreateProcess(nil, PChar(CommandLine), nil, nil, True,
    // **** Attention: Amended by to point current directory to system32\wbem, this is to solve an error returned by netsh.exe if not done otherwise.
   //   CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, @env, nil, si, pi);
     CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, @env, pchar(GetSystemPath(WindRoot) + 'system32\wbem'), si, pi);
  </code></pre>
  
  <p>I've researched for a day but no clues, hope someone can help.  Thanks.</p>
  
  <p>Additional remarks -</p>
  
  <ol>
  <li><p>Server is 32 bit Win2k3.</p></li>
  <li><p>Tried domain administrator, doesn't work. </p></li>
  <li><p>Code snippets:</p>
  
  <pre><code>Procedure ExecConsoleApp(CommandLine: ansistring; Output, Errors: TStringList);
    var
      sa: TSECURITYATTRIBUTES;
      si: TSTARTUPINFO;
      pi: TPROCESSINFORMATION;
      hPipeOutputRead: THANDLE;
      hPipeOutputWrite: THANDLE;
      hPipeErrorsRead: THANDLE;
      hPipeErrorsWrite: THANDLE;
      Res, bTest: boolean;
      env: array[0..100] of char;
      szBuffer: array[0..256] of char;
      dwNumberOfBytesRead: DWORD;
      Stream: TMemoryStream;
    begin
      sa.nLength := sizeof(sa);
      sa.bInheritHandle := True;
      sa.lpSecurityDescriptor := nil;
      CreatePipe(hPipeOutputRead, hPipeOutputWrite, @sa, 0);
      CreatePipe(hPipeErrorsRead, hPipeErrorsWrite, @sa, 0);
      ZeroMemory(@env, SizeOf(env));
      ZeroMemory(@si, SizeOf(si));
      ZeroMemory(@pi, SizeOf(pi));
      si.cb := SizeOf(si);
      si.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      si.wShowWindow := SW_HIDE;
      si.hStdInput := 0;
      si.hStdOutput := hPipeOutputWrite;
      si.hStdError := hPipeErrorsWrite;
  
    (* Remember that if you want to execute an app with no parameters you nil the
       second parameter and use the first, you can also leave it as is with no
       problems.                                                                 *)
      Res := CreateProcess(nil, PChar(CommandLine), nil, nil, True,
      CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, @env, nil, si, pi);
  
  
      // Procedure will exit if CreateProcess fail
      if not Res then
      begin
        CloseHandle(hPipeOutputRead);
        CloseHandle(hPipeOutputWrite);
        CloseHandle(hPipeErrorsRead);
        CloseHandle(hPipeErrorsWrite);
        Exit;
      end;
      CloseHandle(hPipeOutputWrite);
      CloseHandle(hPipeErrorsWrite);
  
      //Read output pipe
      Stream := TMemoryStream.Create;
      try
        while True do
        begin
          bTest := ReadFile(hPipeOutputRead, szBuffer, 256, dwNumberOfBytesRead, nil);
          if not bTest then
          begin
            break;
          end;
          OemToAnsi(szBuffer, szBuffer);
          Stream.Write(szBuffer, dwNumberOfBytesRead);
        end;
        Stream.Position := 0;
        Output.LoadFromStream(Stream);
      finally
        Stream.Free;
      end;
  
      //Read error pipe
      Stream := TMemoryStream.Create;
      try
        while True do
        begin
          bTest := ReadFile(hPipeErrorsRead, szBuffer, 256, dwNumberOfBytesRead, nil);
          if not bTest then
          begin
            break;
          end;
          OemToAnsi(szBuffer, szBuffer);
          Stream.Write(szBuffer, dwNumberOfBytesRead);
        end;
        Stream.Position := 0;
        Errors.LoadFromStream(Stream);
      finally
        Stream.Free;
      end;
  
      WaitForSingleObject(pi.hProcess, INFINITE);
      CloseHandle(pi.hProcess);
      CloseHandle(hPipeOutputRead);
      CloseHandle(hPipeErrorsRead);
    end;
  
  
    cmdstring :=
      'cmd.exe /c "' + GetSystemPath(WindRoot) + 'system32\netsh.exe interface ' +
      ip + ' delete address "' + NetworkInterfaceName + '" ' + VirtualFailoverIPAddress + '"';
  
    logstr('cmdstring: ' + cmdstring);
    ExecConsoleApp(cmdstring, OutP, ErrorP);
  
    if OutP.Text &lt;&gt; '' then
    begin
      logstr('Delete IP Result: ' + OutP.Text);
    end
    else
    begin
      logstr('Delete IP Error: ' + ErrorP.Text);
    end;
  </code></pre></li>
  <li><p>Tried running netsh.exe directly instead of "cmd.exe /c C:\Windows\system32\netsh.exe...", and got the same "The system cannot find the file specified." error.  I also accidentally discovered that if I were to issue a wrong netsh command, netsh will actually return an error, e.g.</p></li>
  </ol>
  
  <p>netsh interface ip delete address "LocalArea Connection" 10.40.201.65</p>
  
  <blockquote>
    <p>Invalid interface LocalArea Connection specified.</p>
  </blockquote>
  
  <p>The following is returned if i correct the typo "LocalArea" to "Local Area".
  netsh interface ip delete address "Local Area Connection" 10.40.201.65</p>
  
  <blockquote>
    <p>The system cannot find the file specified.</p>
  </blockquote>
  
  <p>Again, I must repeat that the same command works perfectly fine if I issue it via Command Prompt instead of from my application.</p>