build
napt.build.manager
Build manager for PSADT package creation.
This module orchestrates the complete build process for creating PSADT packages from recipes and downloaded installers.
Design Principles
- Filesystem is source of truth for version information
- Entire PSADT Template_v4 structure copied pristine
- Invoke-AppDeployToolkit.ps1 is generated from template (not copied)
- Build directories are versioned: {app_id}/{version}/
- Branding applied by replacing files in root Assets/ directory (v4 structure)
Example
Basic usage:
build_package
build_package(recipe_path: Path, downloads_dir: Path | None = None, output_dir: Path | None = None) -> BuildResult
Build a PSADT package from a recipe and downloaded installer.
This is the main entry point for the build process. It:
- Loads the recipe configuration
- Finds the downloaded installer
- Extracts version from installer (filesystem is truth)
- Gets/downloads PSADT release
- Creates build directory structure
- Copies PSADT files (pristine)
- Generates Invoke-AppDeployToolkit.ps1 from template
- Copies installer to Files/
- Applies custom branding
- Generates detection script (always; used by App entry and by Update entry)
- Generates requirements script (when build_types is "both" or "update_only")
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
recipe_path
|
Path
|
Path to the recipe YAML file. |
required |
downloads_dir
|
Path | None
|
Directory containing the downloaded installer. Default: Path("downloads") |
None
|
output_dir
|
Path | None
|
Base directory for build output. Default: From config or Path("builds") |
None
|
Returns:
| Type | Description |
|---|---|
BuildResult
|
Build result containing app metadata, build paths, PSADT version, and generated script paths. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If recipe or installer doesn't exist. |
PackagingError
|
If build process fails or script generation fails. |
ConfigError
|
If required configuration is missing. |
Example
Basic build:
result = build_package(Path("recipes/Google/chrome.yaml"))
print(result.build_dir) # builds/napt-chrome/141.0.7390.123
print(result.build_types) # "both"
Custom output directory:
Note
Requires installer to be downloaded first (run 'napt discover'). Version extracted from installer file, not state cache. Overwrites existing build directory if it exists. PSADT files are copied pristine from cache. Invoke-AppDeployToolkit.ps1 is generated (not copied). Scripts are generated as siblings to the packagefiles directory (not included in .intunewin package - must be uploaded separately to Intune). Detection script is always generated. The build_types setting controls requirements script only: "both" (default) generates detection and requirements, "app_only" generates only detection, "update_only" generates detection and requirements.
Source code in napt/build/manager.py
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 | |
napt.build.template
Invoke-AppDeployToolkit.ps1 template generation for NAPT.
This module handles generating the Invoke-AppDeployToolkit.ps1 script by reading PSADT's template, substituting configuration values, and inserting recipe-specific install/uninstall code.
Design Principles
- PSADT template remains pristine in cache
- Generate script by substitution, not modification
- Preserve PSADT's structure and comments
- Support dynamic values (AppScriptDate, discovered version)
- Merge org defaults with recipe overrides
Example
Basic usage:
from pathlib import Path
from napt.build.template import generate_invoke_script
script = generate_invoke_script(
template_path=Path("cache/psadt/4.1.7/Invoke-AppDeployToolkit.ps1"),
config=recipe_config,
version="141.0.7390.123",
psadt_version="4.1.7"
)
Path("builds/app/version/Invoke-AppDeployToolkit.ps1").write_text(script)
generate_invoke_script
generate_invoke_script(template_path: Path, config: dict[str, Any], version: str, psadt_version: str, architecture: str) -> str
Generate Invoke-AppDeployToolkit.ps1 from PSADT template and config.
Reads the PSADT template, replaces the $adtSession hashtable with values from the configuration, and inserts recipe-specific install/ uninstall code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
template_path
|
Path
|
Path to PSADT's Invoke-AppDeployToolkit.ps1 template. |
required |
config
|
dict[str, Any]
|
Merged configuration (org + vendor + recipe). |
required |
version
|
str
|
Application version (from filesystem). |
required |
psadt_version
|
str
|
PSADT version being used. |
required |
architecture
|
str
|
Resolved installer architecture (e.g., "x64", "x86", "arm64", "any"). Sets AppArch in the $adtSession hashtable; "any" leaves AppArch unset. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Generated PowerShell script text. |
Raises:
| Type | Description |
|---|---|
PackagingError
|
If template doesn't exist or template parsing fails. |
Example
Generate deployment script from template:
Source code in napt/build/template.py
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | |
napt.build.packager
.intunewin package generation for NAPT.
This module handles creating .intunewin packages from built PSADT directories using Microsoft's IntuneWinAppUtil.exe tool.
Design Principles
- IntuneWinAppUtil.exe is cached globally (not per-build)
- Package output is named by IntuneWinAppUtil.exe: Invoke-AppDeployToolkit.intunewin
- Build directory can optionally be cleaned after packaging
- Tool is downloaded from Microsoft's official GitHub repository
Example
Basic usage:
create_intunewin
create_intunewin(build_dir: Path, output_dir: Path | None = None, clean_source: bool = False) -> PackageResult
Create a .intunewin package from a PSADT build version directory.
Uses Microsoft's IntuneWinAppUtil.exe tool to package the PSADT build into a .intunewin file for Intune deployment.
The output directory is versioned: packages/{app_id}/{version}/. Any previously packaged version for the same app is removed before the new one is created (single-slot: one package on disk per app at a time). Detection and requirements scripts are copied into the output directory so that 'napt upload' is self-contained and does not need the builds directory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
build_dir
|
Path
|
Path to the version directory produced by 'napt build' (e.g., builds/napt-chrome/144.0.7559.110/). Must contain a packagefiles/ subdirectory with a valid PSADT structure. |
required |
output_dir
|
Path | None
|
Parent directory for package output. Default: packages/ (configurable via defaults.package.output_dir in org.yaml). |
None
|
clean_source
|
bool
|
If True, remove the build version directory after packaging. Default is False. |
False
|
Returns:
| Type | Description |
|---|---|
PackageResult
|
Package metadata including .intunewin path, app ID, and version. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
If the build directory structure is invalid. |
PackagingError
|
If packaging fails or build_dir is missing. |
NetworkError
|
If IntuneWinAppUtil.exe download fails. |
Example
Basic packaging:
result = create_intunewin(
build_dir=Path("builds/napt-chrome/144.0.7559.110")
)
print(result.package_path)
# packages/napt-chrome/144.0.7559.110/Invoke-AppDeployToolkit.intunewin
With cleanup:
Note
Requires build directory from 'napt build' command. IntuneWinAppUtil.exe is downloaded and cached on first use. Setup file is always "Invoke-AppDeployToolkit.exe". Output file is named by IntuneWinAppUtil.exe: packages/{app_id}/{version}/Invoke-AppDeployToolkit.intunewin
Source code in napt/build/packager.py
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | |