Created
September 10, 2021 20:59
-
-
Save joshooaj/93f01d5e7fe6baca0c4d72c944a646da to your computer and use it in GitHub Desktop.
An example of how you might define a Milestone XProtect storage configuration template and use it to create/update live & archive storage to match
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Prompts you to choose a Recording Server to apply the template to | |
| $recordingServer = Get-RecordingServer | Out-GridView -OutputMode Single | |
| if ($null -eq $recordingServer) { | |
| throw 'No Recording Server was selected' | |
| } | |
| # The template definition | |
| $storageTemplate = @{ | |
| Live = @{ | |
| Name = 'Primary' | |
| Description = '' | |
| DiskPath = 'C:\MediaDatabase\' | |
| Signing = $true | |
| RetentionTime = New-TimeSpan -Days 7 | |
| RetentionSize = 1TB / 1MB | |
| } | |
| Archives = @( | |
| @{ | |
| Name = 'First Month' | |
| Description = '' | |
| DiskPath = 'C:\MediaDatabase\' | |
| RetentionTime = New-TimeSpan -Days 31 | |
| RetentionSize = 100TB / 1MB | |
| TargetFps = 10 | |
| FramerateReductionEnabled = $false | |
| }, | |
| @{ | |
| Name = 'First Year' | |
| Description = '' | |
| DiskPath = 'C:\MediaDatabase\' | |
| RetentionTime = New-TimeSpan -Days 365 | |
| RetentionSize = 1PB / 1MB | |
| TargetFps = 1 | |
| FramerateReductionEnabled = $true | |
| } | |
| ) | |
| } | |
| # Retrieve the live storage matching the name from the template. If it doesn't exist, create it. | |
| $liveStorage = $recordingServer | Get-VmsStorage | Where-Object Name -eq $storageTemplate.Live.Name | |
| if ($null -eq $liveStorage) { | |
| $task = $recordingServer.StorageFolder.AddStorage($storageTemplate.Live.Name, $storageTemplate.Live.Description, $storageTemplate.Live.DiskPath, $storageTemplate.Live.Signing, [int]$storageTemplate.Live.RetentionTime.TotalMinutes, $storageTemplate.Live.RetentionSize) | |
| } | |
| else { | |
| # Looks like it exists, lets update everything to make sure it matches the template | |
| $liveStorage.Description = $storageTemplate.Live.Description | |
| $liveStorage.Signing = $storageTemplate.Live.Signing | |
| $liveStorage.RetainMinutes = [int]$storageTemplate.live.RetentionTime.TotalMinutes | |
| $liveStorage.MaxSize = $storageTemplate.Live.RetentionSize | |
| $liveStorage.Save() | |
| # Lets check the disk path matches our template. I'm using Join-Path here to just make sure the template and the actual path both have slashes at the end | |
| $expectedPath = Join-Path $storageTemplate.Live.DiskPath \ | |
| $currentPath = Join-Path $liveStorage.DiskPath \ | |
| if ($expectedPath -ne $currentPath) { | |
| Write-Warning "Storage path for $($liveStorage.Name) is '$currentPath'. Expected '$expectedPath'" | |
| # Maybe add a parameter to the script to choose whether you want to change the storage path if it doesn't match the template? | |
| # You would do so by calling $liveStorage.MoveRecordingStorage($expectedPath) and maybe monitoring the task for completion. | |
| } | |
| } | |
| # Now we'll grab all the archives associated with the live storage we just created/updated | |
| $archives = $liveStorage | Get-VmsArchiveStorage | Sort-Object RetainMinutes | |
| for ($i = 0; $i -lt $storageTemplate.Archives.Count; $i += 1) { | |
| $archiveTemplate = $storageTemplate.Archives[$i] | |
| $archive = $archives[$i] | |
| if ($null -eq $archive) { | |
| # Guess this archive doesn't exist yet - let's create it. | |
| $invokeResult = $liveStorage.ArchiveStorageFolder.AddArchiveStorage($archiveTemplate.Name, $archiveTemplate.Description, $archiveTemplate.DiskPath, $archiveTemplate.TargetFps, $archiveTemplate.RetentionTime.TotalMinutes, $archiveTemplate.RetentionSize) | |
| if ($invokeResult.State -ne [VideoOS.Platform.ConfigurationItems.StateEnum]::Success) { | |
| Write-Error $invokeResult.ErrorText | |
| # Something horrible just happened, let's stop and compose ourselves. | |
| break | |
| } | |
| # Now that we've created the archive, let's instantiate it and assign it to a variable | |
| $archive = [VideoOS.Platform.ConfigurationItems.ArchiveStorage]::new((Get-Site).FQID.ServerId, $invokeResult.GetProperty('Path')) | |
| } | |
| # At this point, we might have just created the archive, or it might have already existed. No matter. We'll just double check that all the properties are set to what we want them to be. | |
| $archive.Description = $archiveTemplate.Description | |
| $archive.TargetFramerate = $archiveTemplate.TargetFps | |
| $archive.RetainMinutes = $archiveTemplate.RetentionTime.TotalMinutes | |
| $archive.MaxSize = $archiveTemplate.RetentionSize | |
| $archive.Save() | |
| if ($archiveTemplate.FramerateReductionEnabled -ne $archive.FramerateReductionEnabled) { | |
| # We can't directly change this boolean value. Instead, we'll retrieve an invokeinfo object, fill it out, and then execute it - this is Milestone config api stuff. | |
| $invokeInfo = $archive.SetFramerateReductionArchiveStorage() | |
| $invokeInfo.SetProperty('FramerateReductionEnabled', $archiveTemplate.FramerateReductionEnabled) | |
| $invokeResult = $invokeInfo.ExecuteDefault() | |
| if ($invokeResult.State -ne [VideoOS.Platform.ConfigurationItems.StateEnum]::Success) { | |
| Write-Error "Error setting FramerateReductionEnabled: $($invokeResult.ErrorText)" | |
| } | |
| } | |
| $expectedPath = Join-Path $archiveTemplate.DiskPath \ | |
| $currentPath = Join-Path $archive.DiskPath \ | |
| if ($expectedPath -ne $currentPath) { | |
| Write-Warning "Storage path for $($liveStorage.Name) / $($archive.Name) is '$currentPath'. Expected '$expectedPath'" | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment