detection
napt.detection
Detection script generation for Intune Win32 apps.
This module generates PowerShell detection scripts for Intune Win32 app deployments. Scripts check Windows uninstall registry keys for installed software and version information using CMTrace-formatted logging.
Detection Logic
- Checks HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall (always)
- Checks HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall (always)
- Checks HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall (only on 64-bit OS with 64-bit PowerShell process)
- Checks HKCU:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall (only on 64-bit OS with 64-bit PowerShell process)
- Matches by DisplayName (using AppName from recipe or MSI ProductName)
- Compares version (exact or minimum version match based on config)
- Provides verbose logging with detailed detection results, registry paths, installed vs expected versions, and match type information
Installer Type Filtering
Scripts filter registry entries based on installer type to prevent false matches when both MSI and EXE versions of software exist:
- MSI installers (strict): Only matches registry entries with WindowsInstaller=1. Prevents false matches with EXE versions.
- Non-MSI installers (permissive): Matches ANY registry entry. Handles EXE installers that run embedded MSIs internally.
Logging
- Primary (System): C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\NAPTDetections.log
- Primary (User): C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\NAPTDetectionsUser.log
- Fallback (System): C:\ProgramData\NAPT\NAPTDetections.log
- Fallback (User): %LOCALAPPDATA%\NAPT\NAPTDetectionsUser.log
- Log rotation: 2-file rotation (.log and .log.old), configurable max size (default: 3MB)
- Format: CMTrace format for compatibility with Intune diagnostics
- Features: Write permission testing with automatic fallback to alternate locations, verbose component-based logging with dynamic component names based on app name and version, detailed detection workflow logging
Example
Generate detection script:
from pathlib import Path
from napt.detection import DetectionConfig, generate_detection_script
config = DetectionConfig(
app_name="Google Chrome",
version="131.0.6778.86",
log_format="cmtrace",
log_level="INFO",
)
script_path = generate_detection_script(
config=config,
output_path=Path("builds/chrome/131.0.6778.86/Google-Chrome-131.0.6778.86-Detection.ps1"),
)
Note
Detection scripts are saved as siblings to the packagefiles directory to prevent them from being included in the .intunewin package. They should be uploaded separately to Intune alongside the package.
DetectionConfig
dataclass
Configuration for detection script generation.
Attributes:
| Name | Type | Description |
|---|---|---|
app_name |
str
|
Application name to search for in registry DisplayName. |
version |
str
|
Expected version string to match. |
log_format |
LogFormat
|
Log format (currently only "cmtrace" supported). |
log_level |
LogLevel
|
Minimum log level (INFO, WARNING, ERROR, DEBUG). |
log_rotation_mb |
int
|
Maximum log file size in MB before rotation. |
exact_match |
bool
|
If True, version must match exactly. If False, minimum version comparison (remote >= expected). |
app_id |
str
|
Application ID (used for fallback if app_name sanitization results in empty string). |
is_msi_installer |
bool
|
If True, only match MSI-based registry entries. If False, only match non-MSI entries. This prevents false matches when both MSI and EXE versions of software exist with the same DisplayName. |
expected_architecture |
ArchitectureMode
|
Architecture filter for registry view selection. - "x86": Check only 32-bit registry view - "x64": Check only 64-bit registry view - "arm64": Check only 64-bit registry view (ARM64 uses 64-bit registry) - "any": Check both 32-bit and 64-bit views (permissive) |
use_wildcard |
bool
|
If True, use PowerShell -like operator for DisplayName matching (supports * and ? wildcards). If False, use exact -eq match. |
Source code in napt/detection.py
sanitize_filename
Sanitize string for use in Windows filename.
Rules
- Replace spaces with hyphens
- Remove invalid Windows filename characters (< > : " | ? * \ /)
- Normalize multiple consecutive hyphens to single hyphen
- Remove leading/trailing hyphens and dots
- If result is empty, fallback to app_id (or "app" if app_id is empty)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
String to sanitize (e.g., "Google Chrome"). |
required |
app_id
|
str
|
Fallback identifier if name becomes empty after sanitization. |
''
|
Returns:
| Type | Description |
|---|---|
str
|
Sanitized filename-safe string (e.g., "Google-Chrome"). |
Example
Basic sanitization:
sanitize_filename("Google Chrome") # Returns: "Google-Chrome"
sanitize_filename("My App v2.0") # Returns: "My-App-v2.0"
sanitize_filename("Test<>App") # Returns: "TestApp"
Fallback behavior:
Source code in napt/detection.py
generate_detection_script
Generate PowerShell detection script for Intune Win32 app.
Creates a PowerShell script that checks Windows uninstall registry keys for software installation and version. The script uses CMTrace-formatted logging with verbose output, includes log rotation logic, and performs write permission testing with automatic fallback to alternate log locations if primary locations are unavailable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
DetectionConfig
|
Detection configuration (app name, version, logging settings). |
required |
output_path
|
Path
|
Path where the detection script will be saved. |
required |
Returns:
| Type | Description |
|---|---|
Path
|
Path to the generated detection script. |
Raises:
| Type | Description |
|---|---|
OSError
|
If the script file cannot be written. |
Example
Generate script with default settings: