In Microsoft Intune, detection rules are used to determine the presence of a Win32 application. The detection rule will make sure that the application installation will only occur if it is not already installed and will also help to confirm a successful installation or not.
There are three types of detection rules built into Intune: MSI, file, and registry, and, for the most part, these will meet most of your needs. When they don’t, you will need to resort to using custom PowerShell detection rules.
This chapter will start by going over some detection fundamentals before moving on to how detection scripts work and the logic behind them. You will then learn about the various types of detection rules, with examples of each type ready to use with your own deployments. Finally, you will learn about custom rules and branching.
Why Use PowerShell?
As well as the three native detection rules, a fourth, more advanced detection type is available to use, and that is a custom detection script – this allows you to script a detection rule for practically anything, limited only by your imagination, and you achieve this by using PowerShell.
Using PowerShell can be a time saver as once you have a detection script saved that you know works, it’s a simple case of a small adjustment to two or three variables and uploading it to Intune – you can rest back on your chair, coffee in hand, knowing that the script has been tried-and-tested before and will do its job correctly.
This book is all for repeatable and reliable deployments, and PowerShell detection rules are a part of that process.
Detection Fundamentals
Let’s start by understanding what informs Microsoft Intune whether an application deployment has been successful or not.
The Microsoft Rules
Interpreting the Table
The part relevant to your scripted detection rule is the second column header: Data read from STDOUT.
STDOUT, or Standard Out, is a stream to which a program outputs its data. The way your detection script is going to use it is to output data to the screen by using a native PowerShell cmdlet.
In Practice
To achieve this, the PowerShell cmdlet Write-Host is used in the detection script code, and you will have seen this cmdlet from Chapter 1, where you were encouraged to read the help files and try out the cmdlets for yourself.
The PowerShell help files for Write-Host state: “Writes customized output to a host.” The host in this case is STDOUT. Sounds perfect.
To signify a successful deployment, you need to use Write-Host to send a message to the screen. But what message should you send? Well, anything! You could use: Write-Host "Success!" or: Write-Host "Installed" just as much as you could use: Write-Host "What a nice day! Are you enjoying it?" As long as you write something it will be interpreted as a successful detection by Intune.
Even though Write-Host will output text to the screen, the end user will never see it when used in a detection script. It will, however, turn up in the IntuneManagementExtension.log found at C:ProgramDataMicrosoftIntuneManagementExtensionLogs.
Where Do I Put the Detection Rules Anyway?
If you are coming from Microsoft Endpoint Configuration Manager (previously known as System Centre Configuration Manager or SCCM for short), then you may wonder if you can copy and paste your rules into a dialog box somewhere within the Intune portal. Currently, in Intune, this is not possible. You must create the detection rule in PowerShell, save it somewhere on your computers as a .ps1 file and then within the Intune portal, browse to the script location and select it to upload.
- 1.
Select the drop-down list next to “Rules format” and choose “Use a custom detection script” from the available options.
- 2.
Select the folder icon next to “Script file” which will then allow you to browse to and select your .ps1 detection rule that you will have previously created and saved.
Silently Continue
When crafting your own detection rules, you will often need to use the parameter -ErrorAction tacked onto the end of the relevant cmdlet being used.
This parameter allows the suppression of non terminating errors, and you should assign it the value of SilentlyContinue. (-ErrorAction ↩ SilentlyContinue)
A non terminating error is not as serious as a terminating error as it will not stop the script from running. This is in stark contrast to a terminating error which will immediately halt script execution.
A terminating error cannot be silenced with the -ErrorAction parameter and if you want to handle them you should use try/catch blocks instead. That way if there is a terminating error, the code within the try block is halted and execution skips to the catch block where you can handle the error.
A non terminating error would otherwise prevent your detection script from doing its job properly. For example, if you were trying to validate a registry key on a system where the key did not exist, a non terminating error would be produced and written to STDERR (have another look at the table previously shown in Figure 4-1), resulting in script failure and the application detection state of unknown.
By adding the -ErrorAction SilentlyContinue parameter, the non terminating error is suppressed should it occur, allowing the script to continue to exit normally and generate the correct failure exit code.
It is probably easier to demonstrate this so let’s try it out. In a PowerShell prompt, execute the following: Get-Item c: hisdoesnotexist
Now try this: Get-item c: hisdoesnotexist -Erroraction SilentlyContinue
How Detection Scripts Work
The way a detection script works can be summarized in plain English as, “Check if this condition is true, if it is, then it means the application has successfully installed and we should use Write-Host to let Intune know that.”
To summarize it even more succinctly, “If this, then that.”
A simplified explanation of If…then
PowerShell If Statement construction – If this, then that
If the IF condition evaluates to false, meaning the application was not detected, then the code between the curly braces is skipped, Intune is not informed of a successful installation by using Write-Host to write to STDOUT, and the script executes successfully with nothing written to either STDOUT or STDERR.
Consulting the first row in the table shown previously in Figure 4-1, you can see that having nothing written to STDOUT or STDERR, as well as a successful script execution, will signify to Intune that the application was not installed.
Detection Rule Types
Now that the fundamentals have been covered, it is time to look at the common detection rule types used in application deployment.
As teaching PowerShell is beyond the scope of this book, I will not explain the minutiae of the inner workings of each detection rule, although if you have read the preceding chapters then you will have some basic understanding already. As with anything, you learn best by doing, and you should read the PowerShell help files on anything that you feel requires clarification and try the code out for yourself on a test computer.
File/Folder Presence
One of the simpler detection methods is to verify the existence of a file or folder.
Set the $fileOrFolderName variable to the file or folder name to detect.
Set the variable $path to the location of the file or folder to detect.
(You can add or leave trailing backslashes when setting the path variable as Join-Path sorts this out for you.) Listing 4-3 detects the presence of the text file: All Servers.txt stored in C:ohtemp.
Detecting file existence
Testing for folder existence is achieved using the same method, specifying a folder name instead of a file name for the $fileOrFolderName variable.
Testing for folder existence
Executable Presence
Executable detection is identical code to file or folder detection, the only difference being the variable named $fileOrFolderName has been renamed to $Executable for clarity; particularly important if other people may eventually use your scripts.
In Listing 4-5, the code detects the presence of the Java executable, java.exe, found in the path C:ProgramFiles(x86)javajre1.8.0_333in
Detecting the Java executable
Executable Version
While the previous example of detecting the presence of a specific executable can be useful, often it is more helpful to detect the version number of the executable.
Continuing to use java.exe as the example executable, let us now make sure it is also the expected version number.
Detecting the product version of an executable file
You can also use the FileVersion property with Get-Item instead of ProductVersion depending on your needs. For example: (Get-item (Join-Path -Path $Path -ChildPath $Executable)).VersionInfo.FileVersion
Finding the Build Number
File version: 103.0.2.8255
Product version: 103.0.2
The resulting detection rule tests for both parts, the file version number and the build number, and expects both to be present to signify a successful installation. It does this by using -and to evaluate two conditions: one for the file version and one for the build number, and both conditions need to be true.
In English, it would read as, “If the file version equals 103.0.2 and the build number equals 8255 then write to STDOUT to signify a successful application detection.”
The detection rule checks for both the file version and the build number
Registry Subkey
It is rare to only wish to detect the presence of a registry subkey. For accuracy, you would want to detect a specific value/data pair.
Should you need to though, the detection rule would resemble this. (By now I’m sure I don’t need to tell you to adjust the variable $RegistrySubKey in the code to meet your needs.)
The detection rule for the Chrome registry subkey
Registry Value/Data Pair
Now, this is more like it. Often, when you are using the registry for detection rules, you will be trying to detect a specific value and its corresponding data to signify a successful deployment.
For this example, if you have deployed the application Git for Windows you may decide to use the registry as the detection rule.
Detection script for a registry value and data pair
Why Don’t You Just Silently Continue?
An easier detection method to obtain registry value/data maybe, but prone to error
Sure, it will work, but remember earlier in this chapter when you were learning about -SilentlyContinue and the difference between non terminating and terminating errors? The cmdlet Get-ItemPropertyValue will produce a terminating error if the value it is looking for does not exist. (This may be the case in a failed deployment.)
If you recall, the -SilentlyContinue switch will not suppress terminating errors and data will be written to the STDERR stream, signifying an unknown outcome.
The trick here is to refactor the code and pipe the contents from Get-ItemProperty (which outputs terminating errors) to Select-Object (which outputs non terminating errors), and will therefore be our host for the -SilentlyContinue parameter.
Try this for yourself: using the detection rule in Listing 4-10 (adjusting the variables to a valid registry value and data pair on your system), verify that the value is detected and “Detected!” is written to your screen.
Then edit the $value variable to something that does not exist and run the same code again. What do you get?
Even though the -silentlyContinue switch is used, it has not stopped the error because it is a terminating error that was produced.
Now try the same thing with the detection rule in Listing 4-9. This time, there is no error message as it has been successfully suppressed.
It is important to always test the code that you write and find out what will happen if what you are trying to detect is not there or contains invalid data. Make sure that it has the desired outcome.
While it may be quicker to use shortcuts and forgo testing your code, in the end, putting in the hard work and doing it properly will save you headaches in the future. And remember, code is reusable. Do it properly once and it’s done forever, ready to be reused time and time again.
Custom Detection
There may come a time when you can’t find anything to detect or don’t care too much and wish to signify the deployment was successful regardless of any true verification.
What you are saying in situations like this is, “I don’t want to, or cannot validate that the application was successfully installed but I want to tell Intune that the installation was okay anyway.”
In edge cases like these (and there should be few instances where you need to do this), you can create a file, or registry subkey with associated value/data to detect as part of your deployment script and then validate its existence in the detection rules to signify a successful deployment, knowing it will always be a successful deployment.
An easier method still is to detect a default file or folder as these are already always present on Windows systems.
Detecting for cmd.exe – you know it will always be there
Detecting the presence of the WindowsSystem32 installation directory
Custom File Detection
You may prefer to create a file to detect as part of the application deployment. Then, once the application has been installed the detection rule looks for the presence of the file just created, which, in turn, signifies a successful application detection.
One advantage of this method over detecting a default file or folder shown previously is that you can rename the created file on each updated deployment of the same application. For example, the first deployment of app1.exe creates an empty text file named App1-001.txt. If App1.exe is then updated and needs to redeploy, this time around the deployment creates and detects App1-002.txt.
As alluded to earlier, the text file is created in the same PowerShell script that deploys the application, and you should do this in the pre- or post-application install phase. It does not matter if you create the file before or after the application is installed because (and let’s face the ugly truth here), if you are using this method of application detection then you are either unable to detect the application through conventional means, or, and I hope this is not the case, you just don’t care.
When using this bad practice of detection, a good practice to follow is to create the custom files in a specific folder at a specific location, and out of reach of standard users.
You should write to the Windows directory, in a subdirectory named after the company you work for, followed by a directory called: Custom Detection. This fulfills two tasks: users are unable to delete its contents, (it is assumed that users log in with standard user permissions – if not you should ask yourself, “Why?”), and the directory then becomes the central storage area for any future projects you may end up working on where you need a repository for custom output or storage.
Here is an imaginary scenario to hammer home this concept.
Scenario: Yum-Yum Dog Foods Inc
Your manager approaches you with the following task: a new application, MyApp.exe, needs to be deployed to all staff.
You install the application on your test system and work out the installation command line.
You discover that once installed, there is no easy method of detecting the installation; having scoured the registry and file system you cannot find anything relevant to use as a detection rule.
You decide to use custom file detection and will create a file called: MyApp-001.log as part of the application deployment script and this can then be used in the detection rule you will write. You also add code to create the directory structure if it’s not present; if the structure is already present it will just create the file to detect.
To use this code, replace the values for the variables: $companyName and $fileName where Yum Yum Dog Foods Inc is the name of the company you work for and MyApp-001.log is the name of the file to be created.
PowerShell code for writing a custom file to be used by the detection script
The detection rule used for MyApp-001.log
Custom Registry Detection
You may prefer to write to the registry instead of the file system for your custom detection and, much like creating custom files, and for the same reasons, it’s best to write to the registry in an organized structure; this keeps everything neat.
Once again, the PowerShell code in Listing 4-15 will first check to see if this location exists in the registry already, and if not, create it before finally writing the value and data to be used for detection.
PowerShell code for writing a custom registry entry to be used by the detection script
The rule to detect the custom registry data
Final Thoughts on Custom Detection
Don’t use it! Joking aside, there may come a time when this is the only method available to you and it is good to have this knowledge in your toolbelt, just in case.
Remember though, creating items for custom rules to detect is not good practice and won’t verify the deployed application is installed. They should only be used as a last resort. They do, however, get you out of a bind in times of need.
Branching
Sometimes you will want to detect either in one location or another depending on if a 32-bit or 64-bit installation has occurred.
A single deployment script can be configured to install either a 32-bit or 64-bit program depending on the target computer “bitness,” and you may not know ahead of time if the detection rule needs to query inside of Program Files (x86) or Program Files.
Although not so common now, you may also wish to detect based on Microsoft Office bitness (e.g. a 32-bit Microsoft Office installation or a 64-bit Microsoft Office installation).
Solve these scenarios by using branching detection rules.
By Office Bitness
In this example detection rule, querying the installed Microsoft Office “bitness” will cause code execution to branch to the correct detection rule to use, based on if the query result is either 32-bit or 64-bit.
In English, the code reads something like this: “If the installed Office version is x86 (32-bit) then use this detection rule. If the Office version is x64 (64-bit) then use this other detection rule.”
A detection rule based on Microsoft Office “bitness”
Listing 4-17 will not run “as-is” as the two IF statements are missing conditions. Once you add the conditions to test for, the code will execute as expected. This is demonstrated in the next scenario.
Scenario – Detecting Mimecast
Mimecast is an application that has two installers: one 32-bit installer and one 64-bit installer. If the client computer has a 32-bit version of Microsoft Office installed, then the 32-bit version of Mimecast must be installed. Likewise, if the client computer has a 64-bit version of Microsoft Office installed then the 64-bit version of Mimecast needs to be installed.
In this scenario, the correct version of Mimecast has been installed and now a detection rule needs to be created that will detect successful installation by querying the correct installed location, either Program Files (x86) or Program Files.
Detecting Mimecast based on the “bitness” of Microsoft Office
Or What?
I wanted to demonstrate how you could use Office bitness in a detection rule for completeness; however, it’s a bit of an overkill and complicated to read. Instead, using PowerShell’s logical operator -or could be a better alternative and you may find this more suitable for future detection scripts that require branching of some kind.
It reads as this: “If you have detected the correct executable version in Program Files (x86) OR if you have detected the correct executable version in Program Files, then inform Intune that installation was successfully detected.”
By using -or, it doesn’t matter which path the executable file was found in that you are using for detecting the version number against – so long as it was found in one of the correct paths then it is a success.
Using PowerShell -or operator in the Mimecast detection rule
This and This
In this last example, both versions of Java (32-bit and 64-bit) were deployed, and therefore for the deployment to be considered successful both versions of Java must be detected.
Detecting this and this to signify a successful detection
Both -or and -and are known as logical operators. To find out more information on these and other logical operators, try using the built-in help by typing the following in a PowerShell console: help About_Logical_Operators
Summary
Well, who knew there would be so much to learn about detection rules? This has been a long chapter and you have covered a lot of ground.
First, you learned about why you might use PowerShell for your detection rules, before moving on to some fundamentals. You learned how to deal with terminating and non terminating errors and how detection scripts work. There are a lot of different types of detection rules and by now you should be able to identify which detection rule will meet your needs. For those edge cases, you learned how to use custom detection rules which can get you out of a bind in times of need. Finally, you learned about detection rule branching.
In the next chapter, you will learn about more advanced application deployment scenarios involving additional file copy operations and where to place the files for deployment. The chapter also covers how to reference the files within the PowerShell deployment script.