繁体   English   中英

从 C# 运行 PowerShell 脚本时出现错误“无法将参数绑定到参数‘Name’,因为它为空”

[英]Error "Cannot bind argument to parameter 'Name' because it is null" when running PowerShell script from C#

AFAIK,将 Office 365 邮箱类型更改为共享的唯一方法是通过 Exchange Online Powershell,看到我必须从 ASP.NET Core 3.1 web 应用程序这样做,我已经实现了以下内容:

从 C# 运行 PowerShell 脚本的方法:

public async Task<List<string>> RunScript(string script, Dictionary<string, object> parameters)
{
    var result = new List<string>();
    PowerShell ps = null;
    try
    {
        ps = PowerShell.Create();
        ps.AddScript(script);
        ps.AddParameters(parameters);
        var pipeline_objs = await ps.InvokeAsync().ConfigureAwait(false);
        foreach (var item in pipeline_objs)
        {
            result.Add(item.BaseObject.ToString());
        }
    }
    catch (Exception ex)
    {
        
        throw;
    }
    finally
    {
        if (ps != null)
        {
            ps.Dispose();
        }
    }
    return result;
}

方法调用如下:

async Task GetMailboxDataAsync()
{
    var script = //Script content
    var parameters = new Dictionary<string, object>
    {
        { "$username", "user@domain.org" },
        { "$password", "password" },
        { "$principal", "user2@domain.org" },
        { "$organization", "domain.onmicrosoft.com" }
    };
    var result = await RunScript(script, parameters);
    result.Dump();
}

PowerShell 我正在尝试运行的脚本(请注意,出于测试目的,我实际上并没有使用Set-EXOMailbox ,只是暂时运行Get-EXOMailbox ):

Param($username,$password,$organization,$principal)
Import-Module ExchangeOnlineManagement
$secured_password = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($username, $secured_password)
Connect-ExchangeOnline -UserPrincipalName $username -DelegatedOrganization $organization -Credential $cred -ShowBanner:$false
Get-EXOMailbox -Identity $principal
Disconnect-ExchangeOnline -Confirm:$false

硬编码 PowerShell 脚本中的值并按预期在命令行中运行它,但从 C# 调用它(即使使用硬编码参数)会返回以下RuntimeExceptionCannot bind argument to parameter 'Name' because it is null. 。。 ScriptStackTrace 属性说:

at Disconnect-ExchangeOnline<Process>, C:\Users\[OMITTED]\Documents\PowerShell\Modules\ExchangeOnlineManagement\2.0.5\netCore\ExchangeOnlineManagement.psm1: line 666
at <ScriptBlock>, <No file>: line 7

我错过了什么?

它在命令行上运行的事实表明它可能是主机应用程序 (3.1) 的 .NET 版本的问题。 您可以尝试使用 Invoke-Command 包装脚本,它可能会利用 Powershell 和 .NET 的最新版本。这是我最近用来从 .NET 主机应用调用 EXO V2 cmdlet 的模式。 我添加了一些额外的错误处理和多线程,以便 PS 远程处理异常不会逃逸到主机应用程序。

$result = $null

# Outer try-catch.
try {

    # Run the script asynchronously. Please note that script blocks must be self-contained,
    # meaning you must pass parameters to them and define all functions inside them.
    Start-Job -Name "$i" -ArgumentList @($username,$password,$organization,$principal) -ScriptBlock {
        param($username,$password,$organization,$principal)

        $result = $null
            
        # Try-catch inside async script.
        try {

            # Another self-contained script block inside Invoke-Command.
            $result = Invoke-Command -ComputerName localhost -ErrorAction Stop `
            -ArgumentList @($username,$password,$organization,$principal) `
            -ScriptBlock {

                <# BEGIN Original script, with edits. #>
                Param($username,$password,$organization,$principal)
                Import-Module ExchangeOnlineManagement
                $secured_password = ConvertTo-SecureString $password -AsPlainText -Force
                $cred = New-Object System.Management.Automation.PSCredential ($username, $secured_password)
                Connect-ExchangeOnline -UserPrincipalName $username -DelegatedOrganization $organization -Credential $cred -ShowBanner:$false
                $result = Get-EXOMailbox -Identity $principal
                # This should allow the script to continue without interruption, 
                # but any remoting exceptions could still escape to the .NET host app.
                try { Disconnect-ExchangeOnline -Confirm:$false -ErrorAction Stop } catch { $Error.Clear() }
                <# END Original script, with edits. #>

                return $result

            }

        } catch {
            Write-Warning ($_ | Out-String) # Do NOT use Write-Error!
            $Error.Clear()
        }

        return $result

    } | Out-Null

    # Wait for the job to finish and get the result.
    $jobs = Get-Job
    while($jobs) {
        $job = $jobs | Wait-Job -Any
        $result = $job | Receive-Job
        $job | Remove-Job
        $jobs = Get-Job
    }

} catch {
    Write-Warning ($_ | Out-String) # Do NOT use Write-Error (unless you want certain exceptions to bubble up, of course).
    $Error.Clear()
}

return $result

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM