1

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.

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.