Execute powershell directly

This commit is contained in:
Luke Bakken 2022-12-09 19:13:40 -08:00
parent 9eb993eb65
commit f7b65abc15
No known key found for this signature in database
GPG Key ID: D99DE30E43EAE440
2 changed files with 97 additions and 32 deletions

View File

@ -62,7 +62,7 @@
-export([pget/2, pget/3, pupdate/3, pget_or_die/2, pmerge/3, pset/3, plmerge/2]). -export([pget/2, pget/3, pupdate/3, pget_or_die/2, pmerge/3, pset/3, plmerge/2]).
-export([format_message_queue/2]). -export([format_message_queue/2]).
-export([append_rpc_all_nodes/4, append_rpc_all_nodes/5]). -export([append_rpc_all_nodes/4, append_rpc_all_nodes/5]).
-export([os_cmd/1]). -export([os_cmd/1, pwsh_cmd/1]).
-export([is_os_process_alive/1]). -export([is_os_process_alive/1]).
-export([version/0, otp_release/0, platform_and_version/0, otp_system_version/0, -export([version/0, otp_release/0, platform_and_version/0, otp_system_version/0,
rabbitmq_and_erlang_versions/0, which_applications/0]). rabbitmq_and_erlang_versions/0, which_applications/0]).
@ -1156,6 +1156,14 @@ os_cmd(Command) ->
end end
end. end.
pwsh_cmd(Command) ->
case os:type() of
{win32, _} ->
do_pwsh_cmd(Command);
_ ->
{error, invalid_os_type}
end.
is_os_process_alive(Pid) -> is_os_process_alive(Pid) ->
with_os([{unix, fun () -> with_os([{unix, fun () ->
run_ps(Pid) =:= 0 run_ps(Pid) =:= 0
@ -1164,26 +1172,17 @@ is_os_process_alive(Pid) ->
PidS = rabbit_data_coercion:to_list(Pid), PidS = rabbit_data_coercion:to_list(Pid),
case os:find_executable("tasklist.exe") of case os:find_executable("tasklist.exe") of
false -> false ->
Cmd = Cmd = format("(Get-Process -Id ~ts).ProcessName", [PidS]),
format( {ok, Res} = pwsh_cmd(Cmd),
"powershell.exe -NoLogo -NoProfile -NonInteractive -Command "
"\"(Get-Process -Id ~ts).ProcessName\"",
[PidS]),
Res =
os_cmd(Cmd ++ " 2>&1") -- [$\r, $\n],
case Res of case Res of
"erl" -> true; "erl" -> true;
"werl" -> true; "werl" -> true;
_ -> false _ -> false
end; end;
_ -> TasklistExe ->
Cmd = Args = ["/nh", "/fi", "pid eq " ++ PidS],
"tasklist /nh /fi " {ok, Res} = do_win32_cmd(TasklistExe, Args),
"\"pid eq " ++ PidS ++ "\"", match =:= re:run(Res, "erl\\.exe", [{capture, none}])
Res = os_cmd(Cmd ++ " 2>&1"),
match =:= re:run(Res,
"erl\\.exe",
[{capture, none}])
end end
end}]). end}]).
@ -1472,3 +1471,82 @@ whereis_name(Name) ->
%% End copypasta from gen_server2.erl %% End copypasta from gen_server2.erl
%% ------------------------------------------------------------------------- %% -------------------------------------------------------------------------
%% This will execute a Powershell command that is expected to return a
%% single-line result. Output lines can't exceed 512 bytes. If multiple
%% lines are returned by the command, these functions will return the
%% last line.
%%
%% Inspired by os:cmd/1 in lib/kernel/src/os.erl
do_pwsh_cmd(Command) ->
Pwsh = find_powershell(),
A1 = ["-NoLogo",
"-NonInteractive",
"-NoProfile",
"-InputFormat", "Text",
"-OutputFormat", "Text",
"-Command", Command],
do_win32_cmd(Pwsh, A1).
do_win32_cmd(Exe, Args) ->
SystemRootDir = os:getenv("SystemRoot", "/"),
% Note: 'hide' must be used or this will not work!
A0 = [exit_status, stderr_to_stdout, in, hide,
{cd, SystemRootDir}, {line, 512}, {arg0, Exe}, {args, Args}],
Port = erlang:open_port({spawn_executable, Exe}, A0),
MonRef = erlang:monitor(port, Port),
Result = win32_cmd_receive(Port, MonRef, <<>>),
true = erlang:demonitor(MonRef, [flush]),
Result.
win32_cmd_receive(Port, MonRef, Data0) ->
receive
{Port, {exit_status, 0}} ->
win32_cmd_receive_finish(Port, MonRef),
{ok, Data0};
{Port, {exit_status, Status}} ->
win32_cmd_receive_finish(Port, MonRef),
{error, {exit_status, Status}};
{Port, {data, {eol, Data1}}} ->
Data2 = string:trim(Data1),
win32_cmd_receive(Port, MonRef, Data2);
{'DOWN', MonRef, _, _, _} ->
flush_exit(Port),
{error, nodata}
after 5000 ->
{error, timeout}
end.
win32_cmd_receive_finish(Port, MonRef) ->
catch erlang:port_close(Port),
flush_until_down(Port, MonRef).
flush_until_down(Port, MonRef) ->
receive
{Port, {data, _Bytes}} ->
flush_until_down(Port, MonRef);
{'DOWN', MonRef, _, _, _} ->
flush_exit(Port)
after 500 ->
flush_exit(Port)
end.
flush_exit(Port) ->
receive
{'EXIT', Port, _} -> ok
after 0 ->
ok
end.
find_powershell() ->
case os:find_executable("pwsh.exe") of
false ->
case os:find_executable("powershell.exe") of
false ->
"powershell.exe";
PowershellExe ->
PowershellExe
end;
PwshExe ->
PwshExe
end.

View File

@ -146,9 +146,9 @@ find_files_line([_H | T]) ->
find_files_line(T). find_files_line(T).
get_used_fd_via_powershell(Pid) -> get_used_fd_via_powershell(Pid) ->
PwshExe = find_powershell(), Cmd = "Get-Process -Id " ++ Pid ++ " | Select-Object -ExpandProperty HandleCount",
Handle = rabbit_misc:os_cmd("\"" ++ PwshExe ++ "\" -NoLogo -NoProfile -NonInteractive -Command (Get-Process -Id " ++ Pid ++ ").Handles"), {ok, Result} = rabbit_misc:pwsh_cmd(Cmd),
list_to_integer(string:trim(Handle)). list_to_integer(Result).
-define(SAFE_CALL(Fun, NoProcFailResult), -define(SAFE_CALL(Fun, NoProcFailResult),
try try
@ -430,16 +430,3 @@ get_fhc_stats() ->
get_ra_io_metrics() -> get_ra_io_metrics() ->
lists:sort(ets:tab2list(ra_io_metrics)). lists:sort(ets:tab2list(ra_io_metrics)).
find_powershell() ->
case os:find_executable("pwsh.exe") of
false ->
case os:find_executable("powershell.exe") of
false ->
"powershell.exe";
PowershellExe ->
PowershellExe
end;
PwshExe ->
PwshExe
end.