NSIS check state of Windows Service - service

I am writing NSIS script and i need to check service state (Running/Stopped/Paused/No exist) and to make some actions then.
But i can`t use any user libs such as nsSCM.
I found a script
sc QUERY ServiceNameHere | FIND "RUNNING"
but i can`t find how to check the return result in NSIS script.
Please help.

If you can use plug-ins:
Using the Simple Service Plugin, you can do this:
SimpleSC::GetServiceStatus "MyService"
Pop $0 ; returns an errorcode (!=0) otherwise success (0)
Pop $1 ; return the status of the service (see below)
If successful, the service status will have one of the following numeric values:
STOPPED
START_PENDING
STOP_PENDING
RUNNING
CONTINUE_PENDING
PAUSE_PENDING
PAUSED
If you can NOT use plug-ins:
Note that I added /C to FIND.exe to output the line count instead of the entire line. Also, be careful modifying the quotes. It took some trial and error to get that right.
StrCpy $R0 '"$SYSDIR\cmd.exe" /c "sc QUERY MyServiceName | FIND /C "RUNNING""'
nsExec::ExecToStack '$R0'
Pop $R1 # contains return code
Pop $R2 # contains output
${If} $R1 == "0"
# command success
${If} $R2 == "1"
# it's running
${Else}
# it's not running
${EndIf}
${Else}
# command failed
${EndIf}
Be sure to include the logic library, as NSIS requires this for conditional statement macros:
# Included files
!include LogicLib.nsh

There are several NSIS plugins and helper functions that deal with NT services: NSIS Service Lib, NSIS Simple Service Plugin and NsSCM. The wiki has a overview of all your options.
Using sc.exe is problematic since the output might be localized, net.exe is probably better (And it also exits on < WinXP) here is my take on that solution:
!include LogicLib.nsh
StrCpy $1 "Event Log" ;Put your service name here
ExpandEnvStrings $0 "%comspec%"
nsExec::ExecToStack '"$0" /k "net start | FIND /C /I "$1""'
Pop $0
Pop $1
StrCpy $1 $1 1
${If} "$0$1" == "01"
MessageBox mb_ok "Running"
${Else}
MessageBox mb_ok "Not Running"
${EndIf}

I check if a service is running by using its DISPLAY name (not the service name), because it tends to be more precise (e.g. service name is JETTY while the DISPLAY name uses my product name - I avoid the risk of counting a JETTY service installed by another product).
So based on Kyle's solution I use:
var running
!macro CheckMyService
StrCpy $running "0"
StrCpy $cmd '"$SYSDIR\cmd.exe" /c "net start | FIND /C "MyServiceDisplayName""'
nsExec::ExecToStack '$cmd'
Pop $R1 # contains return code
Pop $R2 # contains output
StrCpy $n $R2 1
${If} $R1 == "0"
${If} $n == "1"
StrCpy $running "1"
${EndIf}
${EndIf}
DetailPrint "runnning(1=yes): $running"
!macroend

Related

How can I identify if the executed ghostscript command returned an error in Perl?

I am having problem to get ghostscript's error return code to know if it failed or not,
I tried corrupting a PostScript file (messed it up on a file editor) and ran it, but I could not get a 1 or non-0 return.
After reading some manual and topics about it(hardly) here, this is what I currently do:
my $cmd = "/apps/gs/ghostpdl-9.52/bin/gs -dSAFER -dBATCH -dNOPAUSE -sDEVICE=ps2write -sstdout=%stderr -sOutputFile=$output -sPAPERSIZE=a4 -dFIXEDMEDIA -f $psfile";
logmsg("command: $cmd");
my $rc = `$cmd`;
logmsg("rc: $rc");
if($rc != 0){
...
}
but $rc doesn't have any value so I couldn't satisfy $rc != 0
Hopefully someone could help.
Thanks
If the command outputs an error message to STDERR (and many do), then you need to append 2>&1 to the command in order to redirect STDERR to STDOUT for capture by the backticks, like so:
my $output = `$cmd 2>&1`;
Then check $output for some kind of error or success message. I suggest printing it in order to see to see what it contains.
Note that the return value of backticks is the output of the command, not it's return status! If you really want the native return status of the command executed by the backticks, you can get that information using $? or ${^CHILD_ERROR_NATIVE}. See perldoc perlvar for details.

