Skip to main content
Version: 3.0.0-preview

Applicability and reason codes

Every test Maester knows about appears in the result, whether it ran or not. A test that did not run, or did not produce a verdict, has a ReasonCode and a human-readable ReasonDetail on its row. This page explains how Maester reaches that decision and what you can do about each reason.

Use Invoke-Maester -DryRun -PassThru to see the decision for every test without running any test. Each test that would have run is reported as NotRun with reason DryRun; every other row is the row a real run would give. (Pester-format custom tests still go through Pester discovery, which runs their BeforeDiscovery code.)

$plan = Invoke-Maester -DryRun -PassThru
$plan.Tests | Group-Object Result, ReasonCode | Sort-Object Count -Descending | Format-Table Count, Name

The order of the checks​

For each native test, Maester applies these checks in order. The first one that fails decides the row, so a row has exactly one reason.

#CheckFails as
1The test file is valid, loads, has a unique ID and does not need a newer MaesterError
2The test is not disabled in TestSettingsNotRun
3Selection.DefaultAction = Skip and no TestSettings row enables itNotRun
4Selection by ID: -ExcludeTestId, then -TestIdNotRun
5Selection by attribute and tag: -Product, -Feature, -Area, -Severity and -Suite, then -Tag, then the Active Directory opt-in, preview and long-running tests, then -ExcludeTagNotRun
6Platform: the operating system Maester runs onSkipped
7Tenant type (only when enforced)Skipped
8Cloud (only when enforced)Skipped
9Service: every service in Service is known and connectedSkipped
10Licence: the tenant has a compatible licence (only when licences could be read)Skipped
11Parameter values from the config are validError
12-DryRun stops hereNotRun

Then the test runs. A family first calls its instance source; then each instance runs. The test's own outcome decides the rest (see What the function returns).

Rows that come from a check the engine made without running the test (NotRun, and the Skipped rows from checks 6 to 10) still carry the test's description from its .md file. For service and licence skips the row also carries the 2.x skip code in ResultDetail.TestSkipped (for example NotConnectedExchange), so reports read as they did in 2.x.

The facts the checks use​

Maester builds a tenant context once per run and records it in the result as TenantContext. You can see it any time with Get-MtTenantContext.

FactDetected fromWhen it cannot be detected
PlatformThe operating system running PowerShell
ServicesTest-MtConnection for each service the tests needNot connected
LicencesThe tenant's enabled subscribedSkusUnknown: the licence check is skipped and the test runs
Tenant typeorganization.tenantType: AAD is Workforce, CIAM is ExternalUnknown: never skips a test
CloudThe Microsoft Graph environment: Global is Commercial (assumed), USGov is GCCHigh, USGovDoD is DoD, China is ChinaUnknown: never skips a test

GCC tenants use the worldwide Graph endpoint, so they cannot be told apart from Commercial. A GCC tenant states "Cloud": "GCC" under Environment in its config.

Any fact can be forced in the run configuration, and the enforcement of each check can be switched:

{
"Environment": {
"Cloud": "GCC",
"Services": { "Teams": false },
"Enforce": { "Service": true, "License": true, "TenantType": false, "Cloud": false }
}
}

The defaults are shown above: service and licence checks are on; tenant type and cloud are detected and recorded but do not skip tests until you turn them on. The platform check is always on.

Reason codes​

Result is always one of Passed, Failed, Error, Investigate, Skipped and NotRun. Passed, Failed and Investigate rows have no reason code. The reason codes below are a closed list.

NotRun​

The test was not run because of what you asked for.

Reason codeMeaningWhat you can do
DisabledByConfigA TestSettings row sets "Enabled": false. ReasonDetail is the row's Reason, if any.Remove the row or set Enabled to true.
NotListedSelection.DefaultAction is Skip and no TestSettings row sets "Enabled": true for this test (or, for a family, for its parent or any instance).Add { "Id": "<ID>", "Enabled": true }, or use DefaultAction: Run.
ExcludedByIdThe ID matches -ExcludeTestId or Selection.ExcludeTestId.Remove the pattern.
NotSelected-TestId (or Selection.TestId) was given and does not match this test, or -Tag was given and none of the tags selects the test, or the test does not match one of -Product, -Feature, -Area, -Severity and -Suite; ReasonDetail names that selector. For a family, an instance that a -TestId naming other instances did not cover. A Pester-format test is NotSelected whenever the run selects by product, feature or area, because it has none.Add the ID, value or tag, or drop the filter.
ExcludedByTagA tag in -ExcludeTag, Selection.ExcludeTag or PesterConfiguration.Filter.ExcludeTag selects the test.Remove the tag from the exclusions.
PreviewA test with Lifecycle = 'Preview' (in a Pester-format test, the Preview tag), excluded by default.-IncludePreview, any -Tag, Selection.IncludePreview, or name its exact ID in -TestId.
LongRunningA test with LongRunning (in a Pester-format test, the LongRunning tag), excluded by default.-IncludeLongRunning, -Tag LongRunning or -Tag CAWhatIf, Selection.IncludeLongRunning, or name its exact ID in -TestId.
OptInServiceNotConnectedA test that needs Active Directory, and Active Directory is not connected. These tests are opt-in.Connect-Maester -Service ActiveDirectory.
DryRun-DryRun: the test would have run.Run without -DryRun.
DeselectedAtRuntimePester-format tests only: an instance of a test whose name is built at run time ran although the run selected other instances or excluded this one. Its result is not reported.Nothing; select the instances you want by ID.

