Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions schema/v1/ScriptRunnerSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
"command": {
"type": "string"
},
"useSystemShell": {
"type": "boolean"
},
"runCommandAsAdmin":{
"type":"boolean"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class ScriptConfig
public string? Description { get; set; }
public string Command { get; set; }
public bool RunCommandAsAdmin { get; set; }
public bool UseSystemShell { get; set; }
public string Docs { get; set; }
public string DocsContent { get; set; } = string.Empty;
public string DocAssetPath { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ private void RenderParameterForm(ScriptConfig action, Dictionary<string, string>
var taskCompletionSource = new TaskCompletionSource<string>();
try
{
ExecuteCommand(command, this.SelectedAction, title, s =>
ExecuteCommand(command, this.SelectedAction, useSystemShell:false, title, s =>
{
taskCompletionSource.SetResult(s);
});
Expand Down Expand Up @@ -858,7 +858,7 @@ public void RunScript()

var selectedActionCommand = selectedAction.Command;

ExecuteCommand(selectedActionCommand, selectedAction);
ExecuteCommand(selectedActionCommand, selectedAction, selectedAction.UseSystemShell);

// Some audit staff
var usedParams = HarvestCurrentParameters(vaultPrefixForNewEntries: $"{selectedAction.Name}_{Guid.NewGuid():N}");
Expand All @@ -870,7 +870,7 @@ public void RunScript()

}

private void ExecuteCommand(string command, ScriptConfig selectedAction, string? title = null, Action<string>? onComplete = null)
private void ExecuteCommand(string command, ScriptConfig selectedAction, bool useSystemShell, string? title = null, Action<string>? onComplete = null)
{
var (commandPath, args) = SplitCommandAndArgs(command);
var envVariables = new Dictionary<string, string?>(selectedAction.EnvironmentVariables);
Expand Down Expand Up @@ -902,7 +902,7 @@ private void ExecuteCommand(string command, ScriptConfig selectedAction, string?
job.ExecutionCompleted += (sender, args) => onComplete(job.RawOutput);
}

job.RunJob(commandPath, args, selectedAction.WorkingDirectory, selectedAction.InteractiveInputs, selectedAction.Troubleshooting);
job.RunJob(commandPath, args, selectedAction.WorkingDirectory, selectedAction.InteractiveInputs, selectedAction.Troubleshooting, useSystemShell);
}

public ObservableCollection<ExecutionLogAction> ExecutionLog { get; set; } = new ();
Expand Down
81 changes: 61 additions & 20 deletions src/ScriptRunner/ScriptRunner.GUI/ViewModels/RunningJobViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ public void Dispose()
public void RaiseExecutionCompleted() => ExecutionCompleted?.Invoke(this, EventArgs.Empty);
private IReadOnlyList<InteractiveInputDescription> _inputs = new List<InteractiveInputDescription>();
public void RunJob(string commandPath, string args, string? workingDirectory,
IReadOnlyList<InteractiveInputDescription> interactiveInputs, IReadOnlyList<TroubleshootingItem> troubleshooting)
IReadOnlyList<InteractiveInputDescription> interactiveInputs,
IReadOnlyList<TroubleshootingItem> troubleshooting,
bool useSystemShell = false)
{

_inputs = interactiveInputs;
Expand All @@ -115,24 +117,63 @@ public void RunJob(string commandPath, string args, string? workingDirectory,
GracefulCancellation = new CancellationTokenSource();
KillCancellation = new CancellationTokenSource();
ChangeStatus(RunningJobStatus.Running);
await Cli.Wrap(commandPath)
.WithArguments(args)
//TODO: Working dir should be read from the config with the fallback set to the config file dir
.WithWorkingDirectory(workingDirectory ?? "Scripts/")
.WithStandardInputPipe(PipeSource.FromStream(inputStream,autoFlush:true))
.WithStandardOutputPipe(PipeTarget.ToDelegate(s =>

if (useSystemShell)
{
var processStartInfo = new ProcessStartInfo()
{
rawOutput.AppendLine(s);
AppendToOutput(s, ConsoleOutputLevel.Normal);
}))
.WithStandardErrorPipe(PipeTarget.ToDelegate(s =>
FileName = commandPath,
Arguments = args,
WorkingDirectory = workingDirectory,
UseShellExecute = true,
RedirectStandardInput = false,
RedirectStandardOutput = false,
RedirectStandardError = false
};

if (EnvironmentVariables != null)
{
rawErrorOutput.Append(s);
AppendToOutput(s, ConsoleOutputLevel.Error);
}))
.WithValidation(CommandResultValidation.None)
.WithEnvironmentVariables(EnvironmentVariables ?? new())
.ExecuteAsync(KillCancellation.Token, GracefulCancellation.Token);
foreach (var o in EnvironmentVariables)
{
processStartInfo.EnvironmentVariables[o.Key] = o.Value;
}
}
var p = Process.Start(processStartInfo);
try
{
if (p != null)
{
await p.WaitForExitAsync(GracefulCancellation.Token);
}
}
finally
{
if(p.HasExited == false)
p.Kill();
}
}
else
{
await Cli.Wrap(commandPath)
.WithArguments(args)
//TODO: Working dir should be read from the config with the fallback set to the config file dir
.WithWorkingDirectory(workingDirectory ?? "Scripts/")
.WithStandardInputPipe(PipeSource.FromStream(inputStream,autoFlush:true))
.WithStandardOutputPipe(PipeTarget.ToDelegate(s =>
{
rawOutput.AppendLine(s);
AppendToOutput(s, ConsoleOutputLevel.Normal);
}))
.WithStandardErrorPipe(PipeTarget.ToDelegate(s =>
{
rawErrorOutput.Append(s);
AppendToOutput(s, ConsoleOutputLevel.Error);
}))
.WithValidation(CommandResultValidation.None)
.WithEnvironmentVariables(EnvironmentVariables ?? new())
.ExecuteAsync(KillCancellation.Token, GracefulCancellation.Token);
}

ChangeStatus(RunningJobStatus.Finished);
}
catch (Exception e)
Expand Down Expand Up @@ -424,13 +465,13 @@ private void AppendToUiOutput(IList<string> s)
foreach (var part in s.SelectMany(x=>x.Split("\r\n")).TakeLast(OutputBufferSize))
{
var subParts = ConsoleSpecialCharsPattern.Split(part);
if (part.Contains("http://") || part.Contains("https://"))
if (part.Contains("http://", StringComparison.OrdinalIgnoreCase) || part.Contains("https://", StringComparison.OrdinalIgnoreCase))
{
subParts = subParts.SelectMany(x => urlPattern.Split(x)).ToArray();
}
foreach (var chunk in subParts.Where(x=> x != string.Empty))
{
if (chunk.StartsWith("http://") || chunk.StartsWith("https://"))
if (chunk.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || chunk.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
_outputElements.Add(new Link(chunk));
continue;
Expand All @@ -443,7 +484,7 @@ private void AppendToUiOutput(IList<string> s)
subPart = subPart.Replace(";3m", "m");
}

if (subPart.StartsWith("\u001b["))
if (subPart.StartsWith("\u001b[", StringComparison.Ordinal))
{
var foreground = subPart switch
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@
<TextBox Watermark="Search" Text="{Binding TermForCurrentHistoryFilter}"></TextBox>
<CheckBox IsChecked="{Binding CompactedHistoryForCurrent}" ToolTip.Tip="Show latest execution with the same parameters">Compacted</CheckBox>
</StackPanel>
<ListBox Grid.Row="1" SelectedItem="{Binding SelectedRecentExecution, Mode=OneWayToSource}" ItemsSource="{Binding ExecutionLogForCurrent}">
<ListBox Grid.Row="1" SelectedItem="{Binding SelectedRecentExecution}" ItemsSource="{Binding ExecutionLogForCurrent}">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="viewModels:ExecutionLogAction">
<Grid ColumnDefinitions="Auto, *" RowDefinitions="Auto, *">
Expand Down
Loading