FF-1646: Added support for sh/bat/ps1 scripts

This commit is contained in:
John Andrews
2024-08-01 12:20:09 +12:00
parent a5310bd6c3
commit a5245694c3
7 changed files with 997 additions and 578 deletions

View File

@@ -0,0 +1,126 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
namespace FileFlows.BasicNodes.Scripting;
/// <summary>
/// Flow element that executes a bat script
/// </summary>
public class BatScript : Node
{
/// <inheritdoc />
public override int Inputs => 1;
/// <inheritdoc />
public override int Outputs => 2;
/// <inheritdoc />
public override FlowElementType Type => FlowElementType.Process;
/// <inheritdoc />
public override string Icon => "svg:bat";
/// <inheritdoc />
public override bool FailureNode => true;
/// <inheritdoc />
public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/bat-script";
/// <summary>
/// Gets or sets the code to execute
/// </summary>
[Required]
[DefaultValue(@"REM This is a template batch file
REM Replace {file.FullName} and {file.Orig.FullName} with actual values
SET WorkingFile={file.FullName}
SET OriginalFile={file.Orig.FullName}
REM Example commands using the variables
echo Working on file: %WorkingFile%
echo Original file location: %OriginalFile%
REM Add your actual batch commands below
REM Example: Copy the working file to a backup location
REM copy ""%WorkingFile%"" ""C:\Backup\%~nxWorkingFile%""
REM Set the exit code to 0
EXIT /B 0
")]
[Code(1, "bat")]
public string Code { get; set; }
/// <inheritdoc />
public override int Execute(NodeParameters args)
{
if (string.IsNullOrEmpty(Code))
{
args.FailureReason = "No code specified in .bat script";
args.Logger?.ELog(args.FailureReason);
return -1; // no code, flow cannot continue doesn't know what to do
}
if (OperatingSystem.IsWindows() == false)
{
args.FailureReason = "Cannot run a .bat file on a non Windows system";
args.Logger?.ELog(args.FailureReason);
return -1;
}
var batFile = System.IO.Path.Combine(args.TempPath, Guid.NewGuid() + ".bat");
try
{
var code = "@echo off" + Environment.NewLine + args.ReplaceVariables(Code);
args.Logger?.ILog("Executing code: \n" + code);
System.IO.File.WriteAllText(batFile, code);
args.Logger?.ILog($"Temporary bat file created: {batFile}");
var processStartInfo = new ProcessStartInfo
{
FileName = batFile,
WorkingDirectory = args.TempPath,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = processStartInfo };
process.Start();
string standardOutput = process.StandardOutput.ReadToEnd();
string standardError = process.StandardError.ReadToEnd();
process.WaitForExit();
int exitCode = process.ExitCode;
if(string.IsNullOrWhiteSpace(standardOutput) == false)
args.Logger?.ILog($"Standard Output:\n{standardOutput}");
if(string.IsNullOrWhiteSpace(standardError) == false)
args.Logger?.WLog($"Standard Error:\n{standardError}");
args.Logger?.ILog($"Exit Code: {exitCode}");
return exitCode == 0 ? 1 : 2;
}
catch (Exception ex)
{
args.FailureReason = "Failed executing bat script: " + ex.Message;
args.Logger?.ELog(args.FailureReason);
return -1;
}
finally
{
try
{
if (System.IO.File.Exists(batFile))
{
System.IO.File.Delete(batFile);
args.Logger?.ILog($"Temporary bat file deleted: {batFile}");
}
}
catch (Exception ex)
{
args.Logger?.WLog($"Failed to delete temporary bat file: {batFile}. Error: {ex.Message}");
}
}
}
}

View File

@@ -19,7 +19,9 @@ public class Function : Node
/// <inheritdoc />
public override bool FailureNode => true;
/// <inheritdoc />
public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/function";
public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/function";
/// <inheritdoc />
public override string Group => "Scripting";
/// <summary>
/// Gets or sets the number of outputs
@@ -40,11 +42,14 @@ public class Function : Node
public override int Execute(NodeParameters args)
{
if (string.IsNullOrEmpty(Code))
return -1; // no code, flow cannot continue doesnt know what to do
{
args.FailureReason = "No code specified in Function script";
args.Logger?.ELog(args.FailureReason);
return -1; // no code, flow cannot continue doesn't know what to do
}
try
{
return args.ScriptExecutor.Execute(new FileFlows.Plugin.Models.ScriptExecutionArgs
{
Args = args,
@@ -53,6 +58,7 @@ public class Function : Node
}
catch (Exception ex)
{
args.FailureReason = "Failed executing function: " + ex.Message;
args.Logger?.ELog("Failed executing function: " + ex.Message + Environment.NewLine + ex.StackTrace);
return -1;
}

View File

@@ -0,0 +1,127 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
namespace FileFlows.BasicNodes.Scripting;
/// <summary>
/// Flow element that executes a PowerShell script
/// </summary>
public class PowerShellScript : Node
{
/// <inheritdoc />
public override int Inputs => 1;
/// <inheritdoc />
public override int Outputs => 2;
/// <inheritdoc />
public override FlowElementType Type => FlowElementType.Process;
/// <inheritdoc />
public override string Icon => "svg:ps1";
/// <inheritdoc />
public override bool FailureNode => true;
/// <inheritdoc />
public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/powershell-script";
/// <summary>
/// Gets or sets the code to execute
/// </summary>
[Required]
[DefaultValue(@"# This is a template PowerShell script
# Replace {file.FullName} and {file.Orig.FullName} with actual values
$WorkingFile = '{file.FullName}'
$OriginalFile = '{file.Orig.FullName}'
# Example commands using the variables
Write-Output ""Working on file: $WorkingFile""
Write-Output ""Original file location: $OriginalFile""
# Add your actual PowerShell commands below
# Example: Copy the working file to a backup location
# Copy-Item -Path $WorkingFile -Destination ""C:\Backup\$([System.IO.Path]::GetFileName($WorkingFile))""
# Set the exit code to 0
exit 0
")]
[Code(1, "powershell")]
public string Code { get; set; }
/// <inheritdoc />
public override int Execute(NodeParameters args)
{
if (string.IsNullOrEmpty(Code))
{
args.FailureReason = "No code specified in PowerShell script";
args.Logger?.ELog(args.FailureReason);
return -1; // no code, flow cannot continue doesn't know what to do
}
if (OperatingSystem.IsWindows() == false)
{
args.FailureReason = "Cannot run a PowerShell file on a non Windows system";
args.Logger?.ELog(args.FailureReason);
return -1;
}
var ps1File = System.IO.Path.Combine(args.TempPath, Guid.NewGuid() + ".ps1");
try
{
var code = args.ReplaceVariables(Code);
args.Logger?.ILog("Executing code: \n" + code);
System.IO.File.WriteAllText(ps1File, code);
args.Logger?.ILog($"Temporary PowerShell file created: {ps1File}");
var processStartInfo = new ProcessStartInfo
{
FileName = "powershell.exe",
Arguments = $"-NoProfile -ExecutionPolicy Bypass -File \"{ps1File}\"",
WorkingDirectory = args.TempPath,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = processStartInfo };
process.Start();
string standardOutput = process.StandardOutput.ReadToEnd();
string standardError = process.StandardError.ReadToEnd();
process.WaitForExit();
int exitCode = process.ExitCode;
if(string.IsNullOrWhiteSpace(standardOutput) == false)
args.Logger?.ILog($"Standard Output:\n{standardOutput}");
if(string.IsNullOrWhiteSpace(standardError) == false)
args.Logger?.WLog($"Standard Error:\n{standardError}");
args.Logger?.ILog($"Exit Code: {exitCode}");
return exitCode == 0 ? 1 : 2;
}
catch (Exception ex)
{
args.FailureReason = "Failed executing PowerShell script: " + ex.Message;
args.Logger?.ELog(args.FailureReason);
return -1;
}
finally
{
try
{
if (System.IO.File.Exists(ps1File))
{
System.IO.File.Delete(ps1File);
args.Logger?.ILog($"Temporary ps1 file deleted: {ps1File}");
}
}
catch (Exception ex)
{
args.Logger?.WLog($"Failed to delete temporary ps1 file: {ps1File}. Error: {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,127 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
namespace FileFlows.BasicNodes.Scripting;
/// <summary>
/// Flow element that executes a SH script
/// </summary>
public class ShScript : Node
{
/// <inheritdoc />
public override int Inputs => 1;
/// <inheritdoc />
public override int Outputs => 2;
/// <inheritdoc />
public override FlowElementType Type => FlowElementType.Process;
/// <inheritdoc />
public override string Icon => "svg:sh";
/// <inheritdoc />
public override bool FailureNode => true;
/// <inheritdoc />
public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/sh-script";
/// <summary>
/// Gets or sets the code to execute
/// </summary>
[Required]
[DefaultValue(@"# This is a template shell script
# Replace {file.FullName} and {file.Orig.FullName} with actual values
WorkingFile=""{file.FullName}""
OriginalFile=""{file.Orig.FullName}""
# Example commands using the variables
echo ""Working on file: $WorkingFile""
echo ""Original file location: $OriginalFile""
# Add your actual shell commands below
# Example: Copy the working file to a backup location
# cp ""$WorkingFile"" ""/path/to/backup/$(basename \""$WorkingFile\"")""
# Set the exit code to 0
exit 0
")]
[Code(1, "sh")]
public string Code { get; set; }
/// <inheritdoc />
public override int Execute(NodeParameters args)
{
if (string.IsNullOrEmpty(Code))
{
args.FailureReason = "No code specified in SH script";
args.Logger?.ELog(args.FailureReason);
return -1; // no code, flow cannot continue doesn't know what to do
}
if (OperatingSystem.IsWindows())
{
args.FailureReason = "Cannot run a SH script on a Windows system";
args.Logger?.ELog(args.FailureReason);
return -1;
}
var shFile = System.IO.Path.Combine(args.TempPath, Guid.NewGuid() + ".sh");
try
{
var code = args.ReplaceVariables(Code);
args.Logger?.ILog("Executing code: \n" + code);
System.IO.File.WriteAllText(shFile, code);
args.Logger?.ILog($"Temporary SH file created: {shFile}");
var processStartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"\"{shFile}\"",
WorkingDirectory = args.TempPath,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var process = new Process { StartInfo = processStartInfo };
process.Start();
string standardOutput = process.StandardOutput.ReadToEnd();
string standardError = process.StandardError.ReadToEnd();
process.WaitForExit();
int exitCode = process.ExitCode;
if (!string.IsNullOrWhiteSpace(standardOutput))
args.Logger?.ILog($"Standard Output:\n{standardOutput}");
if (!string.IsNullOrWhiteSpace(standardError))
args.Logger?.WLog($"Standard Error:\n{standardError}");
args.Logger?.ILog($"Exit Code: {exitCode}");
return exitCode == 0 ? 1 : 2;
}
catch (Exception ex)
{
args.FailureReason = "Failed executing SH script: " + ex.Message;
args.Logger?.ELog(args.FailureReason);
return -1;
}
finally
{
try
{
if (System.IO.File.Exists(shFile))
{
System.IO.File.Delete(shFile);
args.Logger?.ILog($"Temporary SH file deleted: {shFile}");
}
}
catch (Exception ex)
{
args.Logger?.WLog($"Failed to delete temporary SH file: {shFile}. Error: {ex.Message}");
}
}
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.