Styling & Conventions
This page documents the coding conventions and style guidelines for the NinjaOne PowerShell module.
Naming Conventions
Functions
Follow PowerShell's Verb-Noun naming pattern:
# Good
Get-NinjaOneDevice
Set-NinjaOneDeviceName
New-NinjaOneTag
Remove-NinjaOneTag
Invoke-NinjaOneDeviceRestart
# Bad
GetDevice # Missing module prefix
NinjaDevice # Missing verb
Get-Device-Details # Too many hyphens, unclear scope
GetNinjaOneDevice # No hyphens (not PowerShell style)
Rules:
- Use Approved Verbs from PowerShell's official list (
Get-Verb) - Approved verbs for NinjaOne context:
Get,Set,New,Remove,Invoke,Enable,Disable,Test,Update,Restore,Backup - Always include the module prefix:
NinjaOne - Separate with hyphens:
Verb-NounNoun
Function Parameters
Use PascalCase for parameter names:
# Good
param(
[string]$deviceId,
[string]$organisationId,
[int]$pageSize,
[switch]$includeDetails
)
# Bad
param(
[string]$device_id, # Snake case
[string]$DeviceID, # All caps (use camelCase for multi-word)
[int]$page_size, # Snake case
[switch]$IncludeDetails # Should be camelCase not PascalCase
)
Rules:
- Start with lowercase (except switches which are descriptors)
- Use camelCase for multi-word parameters
- Avoid underscores; use overlapping words or abbreviations
- Switches should be descriptive:
$includeInactive,$skipValidation, not$ior$s
Variables
Use camelCase for local variables:
# Good
$deviceName = $device.name
$requestUri = "https://api/devices/$deviceId"
$processedItems = @()
# Bad
$DeviceName = $device.name # PascalCase
$_requestUri = $requestUri # Leading underscore (private members)
$processed_items = @() # Snake case
Rules:
- Use camelCase consistently
- Private/internal variables: consider context clarity over convention
- Avoid single letters except in loops:
for ($i = 0; ...)
Classes and Enums
Use PascalCase:
# Good
class NinjaOneOrganisationDocument { }
enum DeviceStatus { Active; Inactive; Archived }
# Bad
class ninjaOneOrganisationDocument { }
enum device_status { }
Code Style
Parameter Declarations
Align parameter attributes for readability:
# Good - aligned
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$deviceId,
[Parameter(ValueFromPipeline)]
[AllowNull()]
[object]$device,
[ValidateRange(1, 100)]
[int]$pageSize = 50
)
# Acceptable - compact
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$deviceId,
[object]$device,
[int]$pageSize = 50
)
# Avoid - hard to read
param([Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$deviceId,[object]$device,[int]$pageSize = 50)
Rules:
- One parameter per line
- Attributes above parameter name
- Descriptive comments for clarity
- Include defaults when appropriate
Function Structure
Standard layout for NinjaOne functions:
<#
.SYNOPSIS
Brief description.
.DESCRIPTION
Detailed description.
.PARAMETER deviceId
The device ID.
.EXAMPLE
Get-NinjaOneDevice -deviceId 123
.OUTPUTS
[PSCustomObject] Device information.
#>
function Get-NinjaOneDevice {
[CmdletBinding()]
[OutputType([object])]
param(
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[string]$deviceId # The device ID to retrieve
)
begin {
# Setup code
}
process {
# Main logic
try {
$null = Invoke-NinjaOnePreFlightCheck
$requestUri = "https://api.ninjarmm.com/v2/devices/$deviceId"
$response = Invoke-NinjaOneGETRequest -Uri $requestUri
return $response
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
}
end {
# Cleanup code
}
}
Structure:
- Comment-based help (
<#...#>) [CmdletBinding()]attribute[OutputType()]attribute (when return type is consistent)param()block with inline parameter descriptionsbegin { },process { },end { }sections (if needed)- Use
try/catchfor error handling - Throw terminating errors with
$PSCmdlet.ThrowTerminatingError()
Conditionals
Use consistent formatting:
# Good - readable
if ($device.status -eq 'Active') {
Write-Verbose "Device is active"
} elseif ($device.status -eq 'Inactive') {
Write-Verbose "Device is inactive"
} else {
Write-Verbose "Device is archived"
}
# Avoid - cramped
if ($device.status -eq 'Active') { Write-Verbose "Device is active" } elseif ($device.status -eq 'Inactive') { Write-Verbose "Device is inactive" } else { Write-Verbose "Device is archived" }
Rules:
- Open brace on same line
- One statement per line in block
- Use
elseif(notelse if) - For simple conditions, parentheses optional but recommended
String Formatting
Prefer backticks or string interpolation over concatenation:
# Good - string interpolation
$message = "Device $deviceId not found"
$uri = "https://api.ninjarmm.com/v2/devices/$deviceId/details"
# Good - multiline (backticks)
$message = `
"Processing device $deviceId " +
"in organisation $organisationId"
# Avoid - hard to read concatenation
$message = "Device " + $deviceId + " not found"
# Avoid - mixed styles
$uri = "https://api.ninjarmm.com/v2/devices/" + $deviceId + "/details?filter=" + $filter
Rules:
- Use
"string with $variable"for interpolation - Use
@" ... "@for multiline strings - Use
+for complex expressions only - Avoid excessive concatenation
Collections
Use array syntax clearly:
# Good - explicit array
$ids = @(1, 2, 3)
$items = @()
# Good - pipeline
$items = Get-Item -Path *.ps1
# Avoid - ambiguous
$ids = 1, 2, 3
$items = @
# Avoid - unnecessary conversion
$ids = @(@(1, 2, 3))
Rules:
- Use
@()for empty arrays:$items = @() - Use
@(value1, value2)for multi-item arrays - Single items don't need
@()prefix - Avoid nested
@()unless necessary
Error Handling
Use structured error handling:
# Good
try {
$response = $url | Invoke-WebRequest
}
catch [System.Net.HttpRequestException] {
Write-Error "HTTP request failed: $_"
return $null
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
# Acceptable for internal functions
try {
$response = $url | Invoke-WebRequest
}
catch {
throw "Failed to fetch: $_"
}
Rules:
- Catch specific exceptions when possible
- Log/write error before returning early
- Use
$PSCmdlet.ThrowTerminatingError($_)for fatal errors - Include
$_or$_.Exception.Messagein error output
API Design Patterns
Parameter Guidelines
Required Parameters: Use [Parameter(Mandatory)]
param(
[Parameter(Mandatory)]
[string]$deviceId # Always required
)
Pipeline Support: Enable pipeline binding when logical
param(
[Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
[object]$device # Accept device objects from pipeline
)
Common Parameter Sets: Define overlapping parameters
param(
[Parameter(Mandatory, ParameterSetName = 'ByDeviceId')]
[string]$deviceId,
[Parameter(Mandatory, ParameterSetName = 'ByName')]
[string]$deviceName,
[Parameter(Mandatory, ParameterSetName = 'ByObject')]
[object]$device
)
Return Values
Always be explicit about return types:
[OutputType([object])]
function Get-NinjaOneDevice {
return $response
}
[OutputType([bool])]
function Test-NinjaOneDeviceAccess {
return $true
}
# Returns $null - no [OutputType] attribute
function Initialize-NinjaOneSession {
# No return statement
}
Rules:
- Specify
[OutputType()]with type in brackets - Return consistent types (not sometimes array, sometimes single item)
- Use
[object]for complex/heterogeneous returns - For multiple types:
[OutputType([object[]], [bool])]
Filtering and Selection
For functions that filter or retrieve collections:
# Good - logical parameters
param(
[ValidateSet('Active', 'Inactive', 'Archived')]
[string]$status, # Filter by status
[ValidateRange(1, 1000)]
[int]$limit = 100, # Limit results
[int]$offset = 0, # Pagination offset
[string]$filter # OData filter expression
)
# Bad - too many optional numeric parameters
param(
[int]$skip,
[int]$take,
[int]$pageNumber,
[int]$pageSize,
[int]$offset
)
Rules:
- Consolidate related filtering into one parameter when possible
- Use
ValidateSetfor predefined options - Support pagination with consistent naming:
offset/limitorpage/pageSize - Document filter syntax in help
Documentation Impact
Code style directly affects generated documentation:
'Well-styled function:
function Get-NinjaOneDevice {
<#
.SYNOPSIS
Retrieves a specific NinjaOne device.
.PARAMETER deviceId
The device ID to retrieve # ← In generated docs
#>
param(
[Parameter(Mandatory)]
[string]$deviceId # The device ID to retrieve # ← Also in generated docs
)
}
# Generates:
# Get-NinjaOneDevice [-deviceId] <string>
#
# Retrieves a specific NinjaOne device.
#
# Parameters:
# -deviceId <string>
# The device ID to retrieve
Always write code as if documentation will be auto-generated—because it will be.
PR Checklist for Style
Before submitting, verify:
- Function names follow
Verb-NounNounpattern - Parameter names use camelCase
- All parameters have descriptions (inline comment or .PARAMETER)
- Return type specified with
[OutputType()] - Comment-based help complete (SYNOPSIS, DESCRIPTION, examples)
- Error handling uses try/catch with
$PSCmdlet.ThrowTerminatingError() - No PSScriptAnalyzer violations
- Code passes style checks in test suite