32 or 64 bit version of product: 64
Operating system: Windows 10 - Tech Preview 1803 (17134.1)
32 or 64 bit OS: 64
There seems to be a major difference in how a Service is compiled in PowerShell Studio (PSS) vs PrimalScript.
When a service is built in PSS it seems to just run as a back ground script, and when StopService() is called it just terminates the PowerShell thread...
Where as in PrimalScript the StopService() call kicks off the Stop-MyService Function.
Is there anyway to capture the StopSerivce and PauseService commands in PSS?
I would like to get these in order to get it to cleanly shutdown the service rather than just terminating the thread?
Ideally, I would also like to be able to install the created service and have it linked to dependencies.
I.e. dont run unless the dependent service is running...
but am unable to find a way to do this...
and finally, if there was some way for the installer to selectively prompt for a service account during the install.
i.e. would you like to use a service account enter details.
The following is an example of what i am building..
It uses the .Net File watcher, to monitor for File changes specified in the config file.
When one is identified the Invoke-MyService loop will pick up the Event Item and process it.. e.g. when a file is changed write to the event log.
- <#
- .NOTES
- ========================================================================
- Windows PowerShell Source File
- Created with SAPIEN Technologies PrimalScript 2018
- NAME: Marc Collins (Nillth)
- DATE : 23/04/2018
- ==========================================================================
- #>
- # Warning: Do not rename Start-MyService, Invoke-MyService and Stop-MyService functions
- function Get-ScriptDirectory
- {
- if ($null -ne $hostinvocation)
- {
- Split-Path $hostinvocation.MyCommand.path
- }
- else
- {
- Split-Path $script:MyInvocation.MyCommand.Path
- }
- }
- function Start-MyService
- {
- $Global:StopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
- $Global:StopWatch.Start()
- $global:bRunService = $true
- $global:bServiceRunning = $false
- #region Register Events to Monitor
- ###########################################################################
- #region ServiceMonitor
- $RunningService = Get-WmiObject Win32_Service -Filter "ProcessId='$($PID)'"
- $query = @"
- SELECT *
- FROM __InstanceModificationEvent
- WITHIN 2
- WHERE TargetInstance ISA 'Win32_Service'
- AND TargetInstance.Name = '$($RunningService.Name)'
- "@
- Unregister-Event ServiceChangeWIM -ErrorAction SilentlyContinue
- Register-WmiEvent -Query $query ServiceChangeWIM
- #endregion ServiceMonitor
- ###########################################################################
- #region FileSystem Watcher/s
- $ScriptDirectory = Get-ScriptDirectory
- $TriggerConfig = "$($ScriptDirectory)\TriggerConfig.xml"
- #Creates a Trigger config and Template file on first run if they do not exist
- if (!(Test-Path $TriggerConfig))
- {
- $TriggerExample = "$($ScriptDirectory)TriggerTemplate.txt"
- $TriggerTemplate = @"
- <?xml version="1.0"?>
- <Triggers>
- <Trigger Name="MyApp">
- <TriggerFile>$($TriggerExample)</TriggerFile>
- </Trigger>
- </Triggers>
- "@
- #Create a empty template triggerfile
- if (!(Test-Path $TriggerExample))
- {
- "" | Out-File -FilePath $TriggerExample -Encoding utf8 -Force
- }
- $TriggerTemplate | Out-File -FilePath $TriggerConfig -Encoding utf8 -Force
- }
- $XMLTriggerConfig = New-Object XML
- $XMLTriggerConfig.Load($TriggerConfig)
- foreach ($Trigger in $XMLTriggerConfig.Triggers.Trigger)
- {
- $TriggerFolder = [system.io.path]::GetDirectoryName($Trigger.TriggerFile)
- $TriggerFile = [system.io.path]::GetFileName($Trigger.TriggerFile)
- if ($null -ne $Trigger.Name)
- {
- $TriggerName = "$($Trigger.Name)"
- }
- else
- {
- $TriggerName = "$($TriggerFile)"
- }
- if (Test-Path -LiteralPath $TriggerFolder)
- {
- #Create the File System Watcher
- $fsw = New-Object IO.FileSystemWatcher $TriggerFolder, $TriggerFile -Property @{ IncludeSubdirectories = $false; NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite' }
- $SourceIdentifier = "FileTrigger - $($TriggerFile)"
- }
- Register-ObjectEvent $fsw Changed -SourceIdentifier $SourceIdentifier -Action {New-Event -SourceIdentifier TriggerTouch -MessageData $Event} | Out-Null
- }
- #endregion FileSystem Watcher
- #endregion Register Events to Monitor
- }
- function Invoke-MyService
- {
- $global:bServiceRunning = $true
- while ($global:bRunService)
- {
- $EventReceived = Wait-Event -SourceIdentifier TriggerTouch -Timeout 5
- #Check for shutdown/pause etc activity
- $EventAction = Get-Event -SourceIdentifier Action
- if ($null -ne $EventAction)
- {
- if ($EventReceived.MessageData -eq "ShutdownService")
- {
- #Termination code
- }
- }
- else
- {
- #Process Something.
- #This should contain the Information returned from the FileWatcher
- #$EventReceived.MessageData
- #e.g.
- Write-Host "File $($EventReceived.MessageData.SourceArgs[1].ChangeType) - $($EventReceived.MessageData.SourceArgs[1].FullPath)"
- if ($null -ne $EventReceived)
- {
- Remove-Event -EventIdentifier $EventReceived.EventIdentifier -ErrorAction SilentlyContinue
- }
- }
- }
- $global:bServiceRunning = $false
- }
- function Stop-MyService
- {
- $global:bRunService = $false # Signal main loop to exit
- while ($global:bServiceRunning)
- {
- $EventReceived = Wait-Event ServiceChangeWIM -Timeout 1
- if ($null -ne $EventReceived)
- {
- Remove-Event -EventIdentifier $EventReceived.EventIdentifier -ErrorAction SilentlyContinue
- if ($EventReceived.SourceEventArgs.NewEvent.TargetInstance.State -eq "Stop Pending")
- {
- New-Event -SourceIdentifier Action -MessageData "ShutdownService"
- $global:bServiceRunning = $false
- }
- }
- }
- $EventSubscriber = Get-EventSubscriber -ErrorAction SilentlyContinue
- if ($null -ne $EventSubscriber)
- {
- $EventSubscriber.SourceIdentifier | %{ Unregister-Event $_ }
- }
- }