I am trying to run a Powershell command with admin privileges in Flutter/Dart.
The command runs a .ps1 file inside the temp directory.
I found this article, which I implemented and it works fine.
However, after the PowerShell command runs, I see an output on the PowerShell window and so I expect to print this output but I get nothing.
Future<void> executePowerShellCommand() async {
String tempFilePath = '${Directory.systemTemp.path}\\COMMAND.ps1';
try {
String command = 'powershell';
List<String> args = [
'-Command',
'Start-Process -FilePath "powershell" -ArgumentList "-ExecutionPolicy Bypass -NoProfile -File `"$tempFilePath`"" -Verb RunAs -Wait'
];
final ProcessResult result = await Process.run(command, args, runInShell: true, stdoutEncoding: utf8, stderrEncoding: utf8);
String output = result.stdout.toString().trim();
String errorOutput = result.stderr.toString().trim();
int exitCode = result.exitCode;
if (exitCode == 0 && errorOutput.isEmpty) {
debugPrint('>>>Powershell Command succeeded: $output');//output is empty
}
} catch (e, s) {
debugPrint(">>>Error $e");
}
}
I researched and found out that Start-Process
spawns a separate process and that is why the output is empty. So I thought I could capture the output of the command and save it into a file, then read the contents of the file.
Something like this:
Future<void> executePowerShellCommandWithOutput() async {
String tempFilePath = '${Directory.systemTemp.path}\\COMMAND.ps1';
String outputFilePath = '${Directory.systemTemp.path}\\OUTPUT.txt';
try {
String command = 'powershell';
List<String> args = [
'-Command',
'''Start-Process -FilePath "powershell" -ArgumentList '-ExecutionPolicy Bypass -NoProfile -File "$tempFilePath" | Out-File "$outputFilePath" -Encoding utf8' -Verb RunAs -Wait'''
];
final ProcessResult result = await Process.run(command, args, runInShell: true, stderrEncoding: utf8);
String errorOutput = result.stderr.toString().trim();
int exitCode = result.exitCode;
if (exitCode == 0 && errorOutput.isEmpty) {
File file = File(outputFilePath);
String fileContent = file.readAsString().toString();
debugPrint('>>>File Content: $fileContent');
}
} catch (e, s) {
debugPrint(">>>Error $e");
}
}
This approach is unfortunately not working. How do I get it to work?
Thank you so much.
To make your approach work, you must use -Command
rather than -File
with powershell.exe
, the Windows PowerShell CLI.
Unlike -File
, which only supports a target script path (*.ps1
) optionally followed by literal pass-through arguments, -Command
allows you to pass a snippet of PowerShell source code, which is needed in order to execute an entire pipeline such as yours (... | Out-File ...
)
List<String> args = [
'-Command',
'''Start-Process -FilePath "powershell" -ArgumentList '-ExecutionPolicy Bypass -NoProfile -Command & "$tempFilePath" | Out-File "$outputFilePath" -Encoding utf8' -Verb RunAs -Wait'''
];
Note the use of -Command
instead of -File
, as well as the use of &
, the call operator for invoking the *.ps1
file (which is a syntactic necessity, because the script-file path is quoted).
Note that while it is tempting to try to use Start-Process
's -RedirectStandardOut
and -RedirectStandardError
parameters to directly capture command output in files, this does not work in combination with -Verb RunAs
, i.e. when launching an elevated process - see this answer for details.