Have you ever spent more time naming a script than actually writing it?
If you are anything like me, you know the feeling. Summer is here, and I could probably spend the entire holiday just finding the perfect name for my computer - let alone a PowerShell script or function. There is something about naming things that triggers a unique kind of stress. You want the name to be clear, descriptive, and professional, but you also want to move on and actually get work done. Add to that the constraints you face in other contexts - Azure resources that require lowercase names, unique identifiers, and strict character limits - and naming quickly becomes one of those small decisions that feels unreasonably difficult.
There are only two hard things in Computer Science: cache invalidation and naming things.
The good news is that PowerShell has a well-defined naming convention that takes much of the guesswork out of the equation. In my previous post about validating and improving your PowerShell scripts, I touched on code quality, PSScriptAnalyzer, and approved verbs. This post picks up where that guidance left off and focuses entirely on naming - how to choose the right verb, how to craft a meaningful noun, and how to apply these principles consistently across your scripts and functions.
Based on my experience writing and reviewing PowerShell code across multiple projects and organizations, here is what I have learned about getting names right.
The naming problem
The naming problem is universal in software development, and PowerShell is no exception. Whether you are naming a script file, a function, a variable, or a parameter, the same challenge applies: the name needs to communicate intent clearly and concisely.

In everyday IT work, you might encounter naming challenges everywhere:
- Computer names - balancing descriptive meaning with character limits and organizational standards
- Azure resources - lowercase only, globally unique, restricted characters, and length constraints
- File names - choosing between
Delete.ps1,cleanup-script.ps1, or something more descriptive - Function names - making sure your custom code is discoverable and consistent with built-in cmdlets
Some people resort to creative shortcuts like removing vowels or using GUIDs when they run out of ideas. While those approaches might solve uniqueness problems, they do nothing for readability. A script named RmOldFls.ps1 or a function called Do-Thing tells you almost nothing about what the code actually does.
PowerShell solves this elegantly with a convention that has been part of the language since day one: the verb-noun naming pattern.
The verb-noun naming convention
The verb-noun naming convention is the fundamental rule for naming PowerShell scripts and functions. Use a verb-noun pair that clearly indicates what the code does and what it acts on. If you have a script that creates a new user account, name it New-User.ps1. If you have a function that retrieves the status of a service, name it Get-ServiceStatus.
This convention has several benefits:
- Consistency with built-in cmdlets. PowerShell’s own commands follow this pattern -
Get-Process,Set-Item,Invoke-Command. When your custom code follows the same convention, it feels native. - Readability. You can quickly identify what a script or function does.
Remove-ExpiredCertificateis immediately clear.DelCert.ps1is not. - Discoverability. You can use
Get-Command -Verb Getto find all commands that retrieve data, orGet-Command -Noun *User*to find everything related to users. Your custom functions become part of this ecosystem when you follow the convention.
Think of verb-noun naming as a contract with anyone who reads your code - including your future self. The verb tells them what action is performed. The noun tells them what is being acted on. Together, they form a self-documenting name.
How to choose the right verb
PowerShell defines a set of approved verbs that cover the most common actions. You should always use an approved verb rather than inventing your own. This is not just a recommendation - PSScriptAnalyzer will flag non-approved verbs, and Export-ModuleMember issues warnings when modules contain functions with unapproved verbs.
You can see all approved verbs by running:
# Description: Retrieves the complete list of approved PowerShell verbs
# Elevation is not required - This is a read-only query
Get-Verb | Sort-Object -Property Verb | Format-Table -Property Verb, Group, Description -AutoSizeExample: List all approved PowerShell verbs
The approved verbs are organized into groups that help you pick the right one:
| Group | Common verbs | When to use |
|---|---|---|
| Common | Get, Set, New, Remove | Most everyday actions - retrieving, modifying, creating, deleting |
| Data | Import, Export, Convert | Moving data between formats or locations |
| Lifecycle | Start, Stop, Restart, Suspend | Controlling the state of services, processes, or jobs |
| Diagnostic | Test, Measure, Debug | Validating, measuring, or troubleshooting |
| Communication | Send, Receive, Connect | Network and communication operations |
| Security | Grant, Revoke, Protect | Permission and security operations |
Common verb mistakes
Common verb mistakes appear frequently in code I review - here is what to use instead:
| Instead of | Use | Why |
|---|---|---|
Delete-File | Remove-File | “Delete” is not an approved verb. “Remove” is the standard. |
Change-Password | Set-Password | “Change” is not approved. “Set” covers modification actions. |
Run-Script | Invoke-Script | “Run” is not approved. “Invoke” is the standard for executing commands. |
Create-User | New-User | “Create” is not approved. “New” is the standard for creating resources. |
List-Service | Get-Service | “List” is not approved. “Get” covers retrieval actions. |
Check-Status | Test-Status | “Check” is not approved. “Test” is the standard for validation. |
When you are unsure which verb to use, ask yourself: “What is the closest built-in cmdlet that does something similar?” If you are writing something similar to Get-Process, use Get. If it is similar to Invoke-Command, use Invoke. The built-in cmdlets are your best reference.
How to choose a meaningful noun
The noun is where you describe what the verb acts on. A good noun is specific, descriptive, and uses singular form.
Use singular nouns
PowerShell convention uses singular nouns. The cmdlet is Get-Process, not Get-Processes - even though it often returns multiple objects. This is because the noun describes the type of object, not the quantity:
# These all use singular nouns, even when returning collections
Get-Process # Returns multiple processes
Get-Service # Returns multiple services
Get-ChildItem # Returns multiple itemsExample: Singular nouns with plural results
Follow the same pattern in your custom code. Use Get-ExpiredCertificate rather than Get-ExpiredCertificates.
Be specific, not generic
Avoid vague or generic nouns. The more specific you are, the more useful the name becomes:
| Vague name | Better name | Why it is better |
|---|---|---|
Get-Data | Get-DeviceComplianceReport | Describes exactly what data is retrieved |
Set-Item | Set-RegistryBaseline | Specifies the type of item being configured |
Remove-Object | Remove-StaleDeviceRecord | Clarifies what kind of object is removed |
Test-Thing | Test-NetworkConnectivity | Identifies what is being tested |
Use PascalCase for compound nouns
When your noun consists of multiple words, use PascalCase - capitalize the first letter of each word with no separator:
Get-ServiceStatus(notGet-Service-StatusorGet-servicestatus)Remove-ExpiredCertificate(notRemove-Expired-Certificate)Set-DeviceCompliancePolicy(notSet-devicecompliancepolicy)
This is the same casing convention used by all built-in PowerShell cmdlets and .NET types.
Naming your script files
Script file names should follow the same verb-noun pattern as functions. Instead of vague names like script1.ps1 or cleanup.ps1, use names that describe the action and the target:
| Bad name | Good name | What it tells you |
|---|---|---|
script.ps1 | Remove-ExpiredLogFile.ps1 | Removes log files that have expired |
fix.ps1 | Repair-BrokenGroupMembership.ps1 | Fixes group membership issues |
deploy.ps1 | Install-CompanyApplication.ps1 | Installs a specific application |
update.ps1 | Update-DeviceFirmware.ps1 | Updates firmware on a device |
report.ps1 | Export-ComplianceReport.ps1 | Exports a compliance report |
When you name script files this way, you get the same benefits described earlier - consistency, readability, and discoverability - applied directly to your file system. Finding the right script in a folder becomes trivial when all your Get-* scripts group together, and the file name itself tells you what the script does without needing to open it.
Script file naming rules
Script file naming rules are straightforward when you follow a few key conventions:
- Use the verb-noun pattern:
Verb-Noun.ps1 - Use PascalCase:
Get-DeviceInventory.ps1, notget-deviceinventory.ps1 - Use a dash to separate verb and noun:
Get-DeviceInventory.ps1, notGet_DeviceInventory.ps1orGetDeviceInventory.ps1 - Keep the .ps1 extension (or
.psm1for modules) - Avoid spaces, special characters, and excessively long names
Naming your functions
Functions follow the same verb-noun convention as scripts, but there are additional considerations when writing functions that will be part of a module or shared with others.
Match the function name to its purpose
Matching the function name to its purpose means every function should do one thing, and its name should describe that one thing clearly:
# Description: Examples of well-named functions
# Elevation is not required - These are function definitions only
function Get-DeviceComplianceStatus {
<#
.SYNOPSIS
Retrieves the compliance status for a specified device.
#>
param (
[Parameter(Mandatory)]
[string]$DeviceId
)
# Function logic here
}
function Set-AutopilotGroupTag {
<#
.SYNOPSIS
Updates the group tag for a Windows Autopilot device.
#>
param (
[Parameter(Mandatory)]
[string]$SerialNumber,
[Parameter(Mandatory)]
[string]$GroupTag
)
# Function logic here
}
function Test-IntuneEnrollmentRestriction {
<#
.SYNOPSIS
Validates whether a device meets enrollment restriction criteria.
#>
param (
[Parameter(Mandatory)]
[string]$DeviceId
)
# Function logic here
}Example: Well-named functions with clear purposes
Use a namespace prefix for custom modules
When building a module, consider adding a short prefix to your nouns to avoid conflicts with built-in cmdlets and other modules. Microsoft itself does this - the Microsoft Graph PowerShell module uses Mg as a prefix:
# Without prefix - risks collision with other modules
function Get-DeviceStatus { }
# With prefix - clearly belongs to your module
function Get-CorpDeviceStatus { }
function Set-CorpDeviceBaseline { }
function Test-CorpDeviceCompliance { }Example: Using a namespace prefix in a custom module
This pattern makes it clear which module a command belongs to, especially in environments where many modules are loaded simultaneously.
Avoid aliases in scripts and functions
Avoiding aliases in scripts and functions is an important habit for writing readable, portable code. While PowerShell supports aliases like gci for Get-ChildItem or % for ForEach-Object, they are convenient for interactive use in the console, but in scripts they reduce readability and can cause issues in environments with restricted language modes.
PSScriptAnalyzer will flag alias usage in scripts through the PSAvoidUsingCmdletAliases rule. If you have PSScriptAnalyzer integrated into Visual Studio Code - as covered in my post on validating and improving your PowerShell scripts - you will see warnings highlighted in real time as you type. Always use the full cmdlet names:
# Bad - using aliases
gci C:\Logs | ? { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } | rm
# Good - using full cmdlet names
Get-ChildItem -Path "C:\Logs" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
Remove-ItemExample: Avoid aliases in scripts
Parameters and variables
Parameters and variables deserve the same naming attention as scripts and functions.
Parameter naming
Parameters should be descriptive and use PascalCase. Follow these guidelines:
- Use common parameter names from built-in cmdlets when the meaning is the same:
$Path,$Name,$ComputerName,$Credential,$Force. - Be specific:
$LogFilePathis better than$Pathwhen the parameter specifically expects a log file location. - Avoid abbreviations:
$ComputerNamenot$CN,$UserPrincipalNamenot$UPN.
# Description: Function demonstrating clear parameter naming
# Elevation is not required - This is a function definition only
function Export-DeviceComplianceReport {
param (
[Parameter(Mandatory)]
[string]$OutputPath,
[Parameter()]
[datetime]$StartDate = (Get-Date).AddDays(-30),
[Parameter()]
[datetime]$EndDate = (Get-Date),
[Parameter()]
[string[]]$DeviceGroupFilter,
[Parameter()]
[switch]$IncludeNonCompliant
)
# Function logic here
}Example: Descriptive parameter names
Variable naming
Variable naming within your scripts should follow the same principle of clarity. Use descriptive names and camelCase or PascalCase consistently:
# Bad - cryptic variable names
$x = Get-Date
$d = $x.AddDays(-30)
$f = Get-ChildItem -Path "C:\Logs" | Where-Object { $_.LastWriteTime -lt $d }
# Good - descriptive variable names
$currentDate = Get-Date
$thresholdDate = $currentDate.AddDays(-30)
$expiredLogFiles = Get-ChildItem -Path "C:\Logs" |
Where-Object { $_.LastWriteTime -lt $thresholdDate }Example: Clear variable names
Descriptive variable names make your code self-documenting. When you revisit a script six months later - or when a colleague picks it up for the first time - clear names save significant time.
Validating your naming choices
PowerShell provides built-in tools to validate your naming conventions. PSScriptAnalyzer is your best friend here, and if you followed my earlier post on setting up a well-configured repository, you already have it integrated into your Visual Studio Code workflow.
Check for approved verbs
You can quickly check whether a verb is approved:
# Description: Checks if a specific verb is in the approved verbs list
# Elevation is not required - This is a read-only query
Get-Verb -Verb "Remove"
# Returns the verb if approved, empty if not
Get-Verb -Verb "Delete"
# Returns empty - "Delete" is not an approved verbExample: Validate a verb against the approved list
Use PSScriptAnalyzer rules
PSScriptAnalyzer includes specific rules for naming:
# Description: Analyzes a script for naming convention violations
# Elevation is not required - This is a read-only analysis
Invoke-ScriptAnalyzer -Path ".\MyScript.ps1" -IncludeRule @(
'PSUseApprovedVerbs',
'PSUseSingularNouns'
)Example: Run PSScriptAnalyzer naming rules on a script
The PSUseApprovedVerbs rule checks that all exported functions use approved verbs. The PSUseSingularNouns rule checks that nouns are singular. Together, these rules catch the most common naming mistakes before they become habits.
Quick reference
Here is a summary of the key naming conventions covered in this post:
| Area | Convention | Example |
|---|---|---|
| Script files | Verb-Noun.ps1 in PascalCase | Remove-ExpiredLogFile.ps1 |
| Functions | Verb-Noun in PascalCase | Get-DeviceComplianceStatus |
| Verbs | Use approved verbs only | Get, Set, New, Remove |
| Nouns | Singular, specific, PascalCase | DeviceComplianceStatus |
| Parameters | PascalCase, descriptive | $OutputPath, $DeviceGroupFilter |
| Variables | Descriptive, consistent casing | $expiredLogFiles, $thresholdDate |
| Module prefix | Short namespace prefix | Get-CorpDeviceStatus |
The wrap
Naming things is genuinely hard - there is a reason it shows up on every list of the most difficult challenges in computer science. But PowerShell’s verb-noun convention gives you a solid framework that removes much of the ambiguity. When you follow the approved verbs, use specific singular nouns, and apply consistent PascalCase formatting, your code becomes easier to read, discover, and maintain.
The next time you find yourself staring at a blinking cursor, trying to decide between Delete-OldStuff.ps1 and Cleanup.ps1, remember: use an approved verb, pick a descriptive noun, and move on. Your summer holiday is too short to spend it naming things.
Happy coding.
–Jesper
Header image attribution: Image created with help from Adobe Firefly

