Synopsis #
Proficiency in diagnosing a technical problem is not only dependent on a large number of tests/checks to have in your tool belt, but also on the awareness of the dependency of problem domains. Which results in a logical hierarchy by which tests should be performed. The goal is to give the shortest, most meaningful characterization of the problem.
If your disk is full then further checks for failing application are useless. If your client agent is not running, you don’t need to check for missing updates.
This solution organizes tests by domains/levels in a hierarchy using a nested Powershell hash table. Since the tests are just Powershell script blocks, this comes natural with syntax checks and highlighting in your favorite code editor.
@{
# check system PATH
'path_exists' = { Test-Path $env:windir }
# check free RAM
'mem_free' = { (Get-WmiObject Win32_OperatingSystem).FreePhysicalMemory -gt 100MB }
# sub-section
'service' = @{
# service exists
'exist' = {
if ( Get-Service -Name 'svcname' ) { $true }
else { 'not found' }
}
# sub-sub-section
'file' = @{
# last modification
'age' = { ( (Get-Date) - $myfile.LastWriteTime ).TotalMinutes -le 10 }
}
}
}
Let’s assume memory is exhausted: The only result will be :mem_free. The deeper checks service:exist and file:age will be skipped because they depend on the previous.
On the other hand, if all previous tests succeed but $myfile is older than 10 minutes, then the only result will be file:age.
Rules for writing tests #
A test is a name/value pair where the value is a script block
'test name' = { ... }
A sub-section of tests is a name/value pair where the value is a hash table
'section name' = @{ ... }
A sub-section is only processed after all tests of the current sections are successful.
- A test is successful when the script block returns
[bool] $true. - A test fails when the script block returns
[bool] $false,$nullor any other object. The returned object will be appended to the test name as a string in the output. - A test is also considered failed if the script block throws an exception. The description of the exception will be appended to the output.
- If your test defines the variable $v the content will be appended to the output in -Verbose mode
- Do not call
breakin your script block since this will terminate all tests below the current level. - Do not use
throwin your script block but rather if/then/else structures. Leave exceptions to really unexpected situations. - A variable you declare in one test is available for use in the subsequent tests.
- Tests and sub-sections of the same level are executed by alphabetical order - not necessarily in the order defined in the file. Make sure to define your tests in alphabetical order to avoid confusion.
- Sections can be made optional by using a special test name
'?'. The section is skipped when this test fails.
