You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 3.1调用PowerShell脚本获取DHCP ScopeID失败及版本指定问题

问题描述

我在.NET Core 3.1 Web应用中调用PowerShell脚本执行DHCP服务器任务,脚本用于为新DHCP保留查找对应的ScopeID。脚本在服务器的PowerShell ISE中运行完全正常,但在同一服务器的Web应用中运行时始终返回null。

脚本代码

$DhcpServer = 'MY_DHCP_SERVER'
$IPaddress = '10.140.98.143'
$ScopeId = $null

'PowerShell version: ' + [string]$PSVersionTable.PSVersion

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force

$all_scopes = Get-DhcpServerv4Scope -ComputerName $DhcpServer
if($all_scopes) {
    $number_of_scopes = $all_scopes.Count
    $counter = -1
    $hit_in_scope = $null

    Do {
        $counter = $counter+1
                                         
        If (([version]($all_scopes[$counter]).StartRange.IPAddressToString) -le ([version]$IPaddress) -and ([version]$IPaddress) -le ([version]($all_scopes[$counter]).EndRange.IPAddressToString))
        {
            $hit_in_scope = ($all_scopes[$counter]).ScopeID
        }

    } until ($counter -eq $number_of_scopes -or $hit_in_scope -ne $null)
    
    $ScopeId = $hit_in_scope.IPAddressToString
}

$ScopeId

PowerShell ISE中的输出

PowerShell version: 5.1.17763.2931
10.140.98.128

Web应用中运行脚本的日志

2022-11-01 13:43:00.643 +01:00 [DBG] results: System.Management.Automation.PSDataCollection`1[System.Management.Automation.PSObject]
2022-11-01 13:43:00.644 +01:00 [DBG] results.Count: 2
2022-11-01 13:43:00.644 +01:00 [DBG] resultString: PowerShell version: 7.0.5
2022-11-01 13:43:00.644 +01:00 [DBG] resultString: 
2022-11-01 13:43:00.674 +01:00 [ERR] PowerShell response is null or empty

.NET Core调用代码

private async Task<string> RunPowershellScriptWithReturnStringValue(string script, string errorMessage)
{
    string resultString = null;

    using (var psInstance = PowerShell.Create())
    {
        var results = await psInstance.AddScript(script).InvokeAsync();
        //psdatacollection<psobject>
        Log.Debug($"results: {results.ToString()}");
        Log.Debug($"results.Count: {results.Count}");
        if (results != null)
        {
            foreach (var psObject in results)
            {
                resultString = psObject != null ? psObject.ToString() : null;
                Log.Debug($"resultString: {resultString}");
            }
        }
        if (psInstance.HadErrors)
        {
            Log.Error(errorMessage);
            psInstance.LogErrors();
        }
    }
    if (string.IsNullOrEmpty(resultString))
    {
        Log.Error("PowerShell response is null or empty");
        Log.Debug("PowerShell script follows");
        Log.Debug(script);
    }
    return resultString;
}

我发现同一服务器上运行脚本时使用了不同的PowerShell版本,对此感到困惑。请问:

  1. 调用psInstance.AddScript(script).InvokeAsync()时能否指定使用的PowerShell版本?如何实现?
  2. 或者应该修改脚本使其适配PowerShell 7.0.5?如何修改?

解决方案

问题1:指定PowerShell版本执行脚本

可以指定PowerShell版本,核心思路是放弃直接用PowerShell.Create()创建实例,改为调用对应版本的PowerShell可执行文件运行脚本:

  1. 确认对应版本的可执行文件路径:
    • PowerShell 5.1:C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    • PowerShell 7.x:C:\Program Files\PowerShell\7\pwsh.exe
  2. 修改.NET Core代码,用Process类调用对应可执行文件:
private async Task<string> RunPowershellScriptWithSpecificVersion(string script, string errorMessage, string psExePath)
{
    var processStartInfo = new ProcessStartInfo
    {
        FileName = psExePath,
        Arguments = $"-NoProfile -ExecutionPolicy Unrestricted -Command \"{script}\"",
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        UseShellExecute = false,
        CreateNoWindow = true
    };

    using (var process = Process.Start(processStartInfo))
    {
        var output = await process.StandardOutput.ReadToEndAsync();
        var error = await process.StandardError.ReadToEndAsync();
        await process.WaitForExitAsync();

        if (!string.IsNullOrEmpty(error))
        {
            Log.Error($"{errorMessage}: {error}");
            return null;
        }

        var resultLines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
        return resultLines.Length > 0 ? resultLines.Last() : null;
    }
}

调用时传入对应版本的路径即可:

// 调用PowerShell 5.1
var result = await RunPowershellScriptWithSpecificVersion(script, "DHCP脚本执行失败", @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe");

注意:需确保Web应用运行账户有执行该可执行文件的权限,且脚本操作(如访问DHCP服务器)的权限足够。

问题2:修改脚本适配PowerShell 7.0.5

脚本在PS7中返回null的核心原因是Get-DhcpServerv4Scope返回对象结构与PS5.1存在差异,且[version]处理IP地址的逻辑在PS7中有兼容性问题。修改后的脚本如下:

$DhcpServer = 'MY_DHCP_SERVER'
$IPaddress = '10.140.98.143'
$ScopeId = $null

'PowerShell version: ' + [string]$PSVersionTable.PSVersion

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force

# 显式加载DHCP模块(PS7中需手动加载)
Import-Module DhcpServer -ErrorAction Stop

$all_scopes = Get-DhcpServerv4Scope -ComputerName $DhcpServer
if($all_scopes) {
    # 将IP转换为UInt32数值,避免[version]的兼容性问题
    function Convert-IpToUInt32 {
        param([string]$IpAddress)
        $bytes = [System.Net.IPAddress]::Parse($IpAddress).GetAddressBytes()
        [Array]::Reverse($bytes)
        return [System.BitConverter]::ToUInt32($bytes, 0)
    }

    $targetIpUInt = Convert-IpToUInt32 -IpAddress $IPaddress

    foreach ($scope in $all_scopes) {
        $startIpUInt = Convert-IpToUInt32 -IpAddress $scope.StartRange.IPAddressToString
        $endIpUInt = Convert-IpToUInt32 -IpAddress $scope.EndRange.IPAddressToString
        
        if ($targetIpUInt -ge $startIpUInt -and $targetIpUInt -le $endIpUInt) {
            $ScopeId = $scope.ScopeID.IPAddressToString
            break # 找到结果后直接退出循环
        }
    }
}

$ScopeId

修改说明:

  1. 显式加载DhcpServer模块:PS7中部分模块不会自动加载,需手动导入确保命令可用;
  2. 替换IP比较逻辑:用UInt32数值比较替代[version]转换,避免版本间的兼容性问题,结果更可靠;
  3. 简化循环结构:用foreach替代Do-While,代码更简洁,同时避免索引越界风险。

内容的提问来源于stack exchange,提问作者Dudute

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 02:41:03