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

为什么我的powershell函数无法从C#调用?,c#,powershell,powershell-sdk,C#,Powershell,Powershell Sdk,尝试使用具有以下函数的powershell脚本: function MoveCompressFiles{ Param ( [Parameter(Mandatory=$true )] [string] $Des, [Parameter(Mandatory=$true)] [string] $Src ) Add-Type -AssemblyName System.Drawing $files = Ge

尝试使用具有以下函数的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"}
                });
            }
     }
private static void Powershell()
{
字符串脚本_PATH=System.IO.File.ReadAllText(@“C:\Untitled2.ps1”);
使用(Runspace Runspace=RunspaceFactory.CreateRunspace())
{
Open();
PowerShell ps=PowerShell.Create();
ps.运行空间=运行空间;
ps.AddScript(脚本路径);
ps.Invoke();
ps.AddCommand(“MoveCompressFiles”).AddParameters(新字典
{
{“Des”@“C:\Des”},
{“Src”,@“C:\Src”}
});
}
}
它不起作用,我尝试了从ps脚本调用函数的一些其他方法,但它仍然无法将文件移动到另一个位置,因为您需要修改脚本文件(
),以便使
MoveCompressFiles
函数可用,这需要调用
.AddScript()
, 我建议在一个字符串变量中构造一段PowerShell代码,该字符串变量既是点源脚本,又通过一个
.AddScript()
调用调用您的函数

但是,为了保证
.AddScript()
能够正常工作,您必须首先通过调用
设置执行策略来确保允许脚本调用;下面的代码使用
-范围流程
,以限制对当前流程的更改

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代码点源于脚本文件(
),以定义
MoveCompressFiles
函数,然后调用该函数

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

要查看是否发生了错误,您可以检查
ps.haderors
并检查
ps.Streams.Error
或任何其他流,例如
.ps.Streams.Information
写入主机输出(成功流的输出是
.Invoke()
直接返回的)

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

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

至于你所尝试的

ps.AddScript(脚本路径);ps.Invoke()

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

相反,您必须使用脚本(
),它使脚本在调用方的作用域中运行,从而使其函数定义在调用方的作用域中可用

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