Trying to use a powershell script with a function as follows:
function MoveCompressFiles{
Param
(
[Parameter(Mandatory=$true )]
[string] $Des,
[Parameter(Mandatory=$true)]
[string] $Src
)
Add-Type -AssemblyName System.Drawing
$files = Get-ChildItem $Src
foreach ($f in $files) {
if (($f.Length / 1KB) -lt [int32]200) {
Copy-Item -Path $f.FullName -Destination $Des
}
else {
Copy-Item -Path $f.FullName -Destination $Des
while (((Get-Item (($Des).ToString() + "\$f")).Length / 1KB ) -gt 500) {
$img = [System.Drawing.Image]::FromFile((($Des).ToString() + "$f"))
[int32]$new_width = $img.Width * (20 / 100);
[int32]$new_height = $img.Height * (20 / 100);
$img2 = New-Object System.Drawing.Bitmap($new_width, $new_height)
$graph = [System.Drawing.Graphics]::FromImage($img2)
$graph.DrawImage($img, 0, 0, $new_width, $new_height)
$newImgName = "M".ToString() + $f.ToString()
$img2.Save(($Des).ToString()+"\$newImgName")
$img.Dispose()
$img2.Dispose()
Remove-Item ($Des.ToString()+$f)
Rename-Item -Path ($Des.ToString()+$newImgName) -NewName "$f"
Write-Host ((Get-Item ($Des.ToString()+$f)).Length / 1KB )
}
$filesize = $f.Length * 0.8
$filesize=($filesize / 1KB)
#$filesize = [math]::round(($filesize / 1KB), 0)
$abc = "KB"
$filesizeSTR = $filesize.ToString() + $abc
Push-Location $Src
mogrify -path $Des -define jpeg:extent=$filesizeSTR $f
Pop-Location
Write-Host "Moved file $f"
}
}
}
Works in Powershell, however when i try to do it it in my solution,
private static void Powershell()
{
string SCRIPT_PATH = System.IO.File.ReadAllText(@"C:\Untitled2.ps1");
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(SCRIPT_PATH);
ps.Invoke();
ps.AddCommand("MoveCompressFiles").AddParameters(new Dictionary<string, string>
{
{"Des" , @"C:\Des"},
{"Src", @"C:\Src"}
});
}
}
It doesn't work, I've tried some other methods of calling a function from a ps script but it still fails to even move the files to another location
Since you need to dot-source your script file (. <script>
) in order to make the MoveCompressFiles
function available, which requires an .AddScript()
call,
I suggest constructing a single piece of PowerShell code in a string variable that both dot-sources the script and invokes your function via a single .AddScript()
call.
However, in order to guarantee that .AddScript()
works, you must first ensure that the PowerShell execution policy allows script invocation, using a call to Set-ExecutionPolicy
; the code below uses -Scope Process
, so as to limit the change to the current process.
var SCRIPT_PATH = @"C:\Untitled2.ps1";
var src = @"C:\Src";
var des = @"C:\Des";
var script = $@". ""{SCRIPT_PATH}""; MoveCompressFiles -Des ""{des}"" -Src ""{src}""";
using (PowerShell ps = PowerShell.Create())
{
// Make sure that script execution is allowed.
ps.AddCommand("Set-ExecutionPolicy")
.AddParameter("Scope", "Process")
.AddParameter("ExecutionPolicy", "Bypass")
.AddParameter("Force", true);
ps.Invoke();
// Add the PowerShell code constructed above and invoke it.
ps.AddScript(script);
// Use foreach (var o in ps.Invoke()) { Console.WriteLine(o); } to print the output.
ps.Invoke();
}
Note the simplified, implicit runspace creation, by using PowerShell.Create()
only.
The embedded PowerShell code dot-sources your script file (. <script>
) in order to define the MoveCompressFiles
function, and then invokes the function.
Note that the above, as your own code, doesn't capture or print the output from the PowerShell code (.Invoke()
's output).
To see if errors occurred, you can check ps.HadErrors
and examine ps.Streams.Error
or any of the other streams, such as .ps.Streams.Information
for the Write-Host
output (the success stream's output is what .Invoke()
returns directly).
For instance, use something like the following to print all errors (messages only) that occurred to the console's standard error stream:
foreach (var o in ps.Streams.Error) {
Console.Error.WriteLine(o);
}
As for what you tried:
ps.AddScript(SCRIPT_PATH); ps.Invoke();
While this executes your script, it does so in a child scope, so the embedded function MoveCompressFiles
definition is not added to your session's top-level scope, so the subsequent .AddCommand()
call fails, because the MoveCompressFiles
function isn't available.
Instead, you must dot-source your script (. <script>
), which makes it run in the caller's scope and therefore makes its function definition available there.
As an aside: Despite the .AddScript()
method's name, its primary purpose is to execute a piece of PowerShell code, not a script file.
To execute the latter (without dot-sourcing), use .AddCommand()
.