为什么我的powershell函数无法从C#调用



尝试使用带有以下函数的powershell脚本:

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"
} 
}
}

在Powershell中工作,但是当我尝试在我的解决方案中这样做时

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"}
});
}
}

它不起作用,我尝试了一些从ps脚本调用函数的其他方法,但它甚至无法将文件移动到的另一个位置

由于您需要点源脚本文件(. <script>(以使MoveCompressFiles函数可用,这需要.AddScript()调用,我建议在字符串变量中构造一段PowerShell代码,该代码既可以点源于脚本,也可以通过单个.AddScript()调用调用函数。

但是,为了确保.AddScript()工作,您必须首先确保PowerShell执行策略允许脚本调用,使用对Set-ExecutionPolicy的调用;下面的代码使用-Scope 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();
}

请注意,通过仅使用PowerShell.Create(),简化的隐式运行空间创建

嵌入式PowerShell代码点源于脚本文件(. <script>(,以便定义MoveCompressFiles函数,然后调用该函数。

请注意,作为您自己的代码,上面的内容不会捕获或打印PowerShell代码的输出(.Invoke()的输出(。

要查看是否发生错误,可以检查ps.HadErrors并检查ps.Streams.Error或任何其他流,例如Write-Host输出的.ps.Streams.Information(success流的输出是.Invoke()直接返回的(。

例如,使用以下内容打印控制台标准错误流中发生的所有错误(仅消息(:

foreach (var o in ps.Streams.Error) {
Console.Error.WriteLine(o);
}

至于您尝试了什么

ps.AddScript(SCRIPT_PATH); ps.Invoke();

当这个执行脚本时,它是在子作用域中执行的,因此嵌入函数MoveCompressFiles定义是而不是添加到会话的顶级作用域中,因此后续的.AddCommand()调用失败,因为MoveCompressFiles函数不可用。

相反,您必须点源您的脚本(. <script>(,这使它在调用方的作用域中运行,从而使其函数定义在那里可用。

顺便说一句:尽管.AddScript()方法的名称,但它的主要目的是执行段PowerShell代码,而不是脚本文件。要执行后者(无点源(,请使用.AddCommand()

相关内容

  • 没有找到相关文章

最新更新