compare two PowerShell arrays only if they both contain values
Aside from the problem you've reported, your code has a few other issues:

Use of global variables to pass values into (and out of) functions - e.g. $filter00, $filter01 and $matchingNumbers01. It's hard to reason about these in isolation because they depend on program state that exists outside their scope.

Duplication of code as a result - e.g. the functions hour00_numbers and hour01_numbers are identical except for which global variable they reference - this makes maintenance harder.

Performance issues / race condition by repeatedly calling the hour00_numbers and hour01_numbers functions inside matching_numbers01 instead of caching the results into internal variables.


So, here's a refactor that uses function parameters and output streams to address these problems. It also uses some of the feedback in the comments, and it might just accidentally fix your root problem as a side-effect as well...
# define a function to filter the events, give it a meaningful name, and pass
# the raw event list as a parameter so we only need one version of the function
function Get-HourEvents {
    param( $Events )
    foreach($event in $Events) {
        [regex]::Matches($event.Source.Summary -replace ' ', '9 *[45679]( *[0-9]){6}').Value
    }
}

# pass the filtered events in as parameters '$Left' and '$Right',
# and return the results in the output stream so we don't need to
# read global variables. this makes it easier to reason about, and
# a lot easier to test with frameworks like pester
function Get-MatchingEvents {
    param( $Left, $Right )

    if ($null -eq $Left) {
        Write-Host "Left is empty" -ForegroundColor Yellow
    }
    else {
        Write-Host "Left numbers: $Left" -ForegroundColor Green
    }

    if ($null -eq $Right) {
        Write-Host "Right is empty" -ForegroundColor Yellow
    }
    else {
        Write-Host "hour01 numbers: $Right" -ForegroundColor Green
    }

    if (($null -eq $Left) -or ($null -eq $Right) {
        $results = $null
    }
    else {
        $results = Compare-Object $Left $Right -IncludeEqual | Where-Object { $_.SideIndicator -eq '==' } | Select-Object -ExpandProperty InputObject
    }

    if ($null -eq $results) {
        Write-Host "no matching numbers found" -ForegroundColor Green
    }
    else {
        Write-Host "matching numbers are: $results" -ForegroundColor Yellow
        $results
    }

}

# use the functions like this:

# get the filtered event lists
$hour00Events = Get-HourEvents -Events $filter00
$hour01Events = Get-HourEvents -Events $filter01

# match the event lists and assign the result to a variable
$matchingNumbers01 = Get-MatchingEvents -Left $hour00Events -Right $hour01Events

I also took the liberty of inverting some of your if( ... -ne ... ) { ... } else { ... } as I find it easier to think about when the else will trigger if the if uses a "positive" expression otherwise the else condition becomes a double-negative, but that's just personal style - ymmv.
If you're still seeing the same issue with this version of your code feel free to post a comment below...

In the following PowerShell code, functions hour00_numbers and hour01_numbers create two arrays, that contain numbers matching a specific regex.
function hour00_numbers {
    foreach ($event in $filter00) {
        $hour00Numbers = @()
        $hour00Numbers += [regex]::Matches($event.Source.Summary -replace ' ', '9 *[45679]( *[0-9]){6}').Value
        $hour00Numbers
    }
}
    
function hour01_numbers {
    foreach ($event in $filter01) {
        $hour01Numbers = @()
        $hour01Numbers += [regex]::Matches($event.Source.Summary -replace ' ', '9 *[45679]( *[0-9]){6}').Value
        $hour01Numbers
    }
}

I then check if both arrays are not empty, and if they are not, I check to see if they contain matching numbers.
function matching_numbers01 {
    if ($null -ne $(hour00_numbers) -and $null -ne $(hour01_numbers)) {
        $script:matchingNumbers01 = Compare-Object $(hour00_numbers) $(hour01_numbers) -IncludeEqual | Where-Object { $_.SideIndicator -eq '==' } | Select-Object -ExpandProperty InputObject
    }
    else {
        $matchingNumbers01 = $null
    }

    if ($null -ne $(hour00_numbers)) {
        Write-Host "hour00 numbers: $(hour00_numbers)" -ForegroundColor Green
    }
    else {
        Write-Host "hour00 is empty" -ForegroundColor Yellow
    }

    if ($null -ne $(hour01_numbers)) {
        Write-Host "hour01 numbers: $(hour01_numbers)" -ForegroundColor Green
    }
    else {
        Write-Host "hour01 is empty" -ForegroundColor Yellow
    }

    if ($null -ne $matchingNumbers01) {
        Write-Host "matching numbers are: $matchingNumbers01" -ForegroundColor Yellow
    }
    else {
        Write-Host "no matching numbers found" -ForegroundColor Green
    }
}

I'm doing something wrong here though, because I will frequently get a message saying
Cannot bind argument to parameter 'ReferenceObject' because it is null

If either of the two arrays is empty, it shouldn't compare anything. It should only compare the arrays if both are not empty.
What I'm I doing wrong here?
