Public/Invoke-LicenseManager.ps1
#Requires -RunAsAdministrator <# .Synopsis This is the MAIN script. This script watches for events and sends found events to Invoke-LMEvent for handling. .Parameter LicenseManager A JSON hashtable of processes to concurrency maximum. Example: '{"DirectoryPath":"\\\\license\\LicenseManager","Processes":{"notepad.exe":5,"Calculator.exe":10}}' Done this way so we can use the default of setting this as an Environment Variable for the system. Here's the example, but a little easier to read: { "DirectoryPath": "\\\\license\\LicenseManager", "Processes": { "notepad.exe": 5, "Calculator.exe": 10 } } The number with the process name is the concurrency count. #> function Invoke-LicenseManager { [CmdletBinding()] [OutputType([void])] Param( [Parameter()] [string] $LicenseManager = $env:LicenseManager, [Parameter()] [switch] $Force ) Write-Verbose "[LicenseManager] Bound Parameters: $($MyInvocation.BoundParameters | Out-String)" Write-Verbose "[LicenseManager] Unbound Parameters: $($MyInvocation.UnboundParameters | Out-String)" if ($Force.IsPresent) { Write-Verbose "[LicenseManager] Skipping Duplicate Process Check." } else { if ($proc = Get-WmiObject Win32_Process -Filter "Name = ""powershell.exe"" AND ProcessId <> ""${PID}""" | Where-Object { $_.CommandLine -like '*Invoke-LicenseManager*' }) { Write-Warning "Duplicate process(es) found: $($proc.ProcessId -join ', ')" $proc | ForEach-Object { Write-Verbose "[LicenseManager] $($_.ProcessId): $($_.CommandLine)" } Exit 1 } } $psScriptRootParent = Split-Path $PSScriptRoot -Parent if (-not $LicenseManager) { Throw [System.Management.Automation.ParameterBindingException] 'Required Parameter (LicenseManager) is not available.' } $LicenseManager = $LicenseManager | ConvertFrom-Json $jobScriptBlock = { param( [Parameter(Mandatory = $true)] [string] $Action, [Parameter(Mandatory = $true)] [IO.DirectoryInfo] $ScriptRoot, [Parameter(Mandatory = $true)] [array] $LicenseManager ) . "${ScriptRoot}\Private\Invoke-LMEvent.ps1" $processes = $LicenseManager.Processes.PSObject.Properties.Name | ForEach-Object { "ProcessName = '${_}'" } $processQuery = "SELECT * FROM Win32_Process${Action}Trace WHERE $($Processes -join ' OR ')" $SourceIdentifier = "LicenseManager_Process${Action}_$(New-Guid)" Register-CimIndicationEvent -Query $processQuery -SourceIdentifier $SourceIdentifier while ($true) { $lmEvent = Wait-Event -SourceIdentifier $SourceIdentifier Write-Verbose "[LicenseManager] LM ${Action} Event: $($lmEvent | Out-String)" Remove-Event -EventIdentifier $lmEvent.EventIdentifier Invoke-LMEvent -Action $Action -LicenseManager $LicenseManager -LMEvent $lmEvent -Verbose } } <# Check for currently running processes a get them added. This should really only be needed if the script is being restarted, but let's cover our basis. #> Write-Verbose "[LicenseManager] Intializing ..." . "${psScriptRootParent}\Private\Initialize-LMEntry.ps1" foreach ($process in $LicenseManager.Processes.PSObject.Properties.Name) { Write-Verbose "[LicenseManager] Initializing Process: ${process}" [IO.FileInfo] $process = $process $lmEntry = @{ LicenseManager = $LicenseManager ProcessName = $process.Name } Write-Verbose "[LicenseManager] Initialize-LMEntry: $($lmEntry | ConvertTo-Json)" Initialize-LMEntry @lmEntry } <# Start the Background Job to watch for Processes STARTING. #> $jobProcessStart = Start-Job -Name 'LM_ProcStart' -ScriptBlock $jobScriptBlock -ArgumentList 'Start', $psScriptRootParent, $LicenseManager Write-Verbose "[LicenseManager] Started Job: LM_ProcStart (${jobProcessStart})" <# Start the Background Job to watch for Processes STOPPING #> $jobProcessStop = Start-Job -Name 'LM_ProcStop' -ScriptBlock $jobScriptBlock -ArgumentList 'Stop', $psScriptRootParent, $LicenseManager Write-Verbose "[LicenseManager] Started Job: LM_ProcStop (${jobProcessStop})" <# This is here while developing. Comment this little bit out before going to production. #> # Write-Verbose "[LicenseManager] Running notepad in 3 second ..." # Start-Sleep -Seconds 3 # notepad <# Keep this Process Open; k thanks #> while ($true) { $jobProcessStart | Receive-Job $jobProcessStop | Receive-Job Start-Sleep -Seconds 1 } } |