- NSIS Discussion
- NSIS Service Plugin
Archive: NSIS Service Plugin
BashLogic
12th June 2006 13:48 UTC
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
CancerFace
12th June 2006 15:02 UTC
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
BashLogic
12th June 2006 16:34 UTC
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
CancerFace
12th June 2006 16:43 UTC
You can use the NsSCM plugin to query/start/stop the service ...
CF
BashLogic
12th June 2006 16:46 UTC
but can that other plugin enable a disabled service?
BashLogic
12th June 2006 19:26 UTC
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<---
CancerFace
12th June 2006 22:45 UTC
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
BashLogic
13th June 2006 06:47 UTC
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
CancerFace
13th June 2006 08:08 UTC
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