PowerShell support: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
(Initial version)
 
(No difference)

Revision as of 18:16, 7 January 2014

Author: CharlesB (talk, contrib)


Description

These macros simplify PowerShell use in NSIS, and overcomes a bug of PowerShell v2, [described here], and [reported here]).

PowerShellExec and PowerShellExecLog respectively the script output on the stack and in the log window The same goes for PowerShellExecFile and PowerShellExecFileLog, which are used to execute a PowerShell script file.

If execution fails, the error level is set to 2.

How to use

Save the script in a file named psexec.nsh, and place it next to your .nsi (or in the NSIS include directory). Then in your script, put an !include psexec.nsh, and call it like this

${PowerShellExec} "echo 'hello powershell'"  
Pop $R1 ;$R1 is "hello powershell"
 
InitPluginsDir
SetOutput $PLUGINSDIR\Powershell
File script.ps1
${PowerShellExecFileLog} "$PLUGINSDIR\Powershell\script.ps1"

In your PS commands, remember to escape the dollar sign by doubling it:

${PowerShellExec} "echo $$ProgramFiles"

Pitfalls

Be aware that as long as the installer is a 32 bit process, the PowerShell interpreter is also in 32 bit. This can cause redirections in filesystem, registry and environment variables when running or 64 bit systems (see https://en.wikipedia.org/wiki/WoW64)

Also I found that executing a file directly from $PLUGINSDIR caused errors in script execution, and that saving it in a $PLUGINSDIR subfolder prevented the errors.

The Script

!ifndef PSEXEC_INCLUDED
!define PSEXEC_INCLUDED
 
!include nsexec.nsh
 
!macro PowerShellExecMacro PSCommand
  InitPluginsDir
  ;Save command in a temp file
  Push $R1
  FileOpen $R1 $PLUGINSDIR\tempfile.ps1 w
  FileWrite $R1 "${PSCommand}"
  FileClose $R1
  Pop $R1
 
  !insertmacro PowerShellExecFileMacro "$PLUGINSDIR\tempfile.ps1"
!macroend
 
!macro PowerShellExecLogMacro PSCommand
  InitPluginsDir
  ;Save command in a temp file
  Push $R1
  FileOpen $R1 $PLUGINSDIR\tempfile.ps1 w
  FileWrite $R1 "${PSCommand}"
  FileClose $R1
  Pop $R1
 
  !insertmacro PowerShellExecFileLogMacro "$PLUGINSDIR\tempfile.ps1"
!macroend
 
!macro PowerShellExecFileMacro PSFile
  !define PSExecID ${__LINE__}
  Push $R0
 
  nsExec::ExecToStack 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "${PSFile}"  '
 
  Pop $R0 ;return value is first on stack
  ;script output is second on stack, leave on top of it
  IntCmp $R0 0 finish_${PSExecID}
  SetErrorLevel 2
 
finish_${PSExecID}:
  Exch ;now $R0 on top of stack, followed by script output
  Pop $R0
  !undef PSExecID
!macroend
 
!macro PowerShellExecFileLogMacro PSFile
  !define PSExecID ${__LINE__}
  Push $R0
 
  nsExec::ExecToLog 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "${PSFile}"  '
  Pop $R0 ;return value is on stack
  IntCmp $R0 0 finish_${PSExecID}
  SetErrorLevel 2
 
finish_${PSExecID}:
  Pop $R0
  !undef PSExecID
!macroend
 
!define PowerShellExec `!insertmacro PowerShellExecMacro`
!define PowerShellExecLog `!insertmacro PowerShellExecLogMacro`
!define PowerShellExecFile `!insertmacro PowerShellExecFileMacro`
!define PowerShellExecFileLog `!insertmacro PowerShellExecFileLogMacro`
 
!endif

Version History

[Update 2014-01-07]
Initial version