PowerShell传递SPFeatureScope参数报错:字符无法转为该类型
这个错误的根源是**Invoke-Command的作用域隔离导致变量没有正确传递**,进而让你的$featureUpgradeOrder数组在脚本块内部被错误解析,最终$featureInfo[1]拿到的是字符"w"(来自SPFeatureScope::Web的字符串表示"Web"的第二个字符),而非预期的枚举值。
问题分析
你在调用Execute-Safely时,脚本块直接引用了外部的$site和$featureUpgradeOrder变量,但Invoke-Command会创建一个新的作用域,默认不会继承父作用域的变量。这导致脚本块内部的$featureUpgradeOrder没有正确获取到你定义的二维数组,反而被意外解析成了字符串或其他结构,最终在遍历的时候拆分成了单个字符。
解决方案
有几种简单的修复方式,选最适合你的一种即可:
方案1:移除不必要的Invoke-Command
因为你是本地执行脚本块,完全不需要用Invoke-Command,直接用&运算符执行脚本块就能继承当前作用域的变量。修改Execute-Safely函数:
function Execute-Safely { param( [ScriptBlock]$scriptBlock, [string]$action ) try { & $scriptBlock # 直接执行脚本块,保留变量作用域 } catch { Write-Error ("An error occurred when executing [{0}]" -f $action) Write-Error $_ } }
这样你的原有调用代码不需要任何修改,就能正确传递数组变量。
方案2:使用$using:前缀传递变量
如果你一定要保留Invoke-Command,可以在脚本块中用$using:前缀引用父作用域的变量:
Execute-Safely -scriptBlock { Upgrade-FeaturesInSite -site $using:site -featureUpgradeOrder $using:featureUpgradeOrder } -action "Activating site features"
$using:前缀会告诉PowerShell从调用者的作用域中获取变量值,避免作用域隔离导致的变量丢失。
方案3:通过-ArgumentList传递参数
另一种更严谨的方式是给Invoke-Command显式传递参数,修改Execute-Safely函数和调用代码:
function Execute-Safely { param( [ScriptBlock]$scriptBlock, [string]$action, [object[]]$arguments ) try { if ($arguments) { Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $arguments } else { Invoke-Command -ScriptBlock $scriptBlock } } catch { Write-Error ("An error occurred when executing [{0}]" -f $action) Write-Error $_ } } # 调用时传递参数 Execute-Safely -scriptBlock { param($site, $featureUpgradeOrder) Upgrade-FeaturesInSite -site $site -featureUpgradeOrder $featureUpgradeOrder } -action "Activating site features" -arguments $site, $featureUpgradeOrder
这种方式明确传递变量,避免作用域问题,适合复杂场景。
验证修复
修复后,$featureUpgradeOrder会正确传递到Upgrade-FeaturesInSite函数,$featureInfo[1]会拿到Microsoft.SharePoint.SPFeatureScope::Web枚举值,不会再出现字符转换错误。
内容的提问来源于stack exchange,提问作者Luis Valencia