Why is fish 3.0 printing an error message on start?

I recently upgraded to fish 3.0.1 via Homebrew 2.0.1 on MacOS Mojave 10.14.2. Since the upgrade, the following error message appears every time fish starts:
contains: Unknown option '-gx'
/usr/local/Cellar/fish/3.0.1/share/fish/config.fish (line 426):
if not contains $entry $result
^
in function '__fish_macos_set_env'
called on line 228 of file /usr/local/Cellar/fish/3.0.1/share/fish/config.fish
with parameter list 'PATH /etc/paths /etc/paths.d'
from sourcing file /usr/local/Cellar/fish/3.0.1/share/fish/config.fish
called during startup
contains - test if a word is present in a list
Synopsis
contains [OPTIONS] KEY [VALUES...]
contains: Type 'help contains' for related documentation
contains: Unknown option '-e'
/usr/local/Cellar/fish/3.0.1/share/fish/config.fish (line 426):
if not contains $entry $result
^
in function '__fish_macos_set_env'
called on line 228 of file /usr/local/Cellar/fish/3.0.1/share/fish/config.fish
with parameter list 'PATH /etc/paths /etc/paths.d'
from sourcing file /usr/local/Cellar/fish/3.0.1/share/fish/config.fish
called during startup
contains - test if a word is present in a list
Synopsis
contains [OPTIONS] KEY [VALUES...]
contains: Type 'help contains' for related documentation
My first reflex was to have a look in the offending file, namely /usr/local/Cellar/fish/3.0.1/share/fish/config.fish, but this file is only 306 lines long, and therefore does not seem to contain the infamous line 426. I am copying this file below, in case it proves useful:
# Main file for fish command completions. This file contains various
# common helper functions for the command completions. All actual
# completions are located in the completions subdirectory.
#
# Set default field separators
#
set -g IFS \n\ \t
set -qg __fish_added_user_paths
or set -g __fish_added_user_paths
#
# Create the default command_not_found handler
#
function __fish_default_command_not_found_handler
printf "fish: Unknown command %s\n" (string escape -- $argv[1]) >&2
end
if status --is-interactive
# The user has seemingly explicitly launched an old fish with too-new scripts installed.
if not contains -- "string" (builtin -n)
set -g __is_launched_without_string 1
# XXX nostring - fix old fish binaries with no `string' builtin.
# When executed on fish 2.2.0, the `else' block after this would
# force on 24-bit mode due to changes to in test behavior.
# These "XXX nostring" hacks were added for 2.3.1
set_color --bold
echo "You appear to be trying to launch an old fish binary with newer scripts "
echo "installed into" (set_color --underline)"$__fish_data_dir"
set_color normal
echo -e "\nThis is an unsupported configuration.\n"
set_color yellow
echo "You may need to uninstall and reinstall fish!"
set_color normal
# Remove this code when we've made it safer to upgrade fish.
else
# Enable truecolor/24-bit support for select terminals
# Ignore Screen and emacs' ansi-term as they swallow the sequences, rendering the text white.
if not set -q STY
and not string match -q -- 'eterm*' $TERM
and begin
set -q KONSOLE_PROFILE_NAME # KDE's konsole
or string match -q -- "*:*" $ITERM_SESSION_ID # Supporting versions of iTerm2 will include a colon here
or string match -q -- "st-*" $TERM # suckless' st
or test -n "$VTE_VERSION" -a "$VTE_VERSION" -ge 3600 # Should be all gtk3-vte-based terms after version 3.6.0.0
or test "$COLORTERM" = truecolor -o "$COLORTERM" = 24bit # slang expects this
end
# Only set it if it isn't to allow override by setting to 0
set -q fish_term24bit
or set -g fish_term24bit 1
end
end
else
# Hook up the default as the principal command_not_found handler
# in case we are not interactive
function __fish_command_not_found_handler --on-event fish_command_not_found
__fish_default_command_not_found_handler $argv
end
end
#
# Set default search paths for completions and shellscript functions
# unless they already exist
#
set -g __fish_config_dir ~/.config/fish
if set -q XDG_CONFIG_HOME
set __fish_config_dir $XDG_CONFIG_HOME/fish
end
set -l userdatadir ~/.local/share
if set -q XDG_DATA_HOME
set userdatadir $XDG_DATA_HOME
end
# __fish_data_dir, __fish_sysconf_dir, __fish_help_dir, __fish_bin_dir
# are expected to have been set up by read_init from fish.cpp
# Grab extra directories (as specified by the build process, usually for
# third-party packages to ship completions &c.
set -l __extra_completionsdir
set -l __extra_functionsdir
set -l __extra_confdir
if test -f $__fish_data_dir/__fish_build_paths.fish
source $__fish_data_dir/__fish_build_paths.fish
end
# Set up function and completion paths. Make sure that the fish
# default functions/completions are included in the respective path.
if not set -q fish_function_path
set fish_function_path $__fish_config_dir/functions $__fish_sysconf_dir/functions $__extra_functionsdir $__fish_data_dir/functions
end
if not contains -- $__fish_data_dir/functions $fish_function_path
set fish_function_path $fish_function_path $__fish_data_dir/functions
end
if not set -q fish_complete_path
set fish_complete_path $__fish_config_dir/completions $__fish_sysconf_dir/completions $__extra_completionsdir $__fish_data_dir/completions $userdatadir/fish/generated_completions
end
if not contains -- $__fish_data_dir/completions $fish_complete_path
set fish_complete_path $fish_complete_path $__fish_data_dir/completions
end
# This cannot be in an autoload-file because `:.fish` is an invalid filename on windows.
function :
# no-op function for compatibility with sh, bash, and others.
# Often used to insert a comment into a chain of commands without having
# it eat up the remainder of the line, handy in Makefiles.
end
#
# This is a Solaris-specific test to modify the PATH so that
# Posix-conformant tools are used by default. It is separate from the
# other PATH code because this directory needs to be prepended, not
# appended, since it contains POSIX-compliant replacements for various
# system utilities.
#
if test -d /usr/xpg4/bin
if not contains -- /usr/xpg4/bin $PATH
set PATH /usr/xpg4/bin $PATH
end
end
# Add a handler for when fish_user_path changes, so we can apply the same changes to PATH
function __fish_reconstruct_path -d "Update PATH when fish_user_paths changes" --on-variable fish_user_paths
set -l local_path $PATH
for x in $__fish_added_user_paths
set -l idx (contains --index -- $x $local_path)
and set -e local_path[$idx]
end
set -g __fish_added_user_paths
if set -q fish_user_paths
for x in $fish_user_paths[-1..1]
if set -l idx (contains --index -- $x $local_path)
set -e local_path[$idx]
else
set -g __fish_added_user_paths $__fish_added_user_paths $x
end
set local_path $x $local_path
end
end
set -xg PATH $local_path
end
#
# Launch debugger on SIGTRAP
#
function fish_sigtrap_handler --on-signal TRAP --no-scope-shadowing --description "Signal handler for the TRAP signal. Launches a debug prompt."
breakpoint
end
#
# Whenever a prompt is displayed, make sure that interactive
# mode-specific initializations have been performed.
# This handler removes itself after it is first called.
#
function __fish_on_interactive --on-event fish_prompt
__fish_config_interactive
functions -e __fish_on_interactive
end
# Set the locale if it isn't explicitly set. Allowing the lack of locale env vars to imply the
# C/POSIX locale causes too many problems. Do this before reading the snippets because they might be
# in UTF-8 (with non-ASCII characters).
__fish_set_locale
# "." command for compatibility with old fish versions.
function . --description 'Evaluate contents of file (deprecated, see "source")' --no-scope-shadowing
if test (count $argv) -eq 0
# Uses tty directly, as isatty depends on "."
and tty 0>&0 >/dev/null
echo "source: '.' command is deprecated, and doesn't work with STDIN anymore. Did you mean 'source' or './'?" >&2
return 1
else
source $argv
end
end
# Upgrade pre-existing abbreviations from the old "key=value" to the new "key value" syntax.
# This needs to be in share/config.fish because __fish_config_interactive is called after sourcing
# config.fish, which might contain abbr calls.
if not set -q __fish_init_2_3_0
if set -q fish_user_abbreviations
set -l fab
for abbr in $fish_user_abbreviations
set fab $fab (string replace -r '^([^ =]+)=(.*)$' '$1 $2' -- $abbr)
end
set fish_user_abbreviations $fab
end
set -U __fish_init_2_3_0
end
# macOS-ism: Emulate calling path_helper.
if command -sq /usr/libexec/path_helper
# Adapt construct_path from the macOS /usr/libexec/path_helper
# executable for fish; see
# https://opensource.apple.com/source/shell_cmds/shell_cmds-203/path_helper/path_helper.c.auto.html .
function __fish_macos_set_env -d "set an environment variable like path_helper does (macOS only)"
set -l result
for path_file in $argv[2] $argv[3]/*
if test -f $path_file
while read -l entry
if not contains $entry $result
set result $result $entry
end
end <$path_file
end
end
for entry in $$argv[1]
if not contains $entry $result
set result $result $entry
end
end
set -xg $argv[1] $result
end
__fish_macos_set_env 'PATH' '/etc/paths' '/etc/paths.d'
if [ -n "$MANPATH" ]
__fish_macos_set_env 'MANPATH' '/etc/manpaths' '/etc/manpaths.d'
end
functions -e __fish_macos_set_env
end
#
# Some things should only be done for login terminals
# This used to be in etc/config.fish - keep it here to keep the semantics
#
if status --is-login
#
# Put linux consoles in unicode mode.
#
if test "$TERM" = linux
if string match -qir '\.UTF' -- $LANG
if command -sq unicode_start
unicode_start
end
end
end
end
# Invoke this here to apply the current value of fish_user_path after
# PATH is possibly set above.
__fish_reconstruct_path
# Allow %n job expansion to be used with fg/bg/wait
# `jobs` is the only one that natively supports job expansion
function __fish_expand_pid_args
for arg in $argv
if string match -qr '^%\d+$' -- $arg
# set newargv $newargv (jobs -p $arg)
jobs -p $arg
if not test $status -eq 0
return 1
end
else
printf "%s\n" $arg
end
end
end
function bg
builtin bg (__fish_expand_pid_args $argv)
end
function fg
builtin fg (__fish_expand_pid_args $argv)
end
function kill
command kill (__fish_expand_pid_args $argv)
end
function wait
builtin wait (__fish_expand_pid_args $argv)
end
function disown
builtin disown (__fish_expand_pid_args $argv)
end
# As last part of initialization, source the conf directories.
# Implement precedence (User > Admin > Extra (e.g. vendors) > Fish) by basically doing "basename".
set -l sourcelist
for file in $__fish_config_dir/conf.d/*.fish $__fish_sysconf_dir/conf.d/*.fish $__extra_confdir/*.fish
set -l basename (string replace -r '^.*/' '' -- $file)
contains -- $basename $sourcelist
and continue
set sourcelist $sourcelist $basename
# Also skip non-files or unreadable files.
# This allows one to use e.g. symlinks to /dev/null to "mask" something (like in systemd).
[ -f $file -a -r $file ]
and source $file
end
What's going on here? How can I fix this?
What happens here is that a component of your $PATH, $fish_user_paths or a line in /etc/paths looks like an option.
Most likely, this is wrong, and you should remove it.
E.g. try printf '%s\n' $fish_user_paths. If that tells you that one of the entries is "-gx", then you've set it incorrectly and need to use set -e fish_user_paths[number-of-that-entry] to correct it.
Since these are all common options to set, you've probably once done something like set fish_user_paths /something -gx, which adds a "-gx" component (set only reads options before the variable name).
This has been reported upstream at https://github.com/fish-shell/fish-shell/issues/5662, and future fish versions won't spew an error, but the existence of the offending component is most likely an error, so you still want to remove it.

Command output printed instead of captured in Powershell

In general, I know how to capture the output of a command into a variable in Powershell:
> $output = python3 --version
> Write-Host $output
Python 3.7.0
Python 3 prints its version but it's captured into the variable $output and nothing is displayed on the console. As expected:
> $output = python3 --version
> Write-Host $output
Python 3.7.0
But in the case of Python 2, it doesn't work. Python 2 prints its version but its displayed on the console instead of captured and the variable $output is empty.
> $output = python2 --version
Python 2.7.15
> Write-Host $output
>
I have tried some alternative syntaxes but so far nothing helped:
> $output = (python2 --version) # use a subcommand
Python 2.7.15
> $output = "$(python2 --version)" # enclose the subcommand into a string
Python 2.7.15
If I use it in Write-Command, the output looks like the following:
> Write-Host "Python version: $(python2 --version)"
Python 2.7.15
Python version:
>
How is Python 2 printing its version that it's not captured into a variable and is it possible to capture it anyhow?
It's caused by Python 2 which prints version to stderr instead of stdout. Assignment of program call's output captures stdout only which is empty in this case. On the other side, stderr is printed to the console by default, that's why the $output variable is empty and the version is printed to the console. See below for details.
tl; dr:
# Redirect stderr to the success output stream and convert to a string.
$output = (python --version 2>&1).ToString()
# $? is now $True if python could be invoked, and $False otherwise
For commands that may return multiple stderr lines, use:
PSv4+, using the .ForEach() method:
$output = (python --version 2>&1).ForEach('ToString')
PSv3-, using the ForEach-Object cmdlet (whose built-in alias is %):
# Note: The (...) around the python call are required for
# $? to have the expected value.
$output = (python --version 2>&1) | % { $_.ToString() }
# Shorter PSv3+ equivalent, using an operation statement
$output = (python --version 2>&1) | % ToString
As Mathias R. Jessen notes in a comment on the question and you yourself clarified in terms of versions, python 2.x - surprisingly - outputs its version information to stderr rather than stdout, unlike 3.x.
The reason you weren't able to capture the output with $output = ... is that assigning an external program call's output to a variable only captures its stdout output by default.
With a PowerShell-native command, it captures the command's success output stream - see about_redirection.
The primary fix is to use redirection 2>&1 to merge PowerShell's error stream (PowerShell's analog to stderr, to which stderr output is mapped if redirected) into PowerShell's success output stream (the stdout analog), which is then captured in the variable.
This has two side effects, however:
Since PowerShell's error stream is now involved due to the 2>&1 redirection (by default, stderr output is passed through to the console), $? is invariably set to $False, because writing anything to the error stream does that (even if the error stream is ultimately sent elsewhere, as in this case).
Note that $? is not set to $False without the redirection (except in the ISE, which is an unfortunate discrepancy), because stderr output then never "touches" PowerShell's error output stream.
In the PowerShell console, when calling an external program without a 2> redirection, $? is set to $False only is if its exit code is nonzero ($LASTEXITCODE -ne 0).
Therefore, use of 2>&1 solves one problem (inability capture output) while introducing another ($? incorrectly set to $False) - see below for a remedy.
It isn't strings that get written to the success output stream, but [System.Management.Automation.ErrorRecord] instances, because PowerShell wraps every stderr output line in one.
If you only use these instances in a string context - e.g., "Version: $output", you may not notice or care, however.
.ToString() (for a single output line) and .ForEach('ToString') / (...) | % ToString (for potentially multiple output lines) undo both side effects:
They convert the [System.Management.Automation.ErrorRecord] instances back to strings.
They reset $? to $True, because the .ToString() / .ForEach() calls / the use of (...) around the command are expressions, which are themselves considered successful, even if they contain commands that themselves set $? to $False.
Note:
If executable python cannot be located, PowerShell itself will throw a statement-terminating error, which means that the assignment to $output will be skipped (its value, if any existed, will not change), and by default you get noisy error output and $? will be set to $False.
If python can be invoked and it reports an error (which is unlikely with --version), as indicated via nonzero exit code, you can inspect that exit code via the automatic $LASTEXITCODE variable (whose value won't change until the next call to an external program).
That something as simple as putting (...) around a command makes $? invariably return $True (except if a statement- or script-terminating error occurs) is taken advantage of in the above approaches, but is generally obscure behavior that could be considered problematic - see this discussion on GitHub.

Change variables via command line NSIS installer

I would like to change variables within NSIS through command line arguments. I see in the documentation you can change global variables, but not created ones within the NSIS script.
For example: if I had
Var example
StrCpy $example "C:\Program Files (x86)\Installer"
Is it possible to change the example variable string through command line arguments?
OutFile "MySetup.exe"
Name "MySetup"
RequestExecutionLevel user
!include FileFunc.nsh
!include LogicLib.nsh
Var MyVar
Function .onInit
StrCpy $MyVar "Default value"
${GetParameters} $0
ClearErrors
${GetOptions} $0 "/MyVar=" $1 ; Get suffix after "/MyVar=" switch
${IfNot} ${Errors}
StrCpy $MyVar $1
${EndIf}
FunctionEnd
Section
MessageBox mb_OK MyVar:$MyVar
SectionEnd
and execute as "MySetup.exe" /MyVar="Hello world"

Passing PostgreSQL psql error messages to unix shell variables

I am calling PostgreSQL function from Unix shell script.
Can anyone tell me how do i capture PostgreSQL error messages returned from the function in unix shell variables?
I used the below method but not able to
#!/bin/ksh
function crt_views
{
#Call the POSTGRE pkg which created dynamic views
echo "Calling POSTGRE function FN_CRT_ACTNET_VWS..." >> $LOGFILENAME
pg_msg=`psql --echo-all -U<uname> << EOF
set client_min_messages='NOTICE';
SELECT FUNC_CRT_VWS();
EOF`
}
crt_views
echo "PRINTING - $pg_msg"
In output I'm not seeing the errors returned from the PostgreSQL function. Please help
You need to redirect stderr to stdout, since backtick ing something will get you only stdout.
This is because output that is both from RAISE NOTICE and RAISE EXCEPTION (among other things) is printed to stderr by psql.
Note: I also switched from using backtick ing to dollar-paren style execution. Using the backtick, redirecting stderr in this way doesn't work. (My testing was under sh instead of ksh, but in this case the behavior should be similar, I suspect.)
Also, set -e will fail on error, which may be desireable (depending on your needs).
So, that leads to something like this:
#!/bin/ksh
set -e
function crt_views
{
#Call the Postgres pkg which created dynamic views
echo "Calling Postgres function FN_CRT_ACTNET_VWS..." >> $LOGFILENAME
pg_msg=$(psql --echo-all -U<uname> << EOF
set client_min_messages='NOTICE';
SELECT FUNC_CRT_VWS();
EOF
2>&1)
}
crt_views
echo "PRINTING - $pg_msg"