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()]
        [array]
        $LicenseManager = $env:LicenseManager
    )
    Write-Verbose "[LicenseManager] Bound Parameters: $($MyInvocation.BoundParameters | Out-String)"
    Write-Verbose "[LicenseManager] Unbound Parameters: $($MyInvocation.UnboundParameters | Out-String)"

    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 ..."
    . "${PSScriptRoot}\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', $PSScriptRoot, $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', $PSScriptRoot, $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
    }
}