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

如何替换PowerShell函数并在新函数中调用旧版本?

解决PowerShell替换函数后调用旧版本失效的问题

我尝试替换PowerShell的Invoke-RestMethod函数为带缓存功能的新版本,想在新函数内部调用旧版本,但执行时发现$oldInvoke.Invoke实际调用的是新版本而非旧版本,无法实现预期的缓存效果。

我的场景是为Web请求添加缓存,编写的代码如下:

$global:useCache = $true
$oldInvoke = ${function:Invoke-RestMethod}

function Remove-CachedRequests {
    $cachePath = "C:\tmp\Cache"
    Get-ChildItem -Path $cachePath -Include *.* -File -Recurse | foreach { $_.Delete()}
}

function Invoke-RestMethod {
    Param($Uri, $Method, $Headers)
    if ($global:useCache) {
        return _InvokeWithCache $Uri $Method $Headers
    }
    return _InvokeWithoutCache $Uri $Method $Headers
}

function GetFilename {
    Param($Uri, $Method, $Headers)
    $md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $bytes = [Text.Encoding]::ASCII.GetBytes($Uri + $Method + $Header)
    return [System.BitConverter]::ToString($md5.ComputeHash($bytes))
}

function _InvokeWithoutCache {
    Param($Uri, $Method, $Headers)
    return $oldInvoke.Invoke(@{"Uri" = $url; "Method" = $Method; "Headers" = $Headers})
}

function _InvokeWithCache {
    Param($Uri, $Method, $Headers)
    $cachePath = "C:\tmp\Cache"
    $filename = GetFilename $Uri $Method $Headers
    $cache = Get-ChildItem -Filter $filename -Path $cachePath
    if ($cache.Length -gt 0) {
        return Import-Clixml $cache[0]
    }
    $res = _InvokeWithoutCache $Uri $Method $Headers
    $res | Export-Clixml "${cachePath}\${filename}"
    return $res
}

问题原因

  1. 调用方式错误:用${function:Invoke-RestMethod}获取的旧函数是ScriptBlock对象,直接调用Invoke()方法时,执行上下文仍会使用当前作用域的函数定义,导致递归调用新版本的Invoke-RestMethod,而非原始内置命令。
  2. 参数名错误:_InvokeWithoutCache里把参数$Uri写成了$url,会导致参数传递失败。
  3. 变量名错误:GetFilename里的$Header应为$Headers,会导致哈希计算错误。

解决方案

方法一:用&操作符调用旧ScriptBlock

修改_InvokeWithoutCache函数,用&操作符执行保存的旧函数脚本块,同时修正参数名:

function _InvokeWithoutCache {
    Param($Uri, $Method, $Headers)
    # 使用&操作符确保调用原始版本的函数
    & $oldInvoke -Uri $Uri -Method $Method -Headers $Headers
}

方法二:直接获取原始Cmdlet对象

如果需要更彻底的隔离,直接获取Invoke-RestMethod的原始Cmdlet命令对象,避免上下文干扰:

# 替换旧函数的赋值语句,获取原始Cmdlet
$oldInvoke = Get-Command Invoke-RestMethod -CommandType Cmdlet

function _InvokeWithoutCache {
    Param($Uri, $Method, $Headers)
    # 调用原始Cmdlet的Invoke方法
    $oldInvoke.Invoke(@($Uri), @{ Method = $Method; Headers = $Headers })
}

修正其他错误

同时修复GetFilename里的变量名错误:

function GetFilename {
    Param($Uri, $Method, $Headers)
    $md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    # 修正$Header为$Headers
    $bytes = [Text.Encoding]::ASCII.GetBytes($Uri + $Method + $Headers)
    return [System.BitConverter]::ToString($md5.ComputeHash($bytes))
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:54:52