A wildcard in -TestId does not lift the Preview and long-running exclusions; an exact ID does.

Skipped​

The test applies to some tenants but not, or not now, to this one.

Reason codeMeaningWhat you can do
ServiceNotConnectedA service in the test's Service list is not connected. ReasonDetail names it.Connect it, for example Connect-Maester -Service ExchangeOnline.
ServiceNotRegisteredA custom test names a service this Maester version does not know.Fix the name (see the service list) or update Maester.
LicenseNotFoundThe tenant has none of the licences in License.Nothing, if the licence is not in use. To force the decision, set Environment.Licenses, or turn the check off with Environment.Enforce.License = false.
TenantTypeMismatchTenant type is enforced and the test does not apply to this type of tenant.Turn off Environment.Enforce.TenantType, or correct Environment.TenantType.
CloudMismatchCloud is enforced and the test does not apply to this cloud.Turn off Environment.Enforce.Cloud, or correct Environment.Cloud.
PlatformMismatchThe test runs only on another operating system (for example Windows).Run it on that operating system.
NotApplicableThe test called Add-MtTestResultDetail -SkippedBecause NotApplicable: it decided at run time that it does not apply.Nothing.
TestSkippedThe test skipped itself with -SkippedBecause for another reason. The 2.x code (for example NotSupportedAppPermission) is in ResultDetail.TestSkipped.Read ReasonDetail.
NoInstancesA family's instance source returned nothing: there is nothing in this tenant to check.Nothing.
NoResultThe test returned $null without skipping.For a custom test: return $true or $false, or skip explicitly.

Error​

The test, its configuration or its file has a problem. Errors that Maester raises without running the test fail the run and the CI test results; errors raised by the test itself do not, unless you set Output.ErrorsAsFailures (see Result schema).

Reason codeRaised byMeaningWhat you can do
TestErrorThe testThe test threw an error or called -SkippedBecause Error. ReasonDetail is the first line of the message; ErrorRecord holds the full record.Read the message. Often a missing permission or an API failure.
TimeoutThe testThe test ran longer than its timeout.Raise Execution.TestTimeoutSeconds or the test's TimeoutSeconds.
InvalidReturnThe testThe test returned something that is not $true or $false, or several values.For a custom test: return one boolean, and send stray output to $null.
InvalidMetadataMaesterThe [MaesterTest] attribute, the parameters, or the file layout break a rule, or a custom test has no .md file. ReasonDetail names the file and line.Run Get-MtTest -Path <file> and fix what it lists.
InvalidConfigurationMaesterA parameter value from the config (or Invoke-MtTest -Parameter) is not valid for the test.Fix the value in TestSettings[].Parameters. Get-MtTest <ID> lists the parameters.
LoadFailedMaesterA custom test file does not parse or could not be loaded.Fix the syntax error named in ReasonDetail.
DuplicateIdMaesterTwo native tests have the same ID or function name. Neither runs. (A Pester-format test with the ID of a native test is superseded instead.)Rename one, or delete the copy.
RequiresNewerMaesterMaesterThe test or its suite.json needs a newer Maester.Update Maester.
InstanceSourceFailedMaesterA family's instance source threw. One row on the parent ID.Read the message; often a permission or connection problem.
InvalidInstanceIdMaesterA family's instance source returned an instance whose Id is missing, invalid or repeated. One row on the parent ID.For a custom test: return unique IDs that match ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$.
ForeignModuleLoadedMaesterAnother Maester version was loaded into the session while the test ran (usually because something called a 2.x function), so the result cannot be trusted. Maester removes it and carries on.Uninstall Maester 2.x: Uninstall-Module Maester -MaximumVersion 2.99.99 -AllVersions.
PesterNotAvailableMaesterThe run has Pester-format tests and Pester 5.7.1 or later is not installed.Install-Module Pester -MinimumVersion 5.7.1 -Scope CurrentUser.

Not in the result at all​

Two kinds of test produce no row:

  • A Pester-format test that is a stale copy of a built-in test. It is listed under Selection.Superseded in the result instead. See Pester-format tests.
  • A custom native test that uses the ID of a built-in test. It is not loaded, Maester warns, and the built-in runs.

IDs you name in the selection or the config that match no test are listed under Selection.UnknownIds. By default that is a warning; see Selection.OnUnknownId in the run configuration.