Public/Tools/Install-StableFPS.ps1

function Install-StableFPS {
    <#
    .SYNOPSIS
        Install the StableFPS driver on a Recording Server
 
    .DESCRIPTION
        The StableFPS driver is used to add any number of virtual cameras simulated from static video files.
        It includes support for multiple video codecs, audio, metadata, input and output. See the Milestone
        MIP SDK documentation for more information.
 
        This command must be run with elevated permissions due to the fact it must add/modify files in the
        Device Pack installation path which is typically placed in the protected C:\Program Files (x86)\ path.
        It also must stop and start the Recording Server service in order for the new driver to be made available.
 
        If you re-install the StableFPS driver with different parameters, or if you add new video/audio to the
        %DevicePackPath%\StableFPS_DATA folder, you will need to perform "Replace Hardware" on each StableFPS
        hardware device you require to use the new settings/media.
 
    .PARAMETER Source
        The path to the StableFPS folder included with the MIP SDK installation. The default path is
        "C:\Program Files\Milestone\MIPSDK\Tools\StableFPS". To execute this command on a system without MIP
        SDK installed, make sure to copy the StableFPS folder to a path available to the target system. If you
        specify "-Path C:\StableFPS" then this command expects to find the folders C:\StableFPS\StableFPS_DATA and
        C:\StableFPS\vLatest
 
    .PARAMETER Cameras
        Each StableFPS hardware device can have between 1 and 200 camera channels associated with it. The default
        value is 32.
 
    .PARAMETER Streams
        Each camera channel can provide up to 5 streams. By default, each channel will provide only one stream.
 
    .PARAMETER DevicePackPath
        By default the DevicePackPath will be determined from the Get-RecorderConfig cmdlet which assumes the
        StableFPS driver is intended to be installed on the local machine which is also a Recording Server. In
        some cases you may wish to install the StableFPS driver to a remote machine. If this property is provided,
        then the driver will be deployed to the path without attempting to restart any Recording Server service or
        validating the presence of a Recording Server installation. It will then be your responsibility to restart
        the remote Recording Server to make the new driver available.
 
    .EXAMPLE
        Install-StableFPS -Source C:\StableFPS -Cameras 4 -Streams 2
 
        Installs the StableFPS driver from the source already present at C:\StableFPS. Each StableFPS device added
        to the Recording Server will have 4 camera channels, each with the option of up to 2 streams.
    #>

    [CmdletBinding()]
    param (
        [Parameter()]
        [string]
        $Source = "C:\Program Files\Milestone\MIPSDK\Tools\StableFPS",
        [Parameter()]
        [int]
        [ValidateRange(1, 200)]
        $Cameras = 32,
        [Parameter()]
        [int]
        [ValidateRange(1, 5)]
        $Streams = 1,
        [Parameter()]
        [string]
        $DevicePackPath
    )

    begin {
        $Elevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
        if (!$Elevated) {
            throw "Elevation is required for this command to work properly. Consider re-launching PowerShell by right-clicking and running as Administrator."
        }
        if (!(Test-Path (Join-Path $Source "StableFPS_DATA"))) {
            throw "Path not found: $((Join-Path $Source "StableFPS_DATA"))"
        }
        if (!(Test-Path (Join-Path $Source "vLatest"))) {
            throw "Path not found: $((Join-Path $Source "vLatest"))"
        }
    }

    process {
        $serviceStopped = $false
        try {
            $dpPath = if ([string]::IsNullOrWhiteSpace($DevicePackPath)) { (Get-RecorderConfig).DevicePackPath } else { $DevicePackPath }
            if (!(Test-Path $dpPath)) {
                throw "DevicePackPath not valid"
            }
            if ([string]::IsNullOrWhiteSpace($DevicePackPath)) {
                $service = Get-Service "Milestone XProtect Recording Server"
                if ($service.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Running) {
                    $service | Stop-Service -Force
                    $serviceStopped = $true
                }
            }

            $srcData = Join-Path $Source "StableFPS_Data"
            $srcDriver = Join-Path $Source "vLatest"
            Copy-Item $srcData -Destination $dpPath -Container -Recurse -Force
            Copy-Item "$srcDriver\*" -Destination $dpPath -Recurse -Force

            $tempXml = Join-Path $dpPath "resources\StableFPS_TEMP.xml"
            $newXml = Join-Path $dpPath "resources\StableFPS.xml"
            $content = Get-Content $tempXml -Raw
            $content = $content.Replace("{CAM_NUM_REQUESTED}", $Cameras)
            $content = $content.Replace("{STREAM_NUM_REQUESTED}", $Streams)
            $content | Set-Content $newXml
            Remove-Item $tempXml
        }
        catch {
            throw
        }
        finally {
            if ($serviceStopped -and $null -ne $service) {
                $service.Refresh()
                $service.Start()
            }
        }
    }
}