【问题标题】:Powershell running a cmdlet from a called scriptPowershell 从调用的脚本运行 cmdlet
【发布时间】:2016-11-10 23:36:41
【问题描述】:

我有一个脚本调用另一个脚本(带参数)。被调用的脚本包含Install-WindowsFeature cmdlet。当我运行脚本时,被调用的脚本运行,但返回以下错误:

Install-WindowsFeature : The term 'Install-WindowsFeature' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path

当然,我可以从 PowerShell 控制台很好地运行 cmdlet。我还可以从 PowerShell 控制台运行调用的脚本,Install-WindowsFeature 工作正常。那么,这与从运行 cmdlet 的脚本调用脚本有关吗?这是我的调用代码:

$script = "C:\Path\script.ps1"
$argumentList = @()
$argumentlist += ("-Arg1", "value")
$argumentlist += ("-Arg2", "value")
$argumentlist += ("-Arg3", "value")
Invoke-Expression "$script $argumentList"

在被调用的脚本中,我调用了Install-WindowsFeature,如下:

if ($someValue) { Invoke-Command -ScriptBlock {Install-WindowsFeature -Name RSAT-AD-Tools} }

我也试过如下:

if ($someValue) { Install-WindowsFeature -Name RSAT-AD-Tools }

12/16/16 编辑:此脚本在使用 Sapien PowerShell Studio 构建的 GUI 中运行。当我将构建类型更改为“本机”时,它可以工作。我必须重置我的实验室才能检查,但我怀疑如果我只是在 x64 上下文中运行它,它也会运行。 This 文章解释了为什么我认为这很重要。

在 Windows Server 2012 R2 上运行

【问题讨论】:

  • 以管理员身份运行?或者也许提供凭据来运行它? Invoke-Command -Credential
  • @Kage 我也试过了。不确定该 cmdlet 是否只是不可见或者是否会给出拒绝访问错误,但无论如何行为都是相同的。
  • 您是否尝试在 if 语句之前在 script.ps1 中运行 import-module servermanager
  • @TonyHinkle 刚回到这个项目并将命令添加到 script.ps1 并给出错误“未加载指定的模块'ServerManager',因为在任何模块目录中都找不到有效的模块文件。”就像脚本的运行上下文看不到环境/文件系统一样。
  • 我现在不知道该建议什么。我没有测试服务器来尝试复制它。我会为此悬赏,以便引起注意。

标签: powershell


【解决方案1】:

除非你有一个令人信服的理由,否则让我们看看我们是否可以稍微清理你的调用模式 - 并希望通过避免扭曲来解决你的其他问题。

与其将参数列表创建为字符串,不如利用parameter splatting。摆脱将 PowerShell 视为其他不能处理对象的脚本语言的习惯是件好事。

$splat = @{ 
    Arg1 = "value1";
    Arg2 = "value2";
    Arg3 = "value3"
    }

& c:\path\script.ps1 @splat

在 script.ps1 上使用它:

param(
    $Arg1,
    $Arg2,
    $Arg3
)

Write-Host "Arg1 = $Arg1, Arg2 = $Arg2, Arg3 = $Arg3

你会得到预期的输出:

Arg1 = value1, Arg2 = value2, Arg3 = value3

一旦你明白了,可能没有理由在调用 Install-WindowsFeature 时使用 Invoke-Command,除非你省略了调用等细节远程到服务器。 Invoke-Command { Install-WindowsFeature } 在使用 PowerShell 5 的 Server 2012R2 上对我来说仍然可以正常工作,而且没有理由不这样做。

这假设您在支持 Install-WindowsFeature 的服务器上运行此脚本,正如其他 cmets 指出的那样。客户端 Windows 不支持 Install-WindowsFeature,并且 RSAT 工具是通过独立的 RSAT .MSU ​​包安装的,您以不同的方式管理。

Install-WindowsFeature 在 Server 2012R2 上随服务器管理器原生提供 - 无需Import-Module...除非您已对您的个人资料或弄脏了你的模块文件夹。 Windows Server 的早期版本之一需要它 - 但那是几个版本。同样,Add-WindowsFeature 是旧名称 - 它仍然可以作为 Install-WindowsFeature 的别名使用。

我假设您已直接从命令行尝试 Install-WindowsFeature 以确保其正常工作,并且 Get-Module Install-WindowsFeature 看起来是合理的。

PS C:\Windows\system32> get-module ServerManager

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     2.0.0.0    ServerManager                       {Get-WindowsFeature, Install-WindowsFeature, Uninstall-Win...

虽然我们正在讨论这个主题,但几乎没有理由在支持 Install-WindowsFeature 的服务器上使用 DISM,并且有很多理由不这样做。

  1. 服务器管理器和其他几个工具(包括 Win32_ServerFeature)依赖于由 Install-WindowsFeature 使用的 WMI 提供程序解析和理解的功能状态。 可能使用 DISM 启用正确的功能集,但需要注意和细节。仅启用角色和功能的“部分”可能会在特定情况下获得您想要的功能,但角色或功能可能不会显示为已安装在 Get-WindowsFeature 中,可能无法通过 Remove-WindowsFeature 卸载,并且可能不提供相关服务器管理器中的 UI 功能,例如监控角色的健康状况、查看相关事件或提供管理它的工具。

  2. Install-WindowsFeature 与您正在安装的角色和功能中的其他代码集成,并且可能会运行其他运行状况和先决条件检查以确保正确配置。

  3. DISM 功能名称的更改往往比服务器管理器的角色和功能名称更频繁,因此您的脚本可移植性会更好。
    还有其他要点,但我不会深入讨论,因为 DISM 主要是一个评论分支。

【讨论】:

  • 我是 Install-WindowsFeature 的开发经理,所以你遇到的麻烦让我很吃惊。我回来看看我们能做些什么来解决你的问题。
  • 你好,马修。感谢您对此的关注。澄清一下,Install-WindowsFeature 在命令提示符下工作正常。只有在 x32 模式下运行脚本时才会中断(因为 x64 工作正常)。当 Import-Module 也不起作用时,我被告知了这一点。另外,我同意由于 DISM 更像是一个遗留工具,因此 Install-WindowsFeature 更可取。
  • 我认为确实如此 - 通过简化您的调用模式,您可以避免最终进入 x86 进程,或者至少减少移动部件并使任何错误变得更加明显。 :)
  • @McKenning,如果你弄清楚你是如何进入 x86 的,我仍然想听听你的回复。这不应该发生,除非您遗漏了代码。我建议消除 Invoke-Command,因为这是唯一可能导致您的问题的部分。
  • 我还不能就其他答案向 Martin 发表评论,但也想指出使用 DISM 安装服务器功能的另一个缺点。服务器管理器和 Win32_ServerFeature (WMI) 都依赖于相同的机制来确定系统上安装的内容。最终这要归于 DISM,但要启用 正确 的 DISM 功能集是很棘手的,因此我们认为角色/功能的相互关联的依赖关系已正确启用。您最终可以拥有部分功能,但服务器管理器可能不会显示已安装的角色或提供其管理和监控工具。
【解决方案2】:

您可能是对的,似乎脚本是使用 x86 PowerShell 执行的。我想与您分享一个 sn-p,我将其用于需要在 特定环境(例如 x64 PowerShell)中运行的脚本。

脚本在 x64 PowerShell 中重新启动 自身 如果它以 x86 进程启动。只需将其放在脚本的顶部即可:

# Reinvoke the script as x64 if its called from a x86 process.
if ($env:Processor_Architecture -eq "x86")
{
    &"$env:windir\sysnative\WindowsPowerShell\v1.0\powershell.exe" -noprofile -file $myinvocation.Mycommand.path -executionpolicy bypass
    exit
}

另请注意,Install-WindowsFeature cmdlet 不适用于所有 Windows 版本,因此请考虑改用 dism

$featuresToInstall = @('RSAT-AD-Tools')

$dismParameter = @('/online', '/Enable-Feature', ($featuresToInstall | % { '/FeatureName:{0}' -f $_ }), '/NoRestart')
dism @dismParameter

【讨论】:

  • Install-WindowsFeature 之前,有 Add-WindowsFeature(适用于 Windows Server 2008 R2)。使用 dism 仅适用于不受支持的 Windows Server 2008 及更早版本。如果您需要,这很好,但对于大多数环境Install-WindowsFeature 应该没问题。特别是因为随着越来越多的 PowerShell cmdlet 的推出,dism 实际上可能会成为未来版本中的渡渡鸟。
  • @JeroenMostert 在 Windows 10 中,没有 Install-WindowsFeature cmdlet,而是 Enable-WindowsOptionalFeature。这就是为什么我更喜欢使用 dism - 它只是安装功能最可靠的工具(根据我的经验)。
  • 对不起,没有考虑客户端操作系统(我只从跳转服务器管理)。不过,您甚至可以在 Windows 10 上安装 RSAT-AD-Tools 吗?
  • 我知道你来自哪里。同时,我仍然会坚持让人们在我运行我的脚本之前安装 PowerShell 5,而不是说,下降到 cmd,这将始终有效。 :-)(我在开玩笑,我确实明白你来自哪里。)
  • 只是为了插话,您可以通过为该操作系统安装一个 msu 在客户端操作系统(来自 win7)上安装 RSAT。我一直使用它来从跳转框管理域。另外,我很欣赏 Martin 共享的代码,用于基于架构重新调用。这肯定会派上用场。
【解决方案3】:

运行环境决定了您可以访问哪些模块。当我在 PowerShell Studio 中创建这个项目时,它采用了默认的 x86(32 位环境)。这行得通,但是因为我在 Windows Server 2012 R2(64 位环境)上运行它,所以我无法访问 Powershell 模块,例如 Import-Module 和 Install-WindowsFeature。将此更改为 x64 项目解决了我的问题。

为了避免这种情况,确保在操作系统原生的体系结构中运行 PowerShell 脚本和模块非常重要。您可以通过正确设置项目(如果使用 PowerShell Studio 之类的工具)或使用 Martin Brandl 提供的代码验证您是否在该操作系统的本机模式下运行来做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-28
    • 2017-06-01
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 2011-02-23
    • 2012-07-13
    • 2019-12-02
    相关资源
    最近更新 更多