MilestoneSystemsInc / PowerShellSamples

A collection of samples for managing your Milestone XProtect VMS using MilestonePSTools in PowerShell
https://www.milestonepstools.com
MIT License
37 stars 12 forks source link

Send-UserDefinedEvent 23.2.3 regression #113

Closed Silex closed 1 year ago

Silex commented 1 year ago

Hello,

Send-UserDefinedEvent from MilestonePSTools 23.2.3 seems to be not working with 2020 R3:

PS C:\> Get-UserDefinedEvent -Name 'Test' | Send-UserDefinedEvent

Send-UserDefinedEvent : Object reference not set to an instance of an object.
At line:1 char:52
+ ... nedEvent -Name 'Test' | Send-UserDefinedEvent
+                                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Send-UserDefinedEvent], NullReferenceException
    + FullyQualifiedErrorId : Object reference not set to an instance of an object.,MilestonePSTools.EventCommands.SendUserDefinedEvent

If I downgrade MilestonePSTools to 23.1.3 then it works. Did not try more recent versions.

joshooaj commented 1 year ago

Thanks @Silex,

That old command definitely needs refactoring, but I can't reproduce the error. Can you expand $Error[0] for me? I'm suspecting there's an issue connecting to a URL - maybe a certificate issue getting buried under a layer of exceptions?

# trigger the error then...

$Error[0] | Format-List * -Force

$Error[0].Exception | Format-List * -Force

$Error[0].Exception.InnerException | Format-List * -Force
joshooaj commented 1 year ago

@Silex,

Okay it turns out I can reproduce the issue as long as I try to activate a user defined event in the same PowerShell session where it was created without first running Clear-VmsCache.

The Send-UserDefinedEvent command makes a bad assumption that the user defined event can be found using VideoOS.Platform.Configuration.Instance.GetItem(Guid id, Guid, kind), but the configuration items in that area of the SDK are not reloaded automatically so if the event didn't exist when you logged in, GetItem() returns null and Send-UserDefinedEvent doesn't bother to check.

Can you verify whether this works for you?

$ude = Add-UserDefinedEvent -Name 'Issue-113'
Clear-VmsCache
Get-UserDefinedEvent -Name 'Issue-113' | Send-UserDefinedEvent

I can make a minor change to the command so that instead of retrieving the FQID for the event from VideoOS.Platform.Configuration, it is created from scratch. That way we don't make the assumption that the event is found in the currently cached configuration.

I'm also open to feedback on what you would like to see in a rewrite of UserDefinedEvent related commands as the current ones aren't very well written :)

Silex commented 1 year ago

It was not for a user defined event I created during the powershell session. The server uses no certificates.

The code is like this in some loop that runs periodically:

if ($someEvent) {
    Connect-ManagementServer
    Get-UserDefinedEvent -Name 'Intrusion Portes' | Send-UserDefinedEvent
    Disconnect-ManagementServer
}
joshooaj commented 1 year ago

I wonder if it's a timing thing and VideoOS.Configuration.Instance.GetItem(...) returns $null because it hasn't received the configuration from the management server in the background yet? I would hope/think that the SDK would block until the configuration is loaded but maybe it isn't?

Can you try this out and see how long it takes to retrieve the event?

Connect-Vms
$sw = [system.diagnostics.stopwatch]::StartNew()
$ude = Get-UserDefinedEvent -Name 'Intrusion Portes'
$attempts = 0
do {
    Write-Host "Attempt $((++$attempts))"
    $item = [videoos.platform.configuration]::Instance.GetItem(
        $ude.Id,
        [videoos.platform.kind]::TriggerEvent
    )
    if ($null -eq $item) {
        Write-Warning 'Configuration.Instance.GetItem(..) returned $null'
        Start-Sleep -Seconds 1
    }
} while ($null -eq $item)
Write-Host "It took $($sw.Elapsed.TotalSeconds) seconds to load the system configuration."
$ude | Send-UserDefinedEvent
Disconnect-Vms
joshooaj commented 1 year ago

You can also use [videoos.platform.sdk.environment]::ReloadConfiguration((Get-VmsSite).FQID) } to explicitly reload configuration - it would be interesting to know how long it takes. But according to the SDK docs it seems like any call to GetItem() should block until the configuration is loaded.

Measure-Command {
 [videoos.platform.sdk.environment]::ReloadConfiguration((Get-VmsSite).FQID)
} | Select-Object TotalMilliseconds
Silex commented 1 year ago

I tried to reproduce the problem today and it was gone 🤷

Not sure what it was.