Archive: NSIS Service Plugin


NSIS Service Plugin
Greetings,

I have the need to check on a service status and startit up in case it is not running (windows installer) now the funny thing is that as i have been trying to use the SERVICE plugin, i have been able to get it to work with the services that have a single word as a service name but not with services that have spaces in between the words, for example..

----8<----
OutFile findservices.exe
section
services::IsServiceRunning 'Windows Installer'
Pop $0
StrCmp $0 'Ok' success 0
MessageBox MB_OK|MB_ICONSTOP 'command: $0' 0 0
Abort
success:

SectionEnd
----8<----

any ideas on what is going wrong and how that could be corrected?


regards
BL


Try it as MSIServer instead.

 services::IsServiceRunning "MSIServer"

Check the registry under HKLM\System\CurrentControlSet\Services for the exact service name. Windows Installer is the name of the service as it appears on any GUI, the true service name is MSIServer.
You can start/stop/query the service with either name ...
CF

case solved!
thanks a lot!
that resolved my problem. now i only have to figure out
how to enable the service to start it up in case it is disabled ...any ideas?

regards
BL


You can use the NsSCM plugin to query/start/stop the service ...

CF


but can that other plugin enable a disabled service?


case finally closed!!!
ok guys

just to answer my own question,

appearently the service plugin is not able to enable a disabled service. even if you would enable a service from the registry, the net start (which equate to the service plugin) wont be able to start the service because in the service manager db the service is still registered to be in the previous state.

for each service there are two places (if im not mistaken) where information is stored regarding its state, its own registry path/key and the service manager db.

enabling the service from the registry path/key(start|dword) alone would not suffice, you would either have to do it thru the service mmc gui or... you can you the sc.exe to do it!

so if you have a disabled service, enable it first with the sc tool (if not found on your system, you can find it in the reskit) with the command "sc config msiserver start= demand" and after that use the service plugin to startup the service!

here is a sample script that does that, dirty but does the job :)

regards
BL
---8<------8<------8<------8<---
OutFile findservices.exe
section
;enable service from console
execwait "sc config msiserver start= demand"

;check if service is running
services::IsServiceRunning 'MSIServer'
Pop $0
StrCmp $0 'Ok' success 0
MessageBox MB_OK|MB_ICONSTOP 'Service running status: $0 (3= enabled!)' 0 0
success:

;read service registry status value
ReadRegDWORD $0 HKEY_LOCAL_MACHINE "SYSTEM\CurrentControlSet\Services\MSIServer" "Start"
Pop $0
MessageBox MB_OK|MB_ICONSTOP 'value: $0' 0 0

;startup service
services::SendServiceCommand 'start' 'MSIServer'
Pop $0
StrCmp $0 'Ok' success1 0
MessageBox MB_OK|MB_ICONSTOP 'Service start command status: $0' 0 0
success1:

; check that service started
services::IsServiceRunning 'MSIServer'
Pop $0
StrCmp $0 'Ok' success2 0
MessageBox MB_OK|MB_ICONSTOP 'Service running status: $0 (3= enabled!)' 0 0
success2:


SectionEnd
---8<------8<------8<------8<---


You could do the same using direct API calls, thus avoiding the use of a command line tool.
The following code will atempt to start the MSIServer and if it fails it will alter the service's configuration then retry:

!define SC_MANAGER_ALL_ACCESS   0x3F
!define SERVICE_ALL_ACCESS 0xF01FF
!define SERVICE_DEMAND_START 0x00000003
!define SERVICE_NO_CHANGE 0xffffffff

# Get a handle to the SCM
System::Call 'advapi32::OpenSCManagerA(,,i ${SC_MANAGER_ALL_ACCESS})i.R9'

# Get a handle to the service
System::Call 'advapi32::OpenServiceA(i R9,t "MSIServer",i ${SERVICE_ALL_ACCESS})i.R8'

# Start the service
System::Call 'advapi32::StartServiceA(i R8,i 0,i 0)i.r0'
StrCmp $0 0 0 +3
# Change the service startup options
System::Call 'advapi32::ChangeServiceConfigA(i R8,i ${SERVICE_NO_CHANGE},i ${SERVICE_DEMAND_START},i ${SERVICE_NO_CHANGE},,,,,,,)i.r0'
# Start the service
System::Call 'advapi32::StartServiceA(i R8,i 0,i 0)i.r0'

# Close the service handle
System::Call 'advapi32::CloseServiceHandle(i R8)i.r0'

# Close the SCM handle
System::Call 'advapi32::CloseServiceHandle(i R9)i.r0'


:)

CF

wow,
that went right over my head, i didnt know that api calls can be done straight off! regardless of that its a totally different thing on whether i would know how to program to interface with the api :)

so i guess my next question is .. due to security tightening policy, i need to keep the service as disabled after having installed the required applications (after a new install). now you presented how it could be enabled and started, I would greatly appreciate it if you could point on how to disable the service when done :)

that is why i was running checks in between to verify the state prior to applying changes :)

regards
BL


The Windows Installer Service should be left on manual, otherwise the self-healing option that is provided as default with all msi packs will not work, if I am not mistaken.

You can use part of the previous code that I posted to stop the service and set its configuration to disabled:

!define SC_MANAGER_ALL_ACCESS   0x3F
!define SERVICE_ALL_ACCESS 0xF01FF
!define SERVICE_DEMAND_START 0x00000003
!define SERVICE_DISABLED 0x00000004
!define SERVICE_NO_CHANGE 0xffffffff
!define SERVICE_CONTROL_STOP 1

# Get a handle to the SCM
System::Call 'advapi32::OpenSCManagerA(,,i ${SC_MANAGER_ALL_ACCESS})i.R9'

# Get a handle to the service
System::Call 'advapi32::OpenServiceA(i R9,t "MSIServer",i ${SERVICE_ALL_ACCESS})i.R8'

# Stop the service
System::Call '*(i,i,i,i,i,i,i)i.R0'
System::Call 'advapi32::ControlService(i R8,i ${SERVICE_CONTROL_STOP},i R0)i.r0'
System::Call '*$R0(,i.r1,,,,,)' ; $1 contains the service status code
System::Free $R0

# Change the service startup options
System::Call 'advapi32::ChangeServiceConfigA(i R8,i ${SERVICE_NO_CHANGE},i ${SERVICE_DISABLED},i ${SERVICE_NO_CHANGE},,,,,,,)i.r0'

# Close the service handle
System::Call 'advapi32::CloseServiceHandle(i R8)i.r0'

# Close the SCM handle
System::Call 'advapi32::CloseServiceHandle(i R9)i.r0'
You can find more information about starting/stopping/pausing/quering etc a service at this MSDN page.
;)
CF