Create a standalone rule#
You can use PSRule to create tests for PowerShell objects piped to PSRule for validation. Each test is called a rule.
PSRule allows you to write rules using YAML, JSON, or PowerShell. Regardless of the format you choose, any combination of YAML, JSON, or PowerShell rules can be used together.
Abstract
This topic covers how to create a rule using YAML, JSON, and PowerShell by example. In this quickstart, will be using native PowerShell objects. For an example of reading objects from disk, continue reading Testing infrastructure.
Prerequisites#
For this quickstart, PSRule must be installed locally on MacOS, Linux, or Windows.
To install PSRule locally, open PowerShell and run the following Install-Module command.
If you don't have PowerShell installed, complete Installing PowerShell first.
Install-Module -Name 'PSRule' -Repository PSGallery -Scope CurrentUser
Tip
PowerShell is installed by default on Windows. If these instructions don't work for you, your administrator may have restricted how PowerShell can be used in your environment. You or your administrator may be able to install PSRule for all users as a local administrator. See Getting the modules for instructions on how to do this.
Tip
To make you editing experience even better, consider installing the Visual Studio Code extension.
Scenario - Test for image files#
In our quickstart scenario, we have been tasked with creating a rule to test for image files.
When a file ending with the .jpg or .png extension is found the rule should fail.
We will be using the following PowerShell code to get a list of files.
$pathToSearch = $Env:HOME;
$files = Get-ChildItem -Path $pathToSearch -File -Recurse;
Info
The path to search $Env:HOME defaults to the current user's home directory.
This directory is used so this quickstart works on Windows and Linux operating systems.
Feel free to update this path to a more suitable directory on your local machine.
Define the file type rule#
Before an object can be tested with PSRule, one or more rules must be defined.
Each rule is defined in a file named with the suffix .Rule.yaml, .Rule.jsonc, or .Rule.ps1.
Multiple rules can be defined in a single file.
A rule that fail on files with .jpg or .png extensions is shown in YAML, JSON, and PowerShell formats.
You only need to choose one format, however you can choose to create all three to try out each format.
Create the FileType.Rule.yaml file with the following contents.
This file can be created in Visual Studio Code or any text editor.
Make a note of the location you save FileType.Rule.yaml.
---
# Synopsis: Image files are not permitted.
apiVersion: github.com/microsoft/PSRule/v1
kind: Rule
metadata:
name: Yaml.FileType
spec:
type:
- System.IO.FileInfo
condition:
field: Extension
notIn:
- .jpg
- .png
- Use a short
Synopsis:to describe your rule in a line comment above your rule. This will be shown in output as the default recommendation. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name
Yaml.FileType. - The
typeproperty ensures the rule will only run for file info objects. Other objects that might be piped to PSRule will be skipped by theYaml.FileTyperule. - The
conditionproperty determines the checks PSRule will use to test each file returned withGet-ChildItem. Specifically, theExtensionproperty of eachFileInfoobject will be compared. The value ofExtensionshould not be either.jpgor.png.
Create the FileType.Rule.jsonc file with the following contents.
This file can be created in Visual Studio Code or any text editor.
Make a note of the location you save FileType.Rule.jsonc.
[
{
// Synopsis: Image files are not permitted.
"apiVersion": "github.com/microsoft/PSRule/v1",
"kind": "Rule",
"metadata": {
"name": "Json.FileType"
},
"spec": {
"type": [
"System.IO.FileInfo"
],
"condition": {
"field": "Extension",
"notIn": [
".jpg",
".png"
]
}
}
}
]
- Use a short
Synopsis:to describe your rule in a line comment above your rule. This will be shown in output as the default recommendation. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name
Json.FileType. - The
typeproperty ensures the rule will only run for file info objects. Other objects that might be piped to PSRule will be skipped by theJson.FileTyperule. - The
conditionproperty determines the checks PSRule will use to test each file returned withGet-ChildItem. Specifically, theExtensionproperty of eachFileInfoobject will be compared. The value ofExtensionshould not be either.jpgor.png.
Create the FileType.Rule.ps1 file with the following contents.
This file can be created in Visual Studio Code, Windows PowerShell ISE, or any text editor.
Make a note of the location you save FileType.Rule.ps1.
# Synopsis: Image files are not permitted.
Rule 'PS.FileType' -Type 'System.IO.FileInfo' {
$Assert.NotIn($TargetObject, 'Extension', @('.jpg', '.png'))
}
- Use a short
Synopsis:to describe your rule in a line comment above your rule. This will be shown in output as the default recommendation. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name
PS.FileType. - The
-Typeparameter ensures the rule will only run for file info objects. Other objects that might be piped to PSRule will be skipped by thePS.FileTyperule. - The condition contained within the curly braces
{ }determines the checks PSRule will use to test each file returned withGet-ChildItem. - The
$Assert.NotInmethod checks theExtensionproperty is not set to.jpgor.png.
Testing file extensions#
You can test the rule by using the Invoke-PSRule command.
For example:
$pathToSearch = $Env:HOME;
$files = Get-ChildItem -Path $pathToSearch -File -Recurse;
# The path to the rule file. Update this to the location of your saved file.
$rulePath = 'C:\temp\FileType.Rule.ps1'
# Or the directory can be used to find all rules in the path:
# $rulePath = 'C:\temp\'
# Test the rule
$files | Invoke-PSRule -Path $rulePath
After running Invoke-PSRule you will get output which includes all files in the pathToSeach.
Files with a .jpg or .png extension should have the outcome of Fail.
All other files should report an outcome of Pass.
For example:
TargetName: main.html
RuleName Outcome Recommendation
-------- ------- --------------
Yaml.FileType Pass Image files are not permitted.
TargetName: favicon.png
RuleName Outcome Recommendation
-------- ------- --------------
Yaml.FileType Fail Image files are not permitted.
Tip
- If you didn't get any results with
Failtry creating or saving a.jpgfile in pathToSeach. -
If you have too many
Passresults you can filter the output to only fails by using-Outcome Fail. For example:$files | Invoke-PSRule -Path $rulePath -Outcome Fail
Scenario - Test for service status#
v2.0.0
In our quickstart scenario, we have been tasked to:
- Find any services that are set to start automatically with
StartTypebeginning withAutomatic. - Fail for any service with a
Statusother thanRunning.
We will be using the following PowerShell code to get a list of local services.
$services = Get-Service
Note
This scenario is designed for Windows clients.
The PowerShell cmdlet Get-Service is only available on Windows.
Define a selector#
A selector can be used to filter a list of all services to only services that are set to start automatically. Selectors use YAML or JSON expressions and are similar to rules in many ways. A selector determines if the rule will be run or skipped.
- If the selector is
truethen the rule will be run and either pass or fail. - If the selector is
falsethen the rule will be skipped.
Create the Service.Rule.yaml file with the following contents.
This file can be created in Visual Studio Code or any text editor.
Make a note of the location you save Service.Rule.yaml.
---
# Synopsis: Find services with an automatic start type.
apiVersion: github.com/microsoft/PSRule/v1
kind: Selector
metadata:
name: Yaml.IsAutomaticService
spec:
if:
field: StartType
startsWith: Automatic
convert: true
- Use a short
Synopsis:to describe your selector in a line comment above your rule. - Name your selector with a unique name
Yaml.IsAutomaticService. - The
ifproperty determines if PSRule will evaluate the service rule. Specifically, theStartTypeproperty of each service object will be compared. The value ofStartTypemust start withAutomatic. - The
convertproperty automatically converts the enum type ofStartTypeto a string.
Create the Service.Rule.jsonc file with the following contents.
This file can be created in Visual Studio Code or any text editor.
Make a note of the location you save Service.Rule.jsonc.
[
{
// Synopsis: Find services with an automatic start type.
"apiVersion": "github.com/microsoft/PSRule/v1",
"kind": "Selector",
"metadata": {
"name": "Json.IsAutomaticService"
},
"spec": {
"if": {
"field": "StartType",
"startsWith": "Automatic",
"convert": true
}
}
}
]
- Use a short
Synopsis:to describe your selector in a line comment above your rule. - Name your selector with a unique name
Json.IsAutomaticService. - The
ifproperty determines if PSRule will evaluate the service rule. Specifically, theStartTypeproperty of each service object will be compared. The value ofStartTypemust start withAutomatic. - The
convertproperty automatically converts the enum type ofStartTypeto a string.
Define the service rule#
Similar to the selector, the Status field will be tested to determine if the service is Running.
Append the following contents to the existing Service.Rule.yaml file.
---
# Synopsis: Automatic services should be running.
apiVersion: github.com/microsoft/PSRule/v1
kind: Rule
metadata:
name: Yaml.ServiceStarted
spec:
with:
- Yaml.IsAutomaticService
condition:
field: Status
equals: Running
convert: true
- Use a short
Synopsis:to describe your rule in a line comment above your rule. This will be shown in output as the default recommendation. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name
Yaml.ServiceStarted. - The
withproperty indicates to only run this rule on selected service objects. TheYaml.IsAutomaticServiceselector must first returntrueotherwise this rule will be skipped. - The
conditionproperty determines the checks PSRule will use to test each service. Specifically, theStatusproperty will be compared. The value ofStatusmust beRunning. - The
convertproperty automatically converts the enum type ofStatusto a string.
Update the contents of Service.Rule.jsonc to the following.
[
{
// Synopsis: Find services with an automatic start type.
"apiVersion": "github.com/microsoft/PSRule/v1",
"kind": "Selector",
"metadata": {
"name": "Json.IsAutomaticService"
},
"spec": {
"if": {
"field": "StartType",
"startsWith": "Automatic",
"convert": true
}
}
},
{
// Synopsis: Automatic services should be running.
"apiVersion": "github.com/microsoft/PSRule/v1",
"kind": "Rule",
"metadata": {
"name": "Json.ServiceStarted"
},
"spec": {
"with": [
"Json.IsAutomaticService"
],
"condition": {
"field": "Status",
"equals": "Running",
"convert": true
}
}
}
]
- Use a short
Synopsis:to describe your rule in a line comment above your rule. This will be shown in output as the default recommendation. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name
Json.ServiceStarted. - The
withproperty indicates to only run this rule on selected service objects. TheJson.IsAutomaticServiceselector must first returntrueotherwise this rule will be skipped. - The
conditionproperty determines the checks PSRule will use to test each service. Specifically, theStatusproperty will be compared. The value ofStatusmust beRunning. - The
convertproperty automatically converts the enum type ofStatusto a string.
Create the Service.Rule.ps1 file with the following contents.
This file can be created in Visual Studio Code, Windows PowerShell ISE, or any text editor.
Make a note of the location you save Service.Rule.ps1.
# Synopsis: Automatic services should be running.
Rule 'PS.ServiceStarted' -With 'Yaml.IsAutomaticService' {
$status = $TargetObject.Status.ToString()
$Assert.HasFieldValue($status, '.', 'Running')
}
- Use a short
Synopsis:to describe your rule in a line comment above your rule. This will be shown in output as the default recommendation. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name
PS.ServiceStarted. - The
-Withparameter indicates to only run this rule on selected service objects. TheYaml.IsAutomaticServiceselector must first returntrueotherwise this rule will be skipped. - The condition contained within the curly braces
{ }determines the checks PSRule will use to test each service object. - The
Statusenum property is converted to a string. - The
$Assert.HasFieldValuemethod checks the convertedStatusproperty is set toRunning.
Testing service objects#
You can test the rule with service object by using the Invoke-PSRule command.
For example:
$services = Get-Service
# The directory path to the rule file. Update this to the location of your saved file.
$rulePath = 'C:\temp\'
# Test the rule
$services | Invoke-PSRule -Path $rulePath
After running Invoke-PSRule you will get output which include for services that start automatically.
Services that are Running should pass whereas other stopped services should fail.
For manual or disabled services a warning will be generated indicating that no matching rules were found.
For example:
TargetName: edgeupdate
RuleName Outcome Recommendation
-------- ------- --------------
PS.ServiceStarted Fail Automatic services should be running.
Yaml.ServiceStarted Fail Automatic services should be running.
Json.ServiceStarted Fail Automatic services should be running.
TargetName: EventLog
RuleName Outcome Recommendation
-------- ------- --------------
PS.ServiceStarted Pass Automatic services should be running.
Yaml.ServiceStarted Pass Automatic services should be running.
Json.ServiceStarted Pass Automatic services should be running.
WARNING: Target object 'TermService' has not been processed because no matching rules were found.
Tip
You can disable the warning by setting Execution.UnprocessedObject option.
Alternatively you can ignore all warnings by using the -WarningAction SilentlyContinue parameter.