This document defines the recommended practices for using, maintaining, and extending the PowerShell IT Support Toolkit.
The goal is to ensure that toolkit scripts remain:
- Reliable
- Safe to execute
- Consistent with the project architecture
- Maintainable
- Predictable for IT support operations
- Easy to troubleshoot and extend
- Suitable for professional IT support environments
These guidelines apply to anyone who uses, reviews, maintains, or contributes to the toolkit.
All toolkit development and usage should follow these principles:
Scripts must prioritize system safety over convenience.
A script should never:
- Delete or modify system data without explicit justification.
- Execute destructive operations without appropriate validation.
- Modify configuration outside its documented scope.
- Trust user-provided paths or values without validation.
- Disable security controls unnecessarily.
- Use elevated privileges when they are not required.
When an operation can fail safely, it should fail safely.
Each script should have a clearly defined responsibility.
A script should:
- Perform the operation described by its name.
- Preserve documented parameters.
- Produce predictable output.
- Handle expected failures gracefully.
- Avoid unexpected side effects.
Avoid combining unrelated administrative tasks into a single script.
Scripts should follow the same conventions throughout the toolkit.
This includes:
- Approved PowerShell verbs
- Consistent parameter naming
- Common module usage
- Error-handling conventions
- Reporting conventions
- Output formatting
- Path handling
- Documentation style
Consistency makes the toolkit easier to operate and maintain.
When maintaining an existing script:
Fix the actual problem without unnecessarily changing correct behavior.
Do not refactor working code simply because another implementation appears cleaner.
Any modification should have a clear technical reason.
Functions and scripts should use approved PowerShell verbs whenever possible.
Examples:
| Purpose | Recommended Verb |
|---|---|
| Retrieve information | Get- |
| Create something | New- |
| Remove something | Remove- |
| Update something | Set- |
| Invoke an operation | Invoke- |
| Test a condition | Test- |
| Export data | Export- |
| Import data | Import- |
| Start an operation | Start- |
| Stop an operation | Stop- |
Examples:
Get-SystemInfo
Get-Processes
Get-AllServices
Invoke-NetworkDiagnostics
Clear-TempFiles
Export-EventLogs
New-PCReportAvoid inventing non-standard verbs when an approved PowerShell verb accurately describes the operation.
Names should communicate purpose without requiring the reader to inspect the implementation.
Prefer:
$CommonModule
$ScriptsRoot
$ExportPath
$TargetPath
$FilesDeletedAvoid unnecessarily cryptic names such as:
$x
$tmp
$obj1
$data2Short variables are acceptable for very small local scopes when their meaning is obvious.
Values that users may reasonably need to change should generally be exposed through parameters rather than hardcoded.
Example:
param(
[string]$ExportPath
)Parameters should have:
- Clear names
- Appropriate types
- Validation where necessary
- Useful defaults when appropriate
- Documentation in the comment-based help
Do not add parameters simply to increase flexibility.
Input validation is particularly important for scripts that:
- Delete files
- Modify configuration
- Create users
- Change networking settings
- Export data
- Interact with system paths
Validation should reject unsafe or invalid input before the destructive operation begins.
For example:
[ValidateRange(0, 3650)]
[int]$OlderThanDays = 0Validation should be proportional to the risk of the operation.
Toolkit scripts should use:
Set-StrictMode -Version LatestThis helps identify:
- Undefined variables
- Invalid property access
- Other programming mistakes
Strict mode should be combined with deliberate error handling rather than disabled to hide implementation problems.
Toolkit scripts generally use:
$ErrorActionPreference = 'Stop'This allows unexpected errors to reach the script's established error-handling path.
Individual commands may override this behavior when a failure is expected and intentionally handled.
For example:
Get-Process -ErrorAction SilentlyContinueshould only be used when the script has a deliberate reason to tolerate command-level failures.
Do not use SilentlyContinue simply to hide errors.
Scripts should use the established project pattern:
try {
# Main operation
}
catch {
Write-ErrorMessage ("[{0}] {1}" -f $_.Exception.GetType().Name, $_.Exception.Message)
exit 1
}This provides consistent error reporting across the toolkit.
Do not introduce a completely different error-handling architecture for an individual script without a strong technical reason.
Some operations are naturally unreliable.
Examples include:
- Reading information from protected processes
- Accessing locked files
- Querying unavailable services
- Reading restricted event logs
- Accessing network resources
These failures should be handled at the smallest appropriate scope.
For example, if one process property cannot be read, the entire process-report operation should not necessarily fail.
Prefer:
try {
$description = $process.Description
}
catch {
$description = $null
}when an unavailable description is an expected condition.
Do not catch errors without deciding what the failure means.
Scripts should operate with the minimum privileges required.
Do not require Administrator privileges simply because they are convenient.
Administrator privileges should only be required when the underlying Windows operation genuinely requires them.
Do not introduce mechanisms such as:
-ExecutionPolicy Bypassunless there is a clearly documented and justified requirement.
The toolkit should not weaken the host security configuration merely to make script execution easier.
Do not construct executable commands from untrusted input.
Avoid patterns where user input is directly inserted into dynamically executed code or command strings.
Prefer PowerShell parameters and the call operator:
& $ExecutablePath -ArgumentList $Argumentsover dynamically constructed command text.
Scripts that operate on paths should:
- Resolve the intended path.
- Verify that the path exists when required.
- Verify whether it is a file or directory.
- Validate that it is within the intended scope.
- Reject dangerous system locations when the operation is destructive.
Destructive scripts should never assume that a user-provided path is safe.
Cleanup operations should delete only the intended contents.
The target directory itself should remain intact unless deleting the directory is explicitly the documented purpose of the script.
This is especially important for:
- Temporary-file cleanup
- Cache cleanup
- Log cleanup
- Backup cleanup
Before deleting or modifying files recursively, verify that the resolved path is not an unintended parent directory.
Dangerous targets include locations such as:
- A filesystem root
- Windows system directories
- Program installation directories
- User profile roots
- Other critical application data directories
Safety checks should be based on resolved paths rather than only the raw user input.
When working with paths supplied as literal file-system paths, prefer:
-LiteralPathwhen wildcard expansion is not intended.
Example:
Get-Item -LiteralPath $PathThis prevents special wildcard characters from unexpectedly changing the target.
Recursive operations should remain within the intended scope.
Be particularly careful with:
- Reparse points
- Symbolic links
- Junctions
- Mounted locations
A cleanup script should never unexpectedly traverse into another volume or unrelated directory tree.
Counters and reports should reflect what actually happened.
For example:
FilesScanned
FilesDeleted
FilesFailed
BytesFreed
BytesFreed must only include files that were successfully deleted.
Do not increment success counters before the operation actually succeeds.
Scripts should use the project's established reporting mechanisms where applicable.
For example:
Export-ToolkitReportshould be preferred over creating a separate export implementation.
This keeps report formats consistent across the toolkit.
When producing report data, prefer:
[PSCustomObject]@{
Id = $process.Id
Name = $process.Name
CPU = $cpu
MemoryMB = $memory
}Structured objects are easier to:
- Export
- Filter
- Test
- Consume programmatically
- Convert to JSON
Use the project's common output functions when available:
Write-Info
Write-Success
Write-WarningMessage
Write-ErrorMessage
Write-Section
Show-SystemReportAvoid implementing a new output style inside an individual script without a technical reason.
The toolkit uses shared modules to avoid duplicating common functionality.
Before creating a new helper function, check whether the required functionality already exists in:
scripts\common\
Relevant shared functionality may include:
- Common output
- Logging
- Reporting
- Path handling
- Utility functions
Do not duplicate existing functionality inside individual scripts unless there is a clear reason.
Changes to:
scripts\common\Common.psm1
scripts\common\Logger.psm1
scripts\common\Utilities.psm1
can affect many scripts.
Before changing a shared module:
- Identify every script that depends on it.
- Verify the intended behavior.
- Determine whether the change is backward-compatible.
- Test affected scripts.
- Avoid changing public behavior unnecessarily.
Each script should have one primary responsibility.
For example:
Get-SystemInfo.ps1
should collect system information rather than also modifying network settings or cleaning temporary files.
This improves:
- Testing
- Reusability
- Troubleshooting
- Maintainability
IT-Toolkit.ps1 acts as the interactive entry point.
Its primary responsibilities should remain:
- Displaying the menu
- Accepting user input
- Selecting the appropriate backend script
- Handling high-level execution status
Business or administrative logic should remain in the specialized scripts.
Project-relative paths should be constructed from $PSScriptRoot.
Example:
$CommonModule = Join-Path $PSScriptRoot "..\common\Common.psm1"Avoid assuming that the user launched the script from a specific working directory.
This allows scripts to work correctly when launched from:
- PowerShell
- The toolkit orchestrator
- Another working directory
- Automation environments
Only import modules that the script actually requires.
Unused imports:
- Increase coupling
- Make troubleshooting harder
- Increase startup complexity
- Can create unnecessary failure points
Before adding a module dependency, verify that the script actually uses functionality provided by that module.
When maintaining an existing script, treat these as part of its public interface:
- Script name
- Parameters
- Parameter defaults
- Expected output
- Report fields
- Export behavior
- Exit behavior
- Menu integration
Do not change these unless a genuine defect requires it.
Each toolkit script should contain useful comment-based help.
At minimum, document:
.SYNOPSIS
.DESCRIPTION
.PARAMETER
.EXAMPLE
.NOTES
Documentation should explain what the script does rather than merely restating its filename.
Examples should be realistic and executable.
Every modified script should be validated before being considered complete.
Use PowerShell's parser to verify syntax.
Example:
$errors = $null
[System.Management.Automation.Language.Parser]::ParseFile(
$ScriptPath,
[ref]$null,
[ref]$errors
)
if ($errors) {
Write-Host "SYNTAX: FAILED"
}
else {
Write-Host "SYNTAX: OK"
}Test the normal execution path.
Verify:
- Expected output
- Expected report structure
- Correct exit behavior
- Correct file operations
- Correct parameter handling
Do not test only successful scenarios.
Where applicable, test:
- Invalid paths
- Missing files
- Access denied
- Locked files
- Protected processes
- Invalid parameters
- Missing dependencies
- Failed child scripts
- Export failures
A script is not considered reliable simply because the happy path works.
When a script is exposed through IT-Toolkit.ps1, test it through the actual menu as well as directly.
This verifies:
- Backend mapping
- Child-process execution
- Exit-code handling
- Menu recovery
- Logging behavior
Before modifying an existing script:
- Read the entire script.
- Inspect the modules it depends on.
- Identify the actual defect.
- Confirm that the behavior is genuinely incorrect.
- Make the smallest safe change.
- Re-run syntax validation.
- Test the affected functionality.
- Verify that unrelated functionality remains unchanged.
Do not make changes merely because an alternative implementation looks cleaner.
Before considering a security-sensitive script complete, verify:
- User input is validated.
- File-system paths are resolved safely.
- Destructive operations have safety checks.
- Administrator privileges are only used when necessary.
- Security controls are not unnecessarily disabled.
- Dynamic command execution is avoided where possible.
- Recursive operations cannot unexpectedly escape their intended scope.
- Errors do not result in misleading success messages.
- Sensitive information is not unnecessarily written to logs.
- Temporary test artifacts are removed after validation.
Before using a toolkit script during an IT support task:
- Confirm the intended target system.
- Understand what the script will change or collect.
- Review parameters before execution.
- Confirm that administrative privileges are appropriate.
- Avoid destructive operations unless required.
- Preserve relevant reports and diagnostic output.
- Record important failures or warnings.
- Verify the result after the operation.
- Escalate when the operation is outside the script's documented scope.
When adding or modifying a toolkit script:
- Follow the existing project architecture.
- Use approved PowerShell verbs.
- Add comment-based help.
- Use appropriate parameters.
- Validate risky input.
- Use
Set-StrictMode -Version Latest. - Follow the project's error-handling pattern.
- Reuse common modules where appropriate.
- Avoid unnecessary dependencies.
- Preserve existing report structures.
- Test both success and failure paths.
- Validate integration with
IT-Toolkit.ps1when applicable. - Do not modify unrelated files.
- Verify the final files after editing.
The most important maintenance principle for this toolkit is:
Find the real problem → fix the real problem → verify the fix → preserve everything else.
A successful change is not the change that introduces the most improvements.
A successful change is the smallest justified change that makes the toolkit safer, more reliable, or more correct without breaking established behavior.