Powershell从被调用的脚本运行cmdlet

我有一个脚本调用另一个脚本(带参数) . 被调用的脚本包含 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 EDIT: 此脚本在使用Sapien PowerShell Studio构建的GUI中运行 . 当我将构建类型更改为"Native"时,它可以工作 . 我必须重置我的实验室进行检查,但我怀疑如果我只是在x64上下文中运行它也会运行 . This文章解释了为什么我认为这很重要 .

在Windows Server 2012 R2上运行

回答(3)

2 years ago

除非你有一个令人信服的理由,让我们看看我们是否可以稍微清理你的呼叫模式 - 并希望通过避免扭曲来使你的其他问题消失 .

而不是将参数列表创建为字符串,而是利用parameter splatting . 它's good to get out of the habit of treating PowerShell like other scripting languages that don'吨与对象一起工作 .

$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

一旦你've got that, there'可能没有理由在调用Install-WindowsFeature时使用Invoke-Command,除非你遗漏了远程调用服务器等细节 . Invoke-Command 在使用PowerShell 5的Server 2012R2上仍适用于我,并且's no reason it shouldn' t .

这假设您在支持Install-WindowsFeature的服务器上运行此脚本,正如其他评论所指出的那样 . 客户端Windows不支持Install-WindowsFeature,RSAT工具通过独立的RSAT .MSU软件包安装,您可以采用不同的方式进行管理 .

安装-WindowsFeature本身随Server 2012R2上的服务器管理器一起提供 - 除非您对您的配置文件做了某些事情或者对您的模块文件夹造成了污染,否则不需要导入模块 . 其中一个早期版本的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,并且有很多理由不这样做 .

  • 服务器管理器和其他几个工具(包括Win32_ServerFeature)依赖于Install-WindowsFeature使用的WMI提供程序解析和理解的功能状态 . 可以使用DISM启用正确的功能集,但需要注意和细节 . 仅启用角色和功能的"part"可能会获得特定情况下所需的功能,但角色或功能可能不会显示在Get-WindowsFeature中,可能无法通过Remove-WindowsFeature卸载,并且可能无法提供相关的UI功能在服务器管理器中,例如监视角色的 Health 状况,查看相关事件或提供管理它的工具 .

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

  • DISM功能名称往往比服务器管理器的角色和功能名称更频繁地更改,因此您的脚本可移植性会更好 .
    还有其他一些观点,但我不会介绍它们,因为DISM主要是一个评论分叉 .

2 years ago

你可能是对的,似乎脚本是用 x86 PowerShell执行的 . 我想与您共享一个片段,我将其用于需要在特定环境中运行的脚本(例如x64 PowerShell) .

如果脚本以x86进程启动,则脚本将在 x64 PowerShell中重新启动 . 只需将它放在脚本的顶部:

# 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

2 years ago

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

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