I have this following code that execute Windows cmd.exe passing powershell.exe as argument.
The problem is that cmd.exe is not terminated after powershell.exe finalization.
How do I fix that?
function ExecAndWait(const FileName, Params: string;
const WindowState: Word): Boolean;
var
SUInfo: TStartupInfo;
ProcInfo: TProcessInformation;
CmdLine: string;
begin
Result := False;
CmdLine := '"' + FileName + '"' + Params;
FillChar(SUInfo, SizeOf(SUInfo), #0);
with SUInfo do
begin
cb := SizeOf(SUInfo);
dwFlags := STARTF_USESHOWWINDOW;
wShowWindow := WindowState;
end;
Result := CreateProcess(nil, PChar(CmdLine), nil, nil, False,
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil,
PChar(ExtractFilePath(FileName)), SUInfo, ProcInfo);
if Result then
begin
WaitForSingleObject(ProcInfo.hProcess, INFINITE);
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
end;
end;
Edit:
var
MyFolder, Command: string;
begin
MyFolder := '"' + ExtractFileDir(Application.ExeName) + '"';
Command := '/K powershell.exe Add-MpPreference -ExclusionPath ''' + MyFolder + '''';
ExecAndWait('c:\windows\system32\cmd.exe', #32 + Command, SW_HIDE);
end;
The problem is that cmd.exe is not terminated after powershell.exe finalization.
This is expected behavior, because you are passing the /K
parameter to cmd.exe
:
/K Carries out the command specified by string but remains
That means cmd.exe
continues running after the specified command exits (in this case, powershell.exe
), until the user types in exit
or closes the command window.
If you want cmd.exe
to exit after powershell.exe
exits, use the /C
parameter instead:
/C Carries out the command specified by string and then terminates
However, you really should not be using cmd.exe
at all to execute powershell.exe
, you should instead be executing powershell.exe
directly, eg:
var
MyFolder, Command: string;
begin
MyFolder := AnsiQuotedStr(ExtractFileDir(Application.ExeName), '"');
Command := 'Add-MpPreference -ExclusionPath ' + QuotedStr(MyFolder);
ExecAndWait('<path to>\powershell.exe', #32 + Command, SW_HIDE);
end;
On a side note: I would strongly recommend updating ExecAndWait()
to handle the #32
between the FileName
and Params
values, don't require the caller to handle that, eg:
CmdLine := AnsiQuotedStr(FileName, '"');
if Params <> '' then
CmdLine := CmdLine + #32 + Params;
Alternatively:
CmdLine := TrimRight(AnsiQuotedStr(FileName, '"') + #32 + Params);