Creating a Service with PowerShell Studios

So.. on my recent trip to Florida. Our Support team has a single login to make changes to settings for a server from a web page. So when the change is made, it changes a certain configuration file on the machine. But since they all use one login, they didn’t know who made the change. So I explored some options, and found that with PowerShell Studios you can compile a service and register it. It is very simple also. I am sure I can add more to my service to clean it up a little. I nulled all the variables at the end and found it saved me 2 MB of memory usage.. lol

So the service below detects changes to the file. Then does a netstat on port 8010 to get the users connected. (users have to use that port to connect to the webadmin) Does a NSLookup on what it finds, logs their IP, and creates a backup of the rule. Also, I added something to only keep 90 days of rules because these files are quite large on our side. I kept the write host in the code to help with commenting on the script. The code below uses .net FileWatcher service, and is pretty powerful. The file Watcher Service can watch for changes, deletions, and new.

To install the service you would just compile the Service into a EXE then just use command prompt or powershell to .\WatcherService.exe /i register the service and then start it. You can use the /u argument to uninstall the service.

# Warning: Do not rename Start-MyService, Invoke-MyService and Stop-MyService functions function Start-MyService { # Place one time startup code here. # Initialize global variables and open connections if needed $global:bRunService = $true $global:bServiceRunning = $false $global:bServicePaused = $false } function Invoke-MyService { $global:bServiceRunning = $true while ($global:bRunService) { try { if ($global:bServicePaused -eq $false) #Only act if service is not paused { #Checks for a Job, if a job is still open it just skip $JobCount = get-job If ($JobCount -eq $Null) { $server = $env:computername $folder = '\\' + $Server + '\d$\Admin\Settings' # Enter the root path you want to monitor. $filter = 'Rules.*' # You can enter a wildcard filter here. You can use Extension also $fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property @{ IncludeSubdirectories = $false; NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite' } Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -Action { $name = $Event.SourceEventArgs.Name $changeType = $Event.SourceEventArgs.ChangeType $timeStamp = $Event.TimeGenerated Write-Host "The file '$name' was $changeType at $timeStamp" -fore white $GetIP = Get-NetTCPConnection -LocalPort 8010 | ?{ $_.LocalAddress -ne "" -and $_.LocalAddress -ne "" } | select-object Remoteaddress -Unique Foreach ($IP in $GetIP) { $IPAddress = $IP.RemoteAddress $NameofUser = (Resolve-DnsName $IPAddress).NameHost #this might be different than your enviornment, in ours we cannot nslookup a VPN adddress. If ($IPaddress -like "192*") { Write-Host "A VPN User most likely Changed the rules files With IP of $IPAddress" Out-File -FilePath 'D:\WatcherService\Logs\Changelog.txt' -Append -InputObject "$timeStamp A VPN User most likely Changed the rules files With IP of $IPAddress" } Else { Write-Host "$NameofUser most likely Changed the rules files With IP of $IPAddress" If ($NameofUser -eq $null) { Out-File -FilePath 'D:\WatcherService\Logs\Changelog.txt' -Append -InputObject "$timeStamp Could not find User, but their IP is $IPAddress and RuleFile Was Changed" } Else { Out-File -FilePath 'D:\WatcherService\Logs\Changelog.txt' -Append -InputObject "$timeStamp $NameofUser most likely Changed the rules files With IP of $IPAddress" } } } $TimeforFile = get-date -Format $FilePath = "D:\WatcherService\RulesBackup\" + $TimeforFile + ".txt" get-content D:\Admin\Settings\rules.settings | Add-Content $FilePath sleep 10 $GetIP = $Null $TimeforFile = $Null $FilePath = $Null $changeType = $Null $timeStamp = $Null $name = $Null } $today = Get-Date $90Days = $today.adddays(-90) #Gather all files other than 90 days and deletes them. $RulesLogFile = Get-ChildItem "D:\WatcherService\RulesBackup" -Include *.filter -ErrorAction SilentlyContinue | where { $_.lastwritetime -le $90Days -and $_.psIsContainer -eq $false } if ($RulesLogFile -ne $null) { foreach ($Rule in $RulesLogFile) { [string]$Rulefullfilename = $Rule.fullname Remove-Item $Rulefullfilename -ErrorAction SilentlyContinue | out-null } } $RulesLogFile = $Null $today = $Null $90Days = $Null $server = $Null $folder = $Null $filter = $Null $fsw = $Null } } } catch { # Log exception in application log Write-Host $_.Exception.Message } # Adjust sleep timing to determine how often your service becomes active if ($global:bServicePaused -eq $true) { Start-Sleep -Seconds 45 # if the service is paused we sleep longer between checks } else { Start-Sleep -Seconds 30 # a lower number will make your service active more often and use more CPU cycles } } $global:bServiceRunning = $false } function Stop-MyService { $global:bRunService = $false # Signal main loop to exit $CountDown = 30 # Maximum wait for loop to exit while ($global:bServiceRunning -and $Countdown -gt 0) { Start-Sleep -Seconds 1 # wait for your main loop to exit $Countdown = $Countdown - 1 } Get-Job | Stop-Job Unregister-Event FileChanged } function Pause-MyService { # Service is being paused # Save state $global:bServicePaused = $true # Note that the thread your PowerShell script is running on is not suspended on 'pause'. # It is your responsibility in the service loop to pause processing until a 'continue' command is issued. # It is recommended to sleep for longer periods between loop iterations when the service is paused. # in order to prevent excessive CPU usage by simply waiting and looping. } function Continue-MyService { # Service is being continued from a paused state # Restore any saved states if needed $global:bServicePaused = $false }

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s