user8570495
user8570495

Reputation: 1835

how to execute powershell ps1 scripts from package.json "scripts"?

How can I execute PowerShell ps1 scripts from package.json "scripts"?

I know how to set up a basic script in package.json "scripts". For example with the following configuration, I can exec npm run test which will output "this is only a test" to the console:

"scripts": {
  "test": "echo \"this is only a test\""
}

However, I have a more advanced scenario where I'd like to execute a PowerShell script. Something like this:

"scripts": {
  "buildAngular": "buildAngular.ps1"
}

Can I exec a ps1 script like this via the scripts object? Is any special setup/config required? Are there any additional constraints?

Upvotes: 40

Views: 29337

Answers (4)

Dan Atkinson
Dan Atkinson

Reputation: 11699

Personally, I favour calling a .bat script and passing the .ps1 filename to execute as an argument. Obviously this will only work in Windows, so YMMV.

Inside the batch script, you can perform checks on whether PowerShell Core exists before falling back to 'native' PowerShell. You can also put your -NoProfile -ExecutionPolicy code in the batch script as well so it's a bit cleaner in the package.json file.

Package.json:

"scripts": {
  "test": "build-scripts\RunBuildScript.bat test"
}

RunBuildScript.bat:

@ECHO OFF

REM Check the argument passed in. You could also check if the file actually exists.
SET "NpmBuildScriptName=%1"
IF ["%NpmBuildScriptName%"] == [""] (
    ECHO "Could not find the name of the script."
    GOTO :TidyUp
)

REM Perform some checks for PowerShell Core in the file system.
FOR %%s IN ("PowerShell\pwsh.exe" "\PowerShellCore\pwsh.exe") DO (
    IF EXIST %%s (
        ECHO "PowerShell found at %%s"
        SET "PowerShellPath=%%s"
        GOTO :ExecuteScript
    )
)

REM If you can't find PowerShell, use the default.
IF ["%PowerShellPath%"] == [""] (
    ECHO "PowerShell Core was not found. Defaulting to native PowerShell"
    SET "PowerShellPath=powershell"
    GOTO :ExecuteScript
)

:ExecuteScript
    %PowerShellPath% -NoProfile -ExecutionPolicy Unrestricted -Command "%NpmBuildScriptName%.ps1"
    GOTO :TidyUp

:TidyUp
    REM Wipe after using.
    SET "NpmBuildScriptName="

ECHO 0

test.ps1

Write-Host "this is only a test"

Obviously a lot of hoops to jump through just to output some text, but this approach makes it a bit more extensible.

Upvotes: 0

kas
kas

Reputation: 1025

Prepend the PowerShell command with "powershell", e.g.,

"command": "powershell Remove-Item ..\\folder\\file; Copy-Item -Path folder\\* -Destination ..\\other-folder -Recurse",
"buildAngular": "powershell buildAngular.ps1"

Upvotes: 8

JeffRSon
JeffRSon

Reputation: 11176

You might set the script-shell config - either via npm config set script-shell "powershell" or environment variable $env:npm_config_script_shell="powershell"

Then you could use

"scripts": {
    "test": "Write-Host 'this is only a test'"
}

or

"scripts": {
    "buildAngular": ".\\buildAngular.ps1"
}

I'm not sure whether you can supply parameters like -NoProfile though.

Upvotes: 7

barnski
barnski

Reputation: 1732

Assuming powershell is in you PATH you can call it like this:

"scripts": {
    "test": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command ./test.ps1"
}

Tested on Windows 7 with Powershell v4.

Limitations are that you need Powershell installed and in your PATH. I didn't test it with Powershell for Linux, so not sure if this solution will be portable to other platform for now.

Upvotes: 79

Related Questions