Powershell从被调用的脚本

时间:2016-11-10 23:36:41

标签: powershell

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

在Windows Server 2012 R2上运行

3 个答案:

答案 0 :(得分:3)

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

不要将参数列表创建为字符串,而是利用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 ,除非你&# 39;重新省略远程调用服务器等细节。在使用PowerShell 5的Server 2012R2上, Invoke-Command {Install-WindowsFeature} 仍然可以正常使用,并且没有理由不应该这样做。

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

Install-WindowsFeature 本身随Server 2012R2上的服务器管理器一起提供 - 除非您已经导入模块 ...对您的个人资料做了一些事情或弄脏了您的模块文件夹。其中一个早期版本的Windows Server需要它 - 但这是几个版本。同样, Add-WindowsFeature 是旧名称 - 它仍然可用作 Install-WindowsFeature 的别名。

我假设您已直接从命令行尝试 Install-WindowsFeature 以确保其处于正常工作状态,并且获取模块安装 - 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启用正确的功能集,但需要注意和细节。仅启用" part"一个角色和功能可能会获得您想要的特定情况的功能,但角色或功能可能不会显示为Get-WindowsFeature中安装,可能无法通过Remove-WindowsFeature卸载,并且可能无法在服务器管理器中提供相关的UI功能比如监控角色的健康状况,查看相关事件或提供管理角色的工具。

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

  3. DISM功能名称的变化往往比角色和名称更频繁。服务器管理器的功能名称,因此您的脚本可移植性会更好 还有其他一些观点,但由于DISM主要是评论分支,我不会进入它们。

答案 1 :(得分:2)

你可能是对的,似乎脚本是用 x86 PowerShell执行的。我想与您共享一个片段,我将其用于需要在特定环境中运行的脚本(例如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

答案 2 :(得分:2)

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

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