Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell running a cmdlet from a called script

Tags:

powershell

I have a script that calls another script (with arguments). The called script contains the Install-WindowsFeature cmdlet. When I run the script, the called script runs, but returns the following error:

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

Of course, I can run the cmdlet just fine from a PowerShell console. I can also run the called script from a PowerShell console and Install-WindowsFeature works fine. So, is it something to do with calling a script from a script that runs a cmdlet? Here is my calling code:

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

In the called script, I called Install-WindowsFeature as below:

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

I've also tried it as below:

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

12/16/16 EDIT: This script is running in a GUI built with Sapien PowerShell Studio. When I change the build type to "Native" it works. I have to reset my lab to check, but I suspect it will also run if I just run it in the x64 context. This article explains why I think this matters.

Running on Windows Server 2012 R2

like image 966
McKenning Avatar asked Nov 10 '16 23:11

McKenning


People also ask

How do I run a Commandlet in PowerShell?

Run an old-fashioned command line (cmd.exe), type powershell and execute. Or, you can hit the PowerShell icon on the taskbar. Either way, you'll get a ready-to-use Windows PowerShell console. Use “Get-Help” cmdlet from before as a starting point for your journey.

How do I run a PowerShell script from another script?

PowerShell scripts can run other scripts. Just put the command that runs the second script as a command in the first script (the same way as you would type it on the PowerShell command line).

Which cmdlet runs scripts in PowerShell?

The Set-ExecutionPolicy cmdlet enables you to determine which Windows PowerShell scripts will be allowed to run on your computer.

How do I run a PowerShell script from the command line with parameters?

You can run scripts with parameters in any context by simply specifying them while running the PowerShell executable like powershell.exe -Parameter 'Foo' -Parameter2 'Bar' . Once you open cmd.exe, you can execute a PowerShell script like below.


2 Answers

Unless you've got a compelling reason for it, let's see if we can clean up your calling pattern a bit - and hopefully make your other issues go away by avoiding the contortionism.

Rather than creating your parameter list as a string, take advantage of parameter splatting. It's good to get out of the habit of treating PowerShell like other scripting languages that don't work with objects.

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

& c:\path\script.ps1 @splat

Using that on a script.ps1 something like this:

param(
    $Arg1,
    $Arg2,
    $Arg3
)

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

You'll get an expected output of:

Arg1 = value1, Arg2 = value2, Arg3 = value3

Once you've got that, there's probably no reason to use Invoke-Command on the call to Install-WindowsFeature, unless you're leaving out details like invoking remotely to a server. Invoke-Command { Install-WindowsFeature } still works fine for me on Server 2012R2 with PowerShell 5, and there's no reason it shouldn't.

This assumes you're running this script on a Server that support Install-WindowsFeature, as the other comments point out. Client Windows doesn't support Install-WindowsFeature, and the RSAT tools are installed via a stand-alone RSAT .MSU package, which you manage differently.

Install-WindowsFeature is natively provided with Server Manager on Server 2012R2 - there's no need to Import-Module... unless you've done something to your profile or fouled up your modules folders. One of the earlier versions of Windows Server needed it - but that was a couple versions back. Likewise, Add-WindowsFeature was the old name - and it's still available as an alias for Install-WindowsFeature.

I'm assuming you've tried Install-WindowsFeature directly from the command line to ensure it's in working order, and Get-Module Install-WindowsFeature looks reasonable.

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

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

While we're on the topic, there's very little reason to drop to DISM on Server that supports Install-WindowsFeature, and a number of reasons not to.

  1. Server Manager and several other tools (including Win32_ServerFeature) rely on the feature states parsed and understood by the WMI provider used by Install-WindowsFeature. It's possible to enable the right set of features using DISM, but needs attention and detail. Enabling only "part" of a role and feature may get the functionality you want for specific cases, but the role or feature may not show up as installed in Get-WindowsFeature, may not be uninstallable via Remove-WindowsFeature, and may not offer relevant UI features in Server Manager like monitoring health of the role, viewing relevant events, or offering tools for administering it.

  2. Install-WindowsFeature integrates with additional code from the role & features you're installing, and may run additional health and pre-requisite checks to ensure your correctly configured.

  3. DISM featurenames tend to change more often than the role & feature name of Server Manager, so your script portability will be better.
    There are other points, but I won't go into them since DISM was primarily a comment fork.
like image 152
Matthew Wetmore Avatar answered Nov 09 '22 03:11

Matthew Wetmore


You are probably right, it seems like the script gets executed with x86 PowerShell. I want to share a snippet with you which I use for scripts that needs to run in a specific environment (e. g. x64 PowerShell).

The script restarts itself in a x64 PowerShell if its started as x86 process. Just put this at the top of your script:

# 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
}

Also note that the Install-WindowsFeature cmdlet doesn't work on all windows versions so consider to use dism instead:

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

$dismParameter = @('/online', '/Enable-Feature', ($featuresToInstall | % { '/FeatureName:{0}' -f $_ }), '/NoRestart')
dism @dismParameter
like image 36
Martin Brandl Avatar answered Nov 09 '22 04:11

Martin Brandl