├── ChocolateyPackageCreator ├── schema │ ├── PackageFile.psd1 │ ├── LocalFile.psd1 │ ├── PackageDependency.psd1 │ ├── PackageManifest.psd1 │ ├── RemoteFile.psd1 │ ├── ChocolateyISOPackage.psd1 │ ├── PackageInstaller.psd1 │ ├── ChocolateyPackage.psd1 │ └── PackageMetadata.psd1 ├── ChocolateyPackageCreator.psm1 ├── models │ └── ChocolateyPackage.ps1 ├── static │ ├── package.psd1 │ └── template │ │ ├── iso │ │ └── ChocolateyInstall.eps │ │ └── default │ │ └── ChocolateyInstall.eps ├── functions │ ├── publish.ps1 │ ├── package.ps1 │ └── build.ps1 └── ChocolateyPackageCreator.psd1 ├── examples ├── chrome-enterprise │ ├── process.ps1 │ ├── azure-pipelines.yml │ └── package.psd1 ├── eps.extension │ ├── process.ps1 │ └── package.psd1 ├── sql-express-adv │ ├── process.ps1 │ ├── files │ │ ├── ChocolateyInstall.ps1 │ │ └── config.eps │ └── package.psd1 ├── build.ps1 ├── README.md ├── publish.ps1 ├── 7zip │ └── package.psd1 ├── veeam │ ├── iso.psd1 │ ├── packages │ │ ├── explorer-oracle.psd1 │ │ ├── explorer-sql.psd1 │ │ ├── redistr-mac.psd1 │ │ ├── redistr-windows.psd1 │ │ ├── explorer-exchange.psd1 │ │ ├── explorer-ad.psd1 │ │ ├── explorer-sharepoint.psd1 │ │ ├── redistr-linux.psd1 │ │ ├── catalog.psd1 │ │ ├── console.psd1 │ │ ├── enterprise.psd1 │ │ └── server.psd1 │ └── veeam.psd1 ├── dotnet-472 │ └── package.psd1 ├── ms-reportviewer2015 │ └── package.psd1 ├── buildISO.ps1 ├── sql-2014-clr │ └── package.psd1 ├── vcredist │ └── package.psd1 ├── sql-2014-smo │ └── package.psd1 └── python │ └── package.psd1 ├── LICENSE ├── README.md ├── CHANGELOG.md └── docs ├── schema.md ├── getting_started.md └── iso.md /ChocolateyPackageCreator/schema/PackageFile.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Src = @{ 3 | type = 'string' 4 | required = $true 5 | } 6 | Target = @{ 7 | type = 'string' 8 | required = $true 9 | } 10 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/schema/LocalFile.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | LocalPath = @{ 3 | type = 'string' 4 | required = $true 5 | } 6 | ImportPath = @{ 7 | type = 'string' 8 | required = $true 9 | } 10 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/schema/PackageDependency.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Id = @{ 3 | type = 'string' 4 | required = $true 5 | } 6 | Version = @{ 7 | type = 'string' 8 | required = $false 9 | default = '' 10 | } 11 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/schema/PackageManifest.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Metadata = @{ 3 | type = 'PackageMetadata' 4 | required = $true 5 | } 6 | Files = @{ 7 | type = 'PackageFile[]' 8 | required = $false 9 | default = @() 10 | } 11 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/schema/RemoteFile.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Url = @{ 3 | type = 'string' 4 | required = $true 5 | } 6 | Sha1 = @{ 7 | type = 'string' 8 | required = $false 9 | default = '' 10 | } 11 | ImportPath = @{ 12 | type = 'string' 13 | required = $true 14 | } 15 | } -------------------------------------------------------------------------------- /examples/chrome-enterprise/process.ps1: -------------------------------------------------------------------------------- 1 | param($BuildPath, $Package) 2 | 3 | $toolsDir = Join-Path $BuildPath 'tools' 4 | $chromeDir = Join-Path $toolsDir 'chrome' 5 | $zipFile = Join-Path $BuildPath $Package.RemoteFiles[0].ImportPath 6 | 7 | New-Item -ItemType Directory $chromeDir 8 | Expand-Archive $zipFile $chromeDir 9 | 10 | Copy-Item (Join-Path $chromeDir 'installers/GoogleChromeStandaloneEnterprise64.msi') $toolsDir 11 | Remove-Item $chromeDir -Recurse -Force 12 | Remove-Item $zipFile -------------------------------------------------------------------------------- /examples/eps.extension/process.ps1: -------------------------------------------------------------------------------- 1 | param($BuildPath, $Package) 2 | 3 | $extDir = Join-Path $BuildPath 'extensions' 4 | $zipFile = Join-Path $BuildPath $Package.RemoteFiles[0].ImportPath 5 | 6 | Expand-Archive $zipFile $extDir 7 | Remove-Item $zipFile 8 | 9 | $srcFolder = '{0}-{1}' -f 'eps', $Package.Manifest.Metadata.Version 10 | $srcPath = (Join-Path $extDir $srcFolder) 11 | 12 | $modulePath = Join-Path $extDir ('{0}\{1}\*' -f $srcFolder, 'EPS') 13 | 14 | Move-Item $modulePath $extDir 15 | Remove-Item $srcPath -Recurse -------------------------------------------------------------------------------- /examples/sql-express-adv/process.ps1: -------------------------------------------------------------------------------- 1 | param($BuildPath, $Package) 2 | 3 | $toolsDir = Join-Path $BuildPath 'tools' 4 | $installer = Join-Path $BuildPath $Package.RemoteFiles[0].ImportPath 5 | $installerName = Split-Path $installer -Leaf 6 | 7 | # Extract installer contents 8 | Start-Process $installer -ArgumentList ('/q') -WorkingDirectory $toolsDir -NoNewWindow -Wait 9 | 10 | $sqlFolder = Join-Path $toolsDir ($installerName -replace '.exe', '') 11 | Move-Item (Join-Path $sqlFolder '*') $toolsDir 12 | 13 | Remove-Item $sqlFolder -Recurse 14 | Remove-Item $installer -------------------------------------------------------------------------------- /ChocolateyPackageCreator/ChocolateyPackageCreator.psm1: -------------------------------------------------------------------------------- 1 | # Load models 2 | $models_path = Join-Path $PSScriptRoot 'models' 3 | if ( (Test-Path -Path $models_path -PathType Container) ) { 4 | foreach ( $item in Get-ChildItem -Path $models_path -Filter '*.ps1' ) { 5 | . $item.FullName 6 | } 7 | } 8 | 9 | # Load functions 10 | $functions_path = Join-Path $PSScriptRoot 'functions' 11 | if ( (Test-Path -Path $functions_path -PathType Container) ) { 12 | foreach ( $item in Get-ChildItem -Path $functions_path -Filter '*.ps1' ) { 13 | . $item.FullName 14 | } 15 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/schema/ChocolateyISOPackage.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Name = @{ 3 | type = 'string' 4 | required = $true 5 | } 6 | Path = @{ 7 | type = 'string' 8 | required = $true 9 | } 10 | IsoFile = @{ 11 | type = 'RemoteFile' 12 | required = $true 13 | } 14 | Manifest = @{ 15 | type = 'PackageManifest' 16 | required = $true 17 | } 18 | MetaPackage = @{ 19 | type = 'ChocolateyPackage' 20 | required = $true 21 | } 22 | Packages = @{ 23 | type = 'ChocolateyPackage[]' 24 | required = $true 25 | } 26 | } -------------------------------------------------------------------------------- /examples/chrome-enterprise/azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | branches: 3 | include: 4 | - master 5 | paths: 6 | include: 7 | - examples/chrome-enterprise/* 8 | jobs: 9 | - job: Default 10 | steps: 11 | - task: PowerShell@2 12 | displayName: 'Build Chrome Enterprise package' 13 | inputs: 14 | filePath: examples/build.ps1 15 | arguments: -ConfigFile examples/chrome-enterprise/package.psd1 -OutPath $(Build.StagingDirectory) -Verbose 16 | pwsh: true 17 | - task: PowerShell@2 18 | displayName: 'Deploy Chrome Enterprise package' 19 | inputs: 20 | filePath: examples/publish.ps1 21 | arguments: -Repository $(nuget.repository) -PackagePath $(packagePath) 22 | pwsh: true 23 | env: 24 | API_KEY: $(nuget.apikey) -------------------------------------------------------------------------------- /examples/build.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param( 3 | [string] $ConfigFile, 4 | [string] $OutPath 5 | ) 6 | 7 | $ErrorActionPreference = 'Stop' 8 | Import-Module (Join-Path $PSScriptRoot '..\ChocolateyPackageCreator') -Force 9 | 10 | if (!(Test-Path $ConfigFile)) { 11 | throw 'Cannot find config file at {0}' -f $ConfigFile 12 | } 13 | 14 | if (!(Test-Path $OutPath)) { 15 | throw 'The output path must already exist at {0}' -f $OutPath 16 | } 17 | 18 | $verbose = $PSCmdlet.MyInvocation.BoundParameters['Verbose'] 19 | $hasDefender = Test-Path (Join-Path $env:ProgramFiles 'Windows Defender/MpCmdRun.exe' -ErrorAction SilentlyContinue) 20 | 21 | 22 | $config = Import-PowerShellDataFile $ConfigFile 23 | $packagePath = New-ChocolateyPackage (Split-Path $ConfigFile) $config | 24 | Build-ChocolateyPackage -OutPath $OutPath -ScanFiles:$hasDefender -Verbose:$verbose 25 | 26 | $packagePath 27 | Write-Output "##vso[task.setvariable variable=packagePath;]$packagePath" -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | This directory contains examples of how to use the Chocolatey Package Creator 3 | module to dynamically create Chocolatey packages. 4 | 5 | * `7zip`: Packages the 64-bit version of the 7zip CLI tool 6 | * `dotnet-472`: Packages Microsoft .NET Framework 4.7.2 7 | * `eps.extension`: Packages the Powershell EPS module as a Chocolatey extension. This is 8 | used as a dependency in the `sql-express-adv` package. 9 | * `ms-reportviewer2015`: Packages Microsoft SQL Server Report Viewer 2015. This is used as a dependency in `veeam`. 10 | * `sql-2014-clr`: Packages Microsoft SQL Server 2014 runtime files. This is used as a dependency in `veeam`. 11 | * `sql-2014-smo`: Packages Microsoft SQL Server 2014 management objects. This is used as a dependency in `veeam`. 12 | * `sql-express-adv`: Packages Microsoft SQL Server 2019 (advanced) 13 | * `vcredist`: Packages Microsoft Visual C++ runtime files. This is used as a dependency in `veeam`. 14 | * `veeam`: Packages Veeam Backup & Replication -------------------------------------------------------------------------------- /ChocolateyPackageCreator/schema/PackageInstaller.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | ScriptPath = @{ 3 | type = 'string' 4 | required = $true 5 | } 6 | InstallerPath = @{ 7 | type = 'string' 8 | required = $true 9 | } 10 | InstallerPath64 = @{ 11 | type = 'string' 12 | required = $false 13 | default = '' 14 | } 15 | InstallerType = @{ 16 | type = 'string' 17 | required = $true 18 | } 19 | ExitCodes = @{ 20 | type = 'int[]' 21 | required = $false 22 | default = @(0) 23 | } 24 | Flags = @{ 25 | type = 'string' 26 | required = $false 27 | default = '' 28 | } 29 | ArgumentPrefix = @{ 30 | type = 'string' 31 | required = $false 32 | default = '' 33 | } 34 | Arguments = @{ 35 | type = 'hashtable' 36 | required = $false 37 | default = @{} 38 | } 39 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/schema/ChocolateyPackage.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Name = @{ 3 | type = 'string' 4 | required = $true 5 | } 6 | Path = @{ 7 | type = 'string' 8 | required = $true 9 | } 10 | ProcessScript = @{ 11 | type = 'string' 12 | required = $false 13 | default = '' 14 | } 15 | Shim = @{ 16 | type = 'bool' 17 | required = $false 18 | default = $false 19 | } 20 | Installer = @{ 21 | type = 'PackageInstaller' 22 | required = $false 23 | default = @{} 24 | } 25 | LocalFiles = @{ 26 | type = 'LocalFile[]' 27 | required = $false 28 | default = @() 29 | } 30 | RemoteFiles = @{ 31 | type = 'RemoteFile[]' 32 | required = $false 33 | default = @() 34 | } 35 | Manifest = @{ 36 | type = 'PackageManifest' 37 | required = $true 38 | } 39 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Joshua Gilman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/publish.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param( 3 | [string] $Repository, 4 | [string] $PackagePath, 5 | [ValidateSet('Chocolatey', 'NuGet')] 6 | [string] $Tool = 'Chocolatey', 7 | [switch] $Force, 8 | [switch] $Recurse 9 | ) 10 | 11 | $ErrorActionPreference = 'Stop' 12 | Import-Module (Join-Path $PSScriptRoot '..\ChocolateyPackageCreator') -Force 13 | 14 | if (!$env:API_KEY) { 15 | throw 'Please supply the NuGet API key via the `API_KEY` environment variable' 16 | } 17 | 18 | if ($Recurse) { 19 | $packageFiles = Get-ChildItem $PackagePath -Filter '*.nupkg' -Recurse 20 | if ($packageFiles.Count -eq 0) { 21 | throw 'Could not locate any packages at {0}' -f $PackagePath 22 | } 23 | } 24 | else { 25 | $packageFiles = @($PackagePath) 26 | } 27 | 28 | $verbose = $PSCmdlet.MyInvocation.BoundParameters['Verbose'] 29 | foreach ($packageFile in $packageFiles) { 30 | Write-Verbose ('Publishing package at {0}...' -f $packageFile) 31 | Publish-ChocolateyPackage ` 32 | -Repository $Repository ` 33 | -ApiKey $env:API_KEY ` 34 | -PackageFile $PackageFile ` 35 | -Tool $Tool ` 36 | -Force:$Force ` 37 | -Verbose:$verbose 38 | } -------------------------------------------------------------------------------- /examples/7zip/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = '7zip' 3 | shim = $True 4 | remoteFiles = @( 5 | @{ 6 | url = 'https://www.7-zip.org/a/7z1900-x64.exe' 7 | sha1 = '9FA11A63B43F83980E0B48DC9BA2CB59D545A4E8' 8 | importPath = 'tools/7z.exe' 9 | } 10 | ) 11 | manifest = @{ 12 | metadata = @{ 13 | id = '7zip' 14 | title = '7Zip File Archiver' 15 | version = '19.00' 16 | authors = 'Igor Pavlov' 17 | owners = 'Joshua Gilman' 18 | summary = 'Installs 7Zip CLI tool' 19 | description = '7-Zip is a file archiver with a high compression ratio.' 20 | projectUrl = 'https://www.7-zip.org/' 21 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 22 | tags = '7zip file archive' 23 | copyright = '2021 Igor Pavlov' 24 | licenseUrl = 'http://www.7-zip.org/license.txt' 25 | requireLicenseAcceptance = 'false' 26 | } 27 | files = @( 28 | @{ 29 | src = 'tools\**' 30 | target = 'tools' 31 | } 32 | ) 33 | } 34 | } -------------------------------------------------------------------------------- /examples/eps.extension/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'eps.extension' 3 | processScript = 'process.ps1' 4 | remoteFiles = @( 5 | @{ 6 | url = 'https://github.com/straightdave/eps/archive/refs/tags/v1.0.0.zip' 7 | importPath = 'extensions/eps.zip' 8 | } 9 | ) 10 | manifest = @{ 11 | metadata = @{ 12 | id = 'eps.extension' 13 | title = 'EPS' 14 | version = '1.0.0' 15 | authors = 'Dave Wu' 16 | owners = 'Joshua Gilman' 17 | summary = 'Installs EPS Powershell module' 18 | description = 'EPS ( Embedded PowerShell ), inspired by ERB, is a templating tool that embeds PowerShell code into a text document. It is conceptually and syntactically similar to ERB for Ruby or Twig for PHP.' 19 | projectUrl = 'https://github.com/straightdave/eps' 20 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageCreator' 21 | tags = 'powershell eps extension' 22 | copyright = '2021 Dave Wu' 23 | licenseUrl = 'https://github.com/straightdave/eps/blob/master/LICENSE' 24 | requireLicenseAcceptance = 'false' 25 | } 26 | files = @( 27 | @{ 28 | src = 'extensions\**' 29 | target = 'extensions' 30 | } 31 | ) 32 | } 33 | } -------------------------------------------------------------------------------- /examples/veeam/iso.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-iso' 3 | isoFile = @{ 4 | url = 'https://download2.veeam.com/VBR/v11/VeeamBackup&Replication_11.0.0.837_20210220.iso' 5 | sha1 = 'D6E9F7DB3BA1A4782028773562AA036365724AE4' 6 | importPath = 'veeam.iso' 7 | } 8 | manifest = @{ 9 | metadata = @{ 10 | id = 'veeam-iso' 11 | title = 'Veeam Backup & Replication ISO' 12 | version = '11.0.0.837' 13 | authors = 'Veeam' 14 | owners = 'Joshua Gilman' 15 | summary = 'Installs the contents of the Veeam Backup & Replication ISO' 16 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 17 | projectUrl = 'http://www.veeam.com/' 18 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 19 | tags = 'veeam backup replication iso' 20 | copyright = '2021 Veeam' 21 | licenseUrl = 'https://www.veeam.com/eula.html' 22 | requireLicenseAcceptance = 'false' 23 | } 24 | files = @( 25 | @{ 26 | src = 'tools\**' 27 | target = 'tools' 28 | } 29 | ) 30 | } 31 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/schema/PackageMetadata.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Id = @{ 3 | type = 'string' 4 | required = $true 5 | } 6 | Title = @{ 7 | type = 'string' 8 | required = $true 9 | } 10 | Version = @{ 11 | type = 'string' 12 | required = $true 13 | } 14 | Authors = @{ 15 | type = 'string' 16 | required = $true 17 | } 18 | Owners = @{ 19 | type = 'string' 20 | required = $true 21 | } 22 | Summary = @{ 23 | type = 'string' 24 | required = $true 25 | } 26 | Description = @{ 27 | type = 'string' 28 | required = $true 29 | } 30 | ProjectUrl = @{ 31 | type = 'string' 32 | required = $true 33 | } 34 | PackageSourceUrl = @{ 35 | type = 'string' 36 | required = $true 37 | } 38 | Tags = @{ 39 | type = 'string' 40 | required = $true 41 | } 42 | Copyright = @{ 43 | type = 'string' 44 | required = $true 45 | } 46 | LicenseUrl = @{ 47 | type = 'string' 48 | required = $true 49 | } 50 | RequireLicenseAcceptance = @{ 51 | type = 'string' 52 | required = $true 53 | } 54 | Dependencies = @{ 55 | type = 'PackageDependency[]' 56 | required = $false 57 | default = @() 58 | } 59 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chocolatey Package Creator 2 | > Powershell module for creating internal Chocolatey packages 3 | 4 | ## Installation 5 | ``` 6 | $> Install-Module ChocolateyPackageCreator 7 | ``` 8 | 9 | ## Usage 10 | 11 | For a more in-depth guide, see [Getting Started](https://github.com/jmgilman/ChocolateyPackageCreator/blob/master/docs/getting_started.md). Create a new package template: 12 | ```powershell 13 | $> New-ChocolateyPackageConfig C:\my\package 14 | ``` 15 | 16 | Modify the contents of the template package to fit the needs of the package 17 | you are trying to create. For more in-depth documentation and examples, see the 18 | `examples` directory. To understand the schema of a package file, see the 19 | [schema documentation](docs/schema.md). When ready, build the package: 20 | 21 | ```powershell 22 | $> $config = Import-PowerShellDataFile 'C:\my\package\package.psd1' 23 | $> $packagePath = New-ChocolateyPackage (Split-Path $configFile) $config | 24 | Build-ChocolateyPackage -OutPath 'C:\my\package\bin' 25 | ``` 26 | 27 | And then publish it: 28 | 29 | ```powershell 30 | $> Publish-ChocolateyPackage ` 31 | -Repository 'http://my.nuget.com/repository' ` 32 | -ApiKey $env:API_KEY ` 33 | -PackageFile $packagePath 34 | ``` 35 | 36 | ## Features 37 | 38 | * Define all package elements in a single configuration file 39 | * Automatically download and scan external files 40 | * Easily extendable with custom logic in the package creation process 41 | * Create and deploy packages with a single module 42 | 43 | ## Meta 44 | Joshua Gilman - joshuagilman@gmail.com 45 | 46 | Distributed under the MIT license. See LICENSE for more information. 47 | 48 | https://github.com/jmgilman -------------------------------------------------------------------------------- /ChocolateyPackageCreator/models/ChocolateyPackage.ps1: -------------------------------------------------------------------------------- 1 | class ChocolateyISOPackage { 2 | [string] $Name 3 | [string] $Path 4 | [RemoteFile] $IsoFile 5 | [PackageManifest] $Manifest 6 | [ChocolateyPackage] $MetaPackage 7 | [ChocolateyPackage[]] $Packages 8 | } 9 | 10 | class ChocolateyPackage { 11 | [string] $Name 12 | [string] $Path 13 | [string] $ProcessScript 14 | [bool] $Shim 15 | [PackageInstaller] $Installer 16 | [PackageManifest] $Manifest 17 | [LocalFile[]] $LocalFiles 18 | [RemoteFile[]] $RemoteFiles 19 | } 20 | 21 | class LocalFile { 22 | [string] $LocalPath 23 | [string] $ImportPath 24 | } 25 | 26 | class RemoteFile { 27 | [string] $Url 28 | [string] $Sha1 29 | [string] $ImportPath 30 | } 31 | 32 | class PackageManifest { 33 | [PackageMetadata] $Metadata 34 | [PackageFile[]] $Files 35 | } 36 | 37 | class PackageMetadata { 38 | [string] $Id 39 | [string] $Title 40 | [string] $Version 41 | [string] $Authors 42 | [string] $Owners 43 | [string] $Summary 44 | [string] $Description 45 | [string] $ProjectUrl 46 | [string] $PackageSourceUrl 47 | [string] $Tags 48 | [string] $Copyright 49 | [string] $LicenseUrl 50 | [string] $RequireLicenseAcceptance 51 | [PackageDependency[]] $Dependencies 52 | } 53 | 54 | class PackageDependency { 55 | [string] $Id 56 | [string] $Version 57 | } 58 | 59 | class PackageFile { 60 | [string] $Src 61 | [string] $Target 62 | } 63 | 64 | class PackageInstaller { 65 | [string] $ScriptPath 66 | [string] $InstallerPath 67 | [string] $InstallerPath64 68 | [string] $InstallerType 69 | [int[]] $ExitCodes 70 | [string] $Flags 71 | [string] $ArgumentPrefix 72 | [hashtable] $Arguments 73 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/static/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'mypackage' 3 | processScript = '' 4 | shim = $False 5 | installer = @{ 6 | scriptPath = 'tools' 7 | installerPath = 'installer.msi' 8 | installerPath64 = '' 9 | installerType = 'msi' 10 | exitCodes = @(0) 11 | flags = '/qn' 12 | argumentPrefix = '' 13 | arguments = @{ 14 | ACCEPT_EULA = 1 15 | } 16 | } 17 | localFiles = @() 18 | remoteFiles = @( 19 | @{ 20 | url = 'https://my.download.com/installer.msi' 21 | sha1 = '' 22 | importPath = 'tools/installer.msi' 23 | } 24 | ) 25 | manifest = @{ 26 | metadata = @{ 27 | id = 'mypackage' 28 | title = 'My Package' 29 | version = '1.0.0' 30 | authors = 'Author' 31 | owners = 'Owners' 32 | summary = 'Installs My Package' 33 | description = 'My package does x y z' 34 | projectUrl = 'https://www.mypackage.com' 35 | packageSourceUrl = 'https://github.com/me/mypackagesource' 36 | tags = 'my package' 37 | copyright = '2021 Authors' 38 | licenseUrl = 'https://www.mypackage.com/license' 39 | requireLicenseAcceptance = 'false' 40 | dependencies = @() 41 | } 42 | files = @( 43 | @{ 44 | src = 'tools\**' 45 | target = 'tools' 46 | } 47 | ) 48 | } 49 | } -------------------------------------------------------------------------------- /examples/dotnet-472/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'dotnet-472' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'tools/ndp472-kb4054530-x86-x64-allos-enu.exe' 6 | installerType = 'exe' 7 | exitCodes = @(0, 3010) 8 | flags = '/q /norestart' 9 | } 10 | remoteFiles = @( 11 | @{ 12 | url = 'https://download.visualstudio.microsoft.com/download/pr/887938c3-2a46-4069-a0b1-207035f1dd82/c8fe3fec22581fce77a5120c9d30828b/ndp472-kb4054530-x86-x64-allos-enu.exe' 13 | sha1 = 'CDAC2CCE64932CF8BDC57FEE18296E98B1967B16' 14 | importPath = 'tools/ndp472-kb4054530-x86-x64-allos-enu.exe' 15 | } 16 | ) 17 | manifest = @{ 18 | metadata = @{ 19 | id = 'dotnet-472' 20 | title = 'Microsoft .NET Framework 4.7.2' 21 | version = '4.7.2' 22 | authors = 'Microsoft' 23 | owners = 'Gilman Lab' 24 | summary = 'Installs Microsoft .NET Framework 4.7.2' 25 | description = '.NET Framework is a Windows-only version of .NET for building any type of app that runs on Windows.' 26 | projectUrl = 'https://dotnet.microsoft.com/' 27 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 28 | tags = 'microsoft dot net framework' 29 | copyright = '2021 Microsoft' 30 | licenseUrl = 'https://dotnet.microsoft.com/platform/free' 31 | requireLicenseAcceptance = 'false' 32 | } 33 | files = @( 34 | @{ 35 | src = 'tools\**' 36 | target = 'tools' 37 | } 38 | ) 39 | } 40 | } -------------------------------------------------------------------------------- /examples/veeam/packages/explorer-oracle.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-explorer-oracle' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Explorers\VeeamExplorerforOracle.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_EULA = '1' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | } 13 | } 14 | manifest = @{ 15 | metadata = @{ 16 | id = 'veeam-explorer-oracle' 17 | title = 'Veeam Explorer for Oracle' 18 | version = '11.0.0.837' 19 | authors = 'Veeam' 20 | owners = 'Joshua Gilman' 21 | summary = 'Installs the Veeam Explorer for Oracle' 22 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 23 | projectUrl = 'http://www.veeam.com/' 24 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 25 | tags = 'veeam backup replication explorer oracle' 26 | copyright = '2021 Veeam' 27 | licenseUrl = 'https://www.veeam.com/eula.html' 28 | requireLicenseAcceptance = 'false' 29 | dependencies = @( 30 | @{ 31 | id = 'veeam-iso' 32 | version = '[11.0.0.837]' 33 | } 34 | ) 35 | } 36 | files = @( 37 | @{ 38 | src = 'tools\**' 39 | target = 'tools' 40 | } 41 | ) 42 | } 43 | } -------------------------------------------------------------------------------- /examples/veeam/packages/explorer-sql.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-explorer-sql' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Explorers\VeeamExplorerforSQL.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_EULA = '1' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | } 13 | } 14 | manifest = @{ 15 | metadata = @{ 16 | id = 'veeam-explorer-sql' 17 | title = 'Veeam Explorer for Microsoft SQL Server' 18 | version = '11.0.0.837' 19 | authors = 'Veeam' 20 | owners = 'Joshua Gilman' 21 | summary = 'Installs the Veeam Explorer for Microsoft SQL Server' 22 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 23 | projectUrl = 'http://www.veeam.com/' 24 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 25 | tags = 'veeam backup replication explorer microsoft sql' 26 | copyright = '2021 Veeam' 27 | licenseUrl = 'https://www.veeam.com/eula.html' 28 | requireLicenseAcceptance = 'false' 29 | dependencies = @( 30 | @{ 31 | id = 'veeam-iso' 32 | version = '[11.0.0.837]' 33 | } 34 | ) 35 | } 36 | files = @( 37 | @{ 38 | src = 'tools\**' 39 | target = 'tools' 40 | } 41 | ) 42 | } 43 | } -------------------------------------------------------------------------------- /examples/veeam/packages/redistr-mac.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-redistr-mac' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Packages\VAMRedist.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_EULA = '1' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | } 13 | } 14 | manifest = @{ 15 | metadata = @{ 16 | id = 'veeam-redistr-mac' 17 | title = 'Redistributable Package for Veeam Agent for Mac' 18 | version = '11.0.0.837' 19 | authors = 'Veeam' 20 | owners = 'Joshua Gilman' 21 | summary = 'Installs the Redistributable Package for Veeam Agent for Mac' 22 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 23 | projectUrl = 'http://www.veeam.com/' 24 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 25 | tags = 'veeam backup replication redistrutable agent mac' 26 | copyright = '2021 Veeam' 27 | licenseUrl = 'https://www.veeam.com/eula.html' 28 | requireLicenseAcceptance = 'false' 29 | dependencies = @( 30 | @{ 31 | id = 'veeam-iso' 32 | version = '[11.0.0.837]' 33 | } 34 | ) 35 | } 36 | files = @( 37 | @{ 38 | src = 'tools\**' 39 | target = 'tools' 40 | } 41 | ) 42 | } 43 | } -------------------------------------------------------------------------------- /examples/veeam/packages/redistr-windows.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-redistr-linux' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Packages\VALRedist.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_EULA = '1' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | } 13 | } 14 | manifest = @{ 15 | metadata = @{ 16 | id = 'veeam-redistr-linux' 17 | title = 'Redistributable Package for Veeam Agent for Linux' 18 | version = '11.0.0.837' 19 | authors = 'Veeam' 20 | owners = 'Joshua Gilman' 21 | summary = 'Installs the Redistributable Package for Veeam Agent for Linux' 22 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 23 | projectUrl = 'http://www.veeam.com/' 24 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 25 | tags = 'veeam backup replication redistrutable agent linux' 26 | copyright = '2021 Veeam' 27 | licenseUrl = 'https://www.veeam.com/eula.html' 28 | requireLicenseAcceptance = 'false' 29 | dependencies = @( 30 | @{ 31 | id = 'veeam-iso' 32 | version = '[11.0.0.837]' 33 | } 34 | ) 35 | } 36 | files = @( 37 | @{ 38 | src = 'tools\**' 39 | target = 'tools' 40 | } 41 | ) 42 | } 43 | } -------------------------------------------------------------------------------- /examples/veeam/packages/explorer-exchange.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-explorer-exchange' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Explorers\VeeamExplorerforExchange.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_EULA = '1' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | } 13 | } 14 | manifest = @{ 15 | metadata = @{ 16 | id = 'veeam-explorer-exchange' 17 | title = 'Veeam Explorer for Microsoft Exchange' 18 | version = '11.0.0.837' 19 | authors = 'Veeam' 20 | owners = 'Joshua Gilman' 21 | summary = 'Installs the Veeam Explorer for Microsoft Exchange' 22 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 23 | projectUrl = 'http://www.veeam.com/' 24 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 25 | tags = 'veeam backup replication explorer microsoft exchange' 26 | copyright = '2021 Veeam' 27 | licenseUrl = 'https://www.veeam.com/eula.html' 28 | requireLicenseAcceptance = 'false' 29 | dependencies = @( 30 | @{ 31 | id = 'veeam-iso' 32 | version = '[11.0.0.837]' 33 | } 34 | ) 35 | } 36 | files = @( 37 | @{ 38 | src = 'tools\**' 39 | target = 'tools' 40 | } 41 | ) 42 | } 43 | } -------------------------------------------------------------------------------- /examples/veeam/packages/explorer-ad.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-explorer-ad' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Explorers\VeeamExplorerforActiveDirectory.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_EULA = '1' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | } 13 | } 14 | manifest = @{ 15 | metadata = @{ 16 | id = 'veeam-explorer-ad' 17 | title = 'Veeam Explorer for Microsoft Active Directory' 18 | version = '11.0.0.837' 19 | authors = 'Veeam' 20 | owners = 'Joshua Gilman' 21 | summary = 'Installs the Veeam Explorer for Microsoft Active Directory' 22 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 23 | projectUrl = 'http://www.veeam.com/' 24 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 25 | tags = 'veeam backup replication explorer active directory' 26 | copyright = '2021 Veeam' 27 | licenseUrl = 'https://www.veeam.com/eula.html' 28 | requireLicenseAcceptance = 'false' 29 | dependencies = @( 30 | @{ 31 | id = 'veeam-iso' 32 | version = '[11.0.0.837]' 33 | } 34 | ) 35 | } 36 | files = @( 37 | @{ 38 | src = 'tools\**' 39 | target = 'tools' 40 | } 41 | ) 42 | } 43 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/static/template/iso/ChocolateyInstall.eps: -------------------------------------------------------------------------------- 1 | Function Expand-DiskImage { 2 | param( 3 | [string] $Path, 4 | [string] $Destination 5 | ) 6 | 7 | Write-Host ('Mounting image at {0}...' -f $Path) 8 | Mount-DiskImage -ImagePath $Path 9 | $img = Get-DiskImage -ImagePath $Path 10 | $driveLetter = $img | Get-Volume | Select-Object -ExpandProperty DriveLetter 11 | $drivePath = Get-PSDrive -Name $driveLetter | Select-Object -ExpandProperty Root 12 | 13 | Write-Host ('Copying ISO files from {0} to {1}' -f $drivePath, $Destination) 14 | Copy-Item (Join-Path $drivePath '*') $Destination -Recurse | Out-Null 15 | 16 | Write-Host 'Unmounting image...' 17 | Dismount-DiskImage -ImagePath $Path | Out-Null 18 | } 19 | 20 | Function Invoke-Unshim { 21 | param($BuildPath) 22 | 23 | $exeFiles = Get-ChildItem $BuildPath -Filter '*.exe' -Recurse 24 | foreach ($file in $exeFiles) { 25 | $ignoreFile = $file.FullName + '.ignore' 26 | 27 | Write-Verbose('Preventing shim of {0} with {1}...' -f $file.FullName, $ignoreFile) 28 | Set-Content $ignoreFile '' 29 | } 30 | } 31 | 32 | $packageName = '<%= $packageName %>' 33 | $filePath = '<%= $filePath %>' 34 | $url = '<%= $url %>' 35 | $hash = '<%= $hash %>' 36 | 37 | $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition 38 | $packageDir = Split-Path -parent $scriptDir 39 | $fileFullPath = Join-Path $packageDir $filePath 40 | 41 | Write-Verbose ('Package directory is {0}' -f $packageDir) 42 | Write-Host ('Downloading ISO file to {0}...' -f $fileFullPath) 43 | Get-ChocolateyWebFile ` 44 | -PackageName $env:ChocolateyPackageName ` 45 | -FileFullpath $fileFullPath ` 46 | -Url $url ` 47 | -Checksum $hash ` 48 | -ChecksumType sha1 49 | 50 | Write-Host ('Extracting ISO contents to {0}...' -f $packageDir) 51 | Expand-DiskImage $fileFullPath $packageDir 52 | 53 | Write-Host 'Removing ISO file...' 54 | Remove-Item $fileFullPath -Force 55 | 56 | Write-Host 'Preventing shimming of exe files...' 57 | Invoke-Unshim $packageDir -------------------------------------------------------------------------------- /examples/veeam/packages/explorer-sharepoint.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-explorer-sharepoint' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Explorers\VeeamExplorerforSharePoint.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_EULA = '1' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | } 13 | } 14 | manifest = @{ 15 | metadata = @{ 16 | id = 'veeam-explorer-sharepoint' 17 | title = 'Veeam Explorer for Microsoft SharePoint' 18 | version = '11.0.0.837' 19 | authors = 'Veeam' 20 | owners = 'Joshua Gilman' 21 | summary = 'Installs the Veeam Explorer for Microsoft SharePoint' 22 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 23 | projectUrl = 'http://www.veeam.com/' 24 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 25 | tags = 'veeam backup replication explorer microsoft sharepoint' 26 | copyright = '2021 Veeam' 27 | licenseUrl = 'https://www.veeam.com/eula.html' 28 | requireLicenseAcceptance = 'false' 29 | dependencies = @( 30 | @{ 31 | id = 'veeam-iso' 32 | version = '[11.0.0.837]' 33 | } 34 | ) 35 | } 36 | files = @( 37 | @{ 38 | src = 'tools\**' 39 | target = 'tools' 40 | } 41 | ) 42 | } 43 | } -------------------------------------------------------------------------------- /examples/veeam/packages/redistr-linux.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-redistr-windows' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Packages\VAWRedist.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_EULA = '1' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | } 13 | } 14 | manifest = @{ 15 | metadata = @{ 16 | id = 'veeam-redistr-windows' 17 | title = 'Redistributable Package for Veeam Agent for Microsoft Windows' 18 | version = '11.0.0.837' 19 | authors = 'Veeam' 20 | owners = 'Joshua Gilman' 21 | summary = 'Installs the Redistributable Package for Veeam Agent for Microsoft Windows' 22 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 23 | projectUrl = 'http://www.veeam.com/' 24 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 25 | tags = 'veeam backup replication redistrutable agent windows' 26 | copyright = '2021 Veeam' 27 | licenseUrl = 'https://www.veeam.com/eula.html' 28 | requireLicenseAcceptance = 'false' 29 | dependencies = @( 30 | @{ 31 | id = 'veeam-iso' 32 | version = '[11.0.0.837]' 33 | } 34 | ) 35 | } 36 | files = @( 37 | @{ 38 | src = 'tools\**' 39 | target = 'tools' 40 | } 41 | ) 42 | } 43 | } -------------------------------------------------------------------------------- /examples/chrome-enterprise/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'chrome-enterprise' 3 | processScript = 'process.ps1' 4 | installer = @{ 5 | scriptPath = 'tools' 6 | installerPath = 'tools\GoogleChromeStandaloneEnterprise64.msi' 7 | installerType = 'msi' 8 | flags = '/qn' 9 | } 10 | remoteFiles = @( 11 | @{ 12 | url = 'https://dl.google.com/tag/s/appguid%3D%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26iid%3D%7B28B3FC2A-8F28-9145-D051-455305F69948%7D%26lang%3Den%26browser%3D4%26usagestats%3D0%26appname%3DGoogle%2520Chrome%26needsadmin%3Dtrue%26ap%3Dx64-stable-statsdef_0%26brand%3DGCEB/dl/chrome/install/GoogleChromeEnterpriseBundle64.zip' 13 | sha1 = '75B3C0F78E8747FB638211E1E06F9A58F32104ED' 14 | importPath = 'tools/chrome.zip' 15 | } 16 | ) 17 | manifest = @{ 18 | metadata = @{ 19 | id = 'chrome-enterprise' 20 | title = 'Google Chrome' 21 | version = '90.0.4430.85' 22 | authors = 'Google' 23 | owners = 'Joshua Gilman' 24 | summary = 'Installs Google Chrome' 25 | description = "Get more done with the new Google Chrome. A more simple, secure, and faster web browser than ever, with Google's smarts built-in." 26 | projectUrl = 'https://www.google.com/chrome/' 27 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 28 | tags = 'Google Chrome Browser Web' 29 | copyright = '2021 Google' 30 | licenseUrl = 'https://chromeenterprise.google/terms/chrome-service-license-agreement/' 31 | requireLicenseAcceptance = 'false' 32 | } 33 | files = @( 34 | @{ 35 | src = 'tools\**' 36 | target = 'tools' 37 | } 38 | ) 39 | } 40 | } -------------------------------------------------------------------------------- /examples/ms-reportviewer2015/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'ms-reportviewer2015' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'tools/ReportViewer.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 3010, 1603, 1641) 8 | flags = '/qn /norestart' 9 | } 10 | remoteFiles = @( 11 | @{ 12 | url = 'https://download.microsoft.com/download/A/1/2/A129F694-233C-4C7C-860F-F73139CF2E01/ENU/x86/ReportViewer.msi' 13 | sha1 = 'DDF94C52F2CBA110306916667EFD168DD260769D' 14 | importPath = 'tools/ReportViewer.msi' 15 | } 16 | ) 17 | manifest = @{ 18 | metadata = @{ 19 | id = 'ms-reportviewer2015' 20 | title = 'Microsoft Report Viewer 2015 Runtime' 21 | version = '12.0.2402.15' 22 | authors = 'Microsoft' 23 | owners = 'Joshua Gilman' 24 | summary = 'Installs Microsoft Report Viewer 2015 Runtime' 25 | description = 'The Microsoft Report Viewer 2015 Runtime redistributable package, includes controls for viewing reports designed using Microsoft reporting technology.' 26 | projectUrl = 'https://www.microsoft.com/en-us/download/details.aspx?id=45496' 27 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 28 | tags = 'microsoft report viewer 2015 runtime' 29 | copyright = '2021 Microsoft' 30 | licenseUrl = 'https://www.microsoft.com/en-us/download/details.aspx?id=45496' 31 | requireLicenseAcceptance = 'false' 32 | dependencies = @( 33 | @{ 34 | id = 'sql-2014-smo' 35 | version = '' 36 | } 37 | ) 38 | } 39 | files = @( 40 | @{ 41 | src = 'tools\**' 42 | target = 'tools' 43 | } 44 | ) 45 | } 46 | } -------------------------------------------------------------------------------- /examples/buildISO.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param( 3 | [string] $PackageFile, 4 | [string] $OutPath 5 | ) 6 | 7 | $ErrorActionPreference = 'Stop' 8 | Import-Module (Join-Path $PSScriptRoot '..\ChocolateyPackageCreator') -Force 9 | 10 | if (!(Test-Path $PackageFile)) { 11 | throw 'Cannot find meta package file at {0}' -f $ConfigFile 12 | } 13 | 14 | if (!(Test-Path $OutPath)) { 15 | throw 'The output path must already exist at {0}' -f $OutPath 16 | } 17 | 18 | $verbose = $PSCmdlet.MyInvocation.BoundParameters['Verbose'] 19 | $hasDefender = Test-Path (Join-Path $env:ProgramFiles 'Windows Defender/MpCmdRun.exe' -ErrorAction SilentlyContinue) 20 | $packagePath = Split-Path -Parent $PackageFile 21 | 22 | # Load meta package 23 | Write-Verbose ('Loading meta package at {0}' -f $PackageFile) 24 | $metaConfig = Import-PowerShellDataFile $PackageFile 25 | $metaPackage = New-ChocolateyPackage $packagePath $metaConfig 26 | 27 | # Load ISO package 28 | $isoPackagePath = Join-Path $packagePath 'iso.psd1' 29 | if (!(Test-Path $isoPackagePath)) { 30 | throw 'Could not find ISO package at {0}' -f $isoPackagePath 31 | } 32 | 33 | Write-Verbose ('Loading iso package at {0}' -f $isoPackagePath) 34 | $isoConfig = Import-PowerShellDataFile $isoPackagePath 35 | 36 | # Load all sub packages 37 | $packages = [System.Collections.ArrayList]@() 38 | $packagesPath = Join-Path $packagePath 'packages' 39 | 40 | Write-Verbose ('Searching for sub-packages at {0}...' -f $packagesPath) 41 | $subPackagePaths = Get-ChildItem $packagesPath -Filter '*.psd1' -Recurse 42 | foreach ($subPackageFile in $subPackagePaths) { 43 | Write-Verbose ('Loading sub-package at {0}...' -f $subPackageFile.FullName) 44 | $packageConfig = Import-PowerShellDataFile $subPackageFile.FullName 45 | $packages.Add((New-ChocolateyPackage $subPackageFile.Parent.FullName $packageConfig)) | Out-Null 46 | } 47 | 48 | # Create ISO package 49 | $isoPackage = New-ChocolateyISOPackage $PackagePath $isoConfig $metaPackage $packages 50 | 51 | Write-Verbose 'Building packages...' 52 | $packageFiles = Build-ChocolateyISOPackage ` 53 | -Package $IsoPackage ` 54 | -OutPath $OutPath ` 55 | -ScanFiles:$hasDefender ` 56 | -Verbose:$verbose 57 | 58 | $packageFiles -------------------------------------------------------------------------------- /examples/veeam/packages/catalog.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-catalog' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Catalog\VeeamBackupCatalog64.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPT_THIRDPARTY_LICENSES = '1' 11 | INSTALLDIR = '' 12 | VM_CATALOGPATH = '' 13 | VBRC_SERVICE_USER = '' 14 | VBRC_SERVICE_PASSWORD = '' 15 | VBRC_SERVICE_PORT = '' 16 | } 17 | } 18 | manifest = @{ 19 | metadata = @{ 20 | id = 'veeam-catalog' 21 | title = 'Veeam Backup & Replication Catalog' 22 | version = '11.0.0.837' 23 | authors = 'Veeam' 24 | owners = 'Joshua Gilman' 25 | summary = 'Installs the Veeam Backup & Replication Catalog service' 26 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 27 | projectUrl = 'http://www.veeam.com/' 28 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 29 | tags = 'veeam backup replication catalog' 30 | copyright = '2021 Veeam' 31 | licenseUrl = 'https://www.veeam.com/eula.html' 32 | requireLicenseAcceptance = 'false' 33 | dependencies = @( 34 | @{ 35 | id = 'veeam-iso' 36 | version = '[11.0.0.837]' 37 | }, 38 | @{ 39 | id = 'dotnet-472' 40 | version = '' 41 | } 42 | ) 43 | } 44 | files = @( 45 | @{ 46 | src = 'tools\**' 47 | target = 'tools' 48 | } 49 | ) 50 | } 51 | } -------------------------------------------------------------------------------- /examples/sql-express-adv/files/ChocolateyInstall.ps1: -------------------------------------------------------------------------------- 1 | $packageName = 'sql-express-adv' 2 | $fileName = 'SETUP.exe' 3 | $fileType = 'exe' 4 | 5 | $config = @{ 6 | ROLE = 'AllFeatures_WithDefaults' 7 | ENU = 'True' 8 | UIMODE = 'Normal' 9 | UPDATEENABLED = 'False' 10 | USEMICROSOFTUPDATE = 'False' 11 | UPDATESOURCE = 'MU' 12 | FEATURES = 'SQLENGINE,REPLICATION,ADVANCEDANALYTICS,SQL_INST_MR,SQL_INST_MPY,SQL_INST_JAVA,FULLTEXT' 13 | X86 = 'False' 14 | INSTANCENAME = 'SQLEXPRESS' 15 | INSTALLSHAREDIR = 'C:\Program Files\Microsoft SQL Server' 16 | INSTALLSHAREDWOWDIR = 'C:\Program Files (x86)\Microsoft SQL Server' 17 | INSTANCEID = 'SQLEXPRESS' 18 | SQLTELSVCACCT = 'NT AUTHORITY\NETWORK SERVICE' 19 | SQLTELSVCSTARTUPTYPE = 'Disabled' 20 | INSTANCEDIR = 'C:\Program Files\Microsoft SQL Server' 21 | AGTSVCACCOUNT = 'NT AUTHORITY\NETWORK SERVICE' 22 | SQLSVCACCOUNT = 'NT AUTHORITY\NETWORK SERVICE' 23 | SQLSYSADMINACCOUNTS = 'BUILTIN\Administrators' 24 | ADDCURRENTUSERASSQLADMIN = 'True' 25 | TCPENABLED = '1' 26 | NPENABLED = '1' 27 | EXTSVCACCOUNT = 'NT AUTHORITY\NETWORK SERVICE' 28 | FTSVCACCOUNT = 'NT AUTHORITY\NETWORK SERVICE' 29 | } 30 | 31 | Write-Host 'Building configuration...' 32 | $param = Get-PackageParameters 33 | foreach ($p in $param.GetEnumerator()) { 34 | if ($p.Name -in $config.Keys) { 35 | $config[$p.Name] = $p.Value 36 | } 37 | } 38 | 39 | $toolsDir = Split-Path -Parent $MyInvocation.MyCommand.Definition 40 | $fileLocation = Join-Path $toolsDir $fileName 41 | 42 | Write-Host 'Writing configuration...' 43 | $configContent = Invoke-EpsTemplate -Path (Join-Path $toolsDir 'config.eps') -Binding $config -Safe 44 | Set-Content -Path (Join-Path $toolsDir 'config.ini') -Value $configContent 45 | 46 | Write-Host 'Installing...' 47 | $silentArgs = "/Q /IACCEPTSQLSERVERLICENSETERMS /ConfigurationFile=$(Join-Path $toolsDir 'config.ini')" 48 | Install-ChocolateyInstallPackage ` 49 | -PackageName $packageName ` 50 | -FileType $fileType ` 51 | -File64 $fileLocation ` 52 | -SilentArgs $silentArgs -------------------------------------------------------------------------------- /examples/sql-2014-clr/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'sql-2014-clr' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'tools/SQLSysClrTypesx86.msi' 6 | installerPath64 = 'tools/SQLSysClrTypesx64.msi' 7 | installerType = 'msi' 8 | exitCodes = @(0, 1641, 3010) 9 | flags = '/qn /norestart' 10 | } 11 | remoteFiles = @( 12 | @{ 13 | url = 'https://download.microsoft.com/download/6/7/8/67858AF1-B1B3-48B1-87C4-4483503E71DC/ENU/x86/SQLSysClrTypes.msi' 14 | sha1 = '4175191DAFA15D582C2438DAAA9E1EE19D68AB63' 15 | importPath = 'tools/SQLSysClrTypesx86.msi' 16 | } 17 | @{ 18 | url = 'https://download.microsoft.com/download/6/7/8/67858AF1-B1B3-48B1-87C4-4483503E71DC/ENU/x64/SQLSysClrTypes.msi' 19 | sha1 = 'C7457913643083C0A1C27E637F8E9043B3E94E66' 20 | importPath = 'tools/SQLSysClrTypesx64.msi' 21 | } 22 | ) 23 | manifest = @{ 24 | metadata = @{ 25 | id = 'sql-2014-clr' 26 | title = 'Microsoft System CLR Types for SQL Server 2014' 27 | version = '12.2.5000.0' 28 | authors = 'Microsoft' 29 | owners = 'Joshua Gilman' 30 | summary = 'Installs System CLR Types for SQL Server 2014' 31 | description = 'The SQL Server System CLR Types package contains the components implementing the new geometry, geography, and hierarchyid types in SQL Server 2014.' 32 | projectUrl = 'https://www.microsoft.com/en-us/download/details.aspx?id=53164' 33 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 34 | tags = 'microsoft-system-clr-types-for-sql-server-2014 SQL SQL2014 .NET CLR' 35 | copyright = '2021 Microsoft' 36 | licenseUrl = 'https://www.microsoft.com/en-us/download/details.aspx?id=53164' 37 | requireLicenseAcceptance = 'false' 38 | } 39 | files = @( 40 | @{ 41 | src = 'tools\**' 42 | target = 'tools' 43 | } 44 | ) 45 | } 46 | } -------------------------------------------------------------------------------- /examples/sql-express-adv/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'sql-express-adv' 3 | processScript = 'process.ps1' 4 | localFiles = @( 5 | @{ 6 | localPath = 'files/config.eps' 7 | importPath = 'tools/config.eps' 8 | } 9 | @{ 10 | localPath = 'files/ChocolateyInstall.ps1' 11 | importPath = 'tools/ChocolateyInstall.ps1' 12 | } 13 | ) 14 | remoteFiles = @( 15 | @{ 16 | url = 'https://download.microsoft.com/download/8/4/c/84c6c430-e0f5-476d-bf43-eaaa222a72e0/SQLEXPRADV_x64_ENU.exe' 17 | sha1 = 'C70158B4A53960D3029B9688D781F166FA8BC637' 18 | importPath = 'tools/SQLEXPRADV_x64_ENU.exe' 19 | } 20 | ) 21 | manifest = @{ 22 | metadata = @{ 23 | id = 'sql-express-adv' 24 | title = 'Microsoft SQL Server Express 2019 with Advanced Services' 25 | version = '15.0.2000.5' 26 | authors = 'Microsoft' 27 | owners = 'Joshua Gilman' 28 | summary = 'Installs SQL Server 2019 Express database engine' 29 | description = 'Experience the full feature set of SQL Server Express. This package contains the Database Engine, Reporting Services, and Full Text Search features.' 30 | projectUrl = 'https://www.microsoft.com/en-us/server-cloud/products/sql-server-editions/sql-server-express.aspx' 31 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageCreator' 32 | tags = 'sql server express 2019' 33 | copyright = '2021 Microsoft' 34 | licenseUrl = 'https://download.microsoft.com/download/6/6/0/66078040-86d8-4f6e-b0c5-e9919bbcb537/SQL%20Server%202019%20Licensing%20guide.pdf' 35 | requireLicenseAcceptance = 'false' 36 | dependencies = @( 37 | @{ 38 | id = 'eps.extension' 39 | version = '1.0.0' 40 | } 41 | ) 42 | } 43 | files = @( 44 | @{ 45 | src = 'tools\**' 46 | target = 'tools' 47 | } 48 | ) 49 | } 50 | } -------------------------------------------------------------------------------- /examples/vcredist/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'vcredist' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'tools/VC_redist.x86.exe' 6 | installerPath64 = 'tools/VC_redist.x64.exe' 7 | installerType = 'exe' 8 | exitCodes = @(0, 1638, 3010) 9 | flags = '/quiet /norestart' 10 | } 11 | remoteFiles = @( 12 | @{ 13 | url = 'https://download.visualstudio.microsoft.com/download/pr/85d47aa9-69ae-4162-8300-e6b7e4bf3cf3/52B196BBE9016488C735E7B41805B651261FFA5D7AA86EB6A1D0095BE83687B2/VC_redist.x64.exe' 14 | sha1 = 'A4EFAD335D3CCFA19963F53398E87BE5C8BEBC45' 15 | importPath = 'tools/VC_redist.x64.exe' 16 | } 17 | @{ 18 | url = 'https://download.visualstudio.microsoft.com/download/pr/85d47aa9-69ae-4162-8300-e6b7e4bf3cf3/14563755AC24A874241935EF2C22C5FCE973ACB001F99E524145113B2DC638C1/VC_redist.x86.exe' 19 | sha1 = 'D848A57ADB68456B91BD8BA5108C116DE8DA8F25' 20 | importPath = 'tools/VC_redist.x86.exe' 21 | } 22 | ) 23 | manifest = @{ 24 | metadata = @{ 25 | id = 'vcredist' 26 | title = 'Microsoft Visual C++ Redistributable' 27 | version = '14.28.29914' 28 | authors = 'Microsoft' 29 | owners = 'Joshua Gilman' 30 | summary = 'Installs Microsoft Visual C++ Redistributable' 31 | description = 'Run-time components that are required to run C++ applications that are built by using Visual Studio 2015-2019' 32 | projectUrl = 'https://visualstudio.microsoft.com/vs/' 33 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 34 | tags = 'microsoft visual c++ redistributable 140 2015 2017 2019' 35 | copyright = '2021 Microsoft' 36 | licenseUrl = 'https://visualstudio.microsoft.com/license-terms/mlt031619/' 37 | requireLicenseAcceptance = 'false' 38 | } 39 | files = @( 40 | @{ 41 | src = 'tools\**' 42 | target = 'tools' 43 | } 44 | ) 45 | } 46 | } -------------------------------------------------------------------------------- /examples/veeam/packages/console.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-console' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Backup/Shell.x64.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPTEULA = 'yes' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | INSTALLDIR = '' 13 | } 14 | } 15 | manifest = @{ 16 | metadata = @{ 17 | id = 'veeam-console' 18 | title = 'Veeam Backup & Replication Console' 19 | version = '11.0.0.837' 20 | authors = 'Veeam' 21 | owners = 'Joshua Gilman' 22 | summary = 'Installs the Veeam Backup & Replication Console' 23 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 24 | projectUrl = 'http://www.veeam.com/' 25 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 26 | tags = 'veeam backup replication console' 27 | copyright = '2021 Veeam' 28 | licenseUrl = 'https://www.veeam.com/eula.html' 29 | requireLicenseAcceptance = 'false' 30 | dependencies = @( 31 | @{ 32 | id = 'veeam-iso' 33 | version = '[11.0.0.837]' 34 | }, 35 | @{ 36 | id = 'dotnet-472' 37 | version = '' 38 | }, 39 | @{ 40 | id = 'ms-reportviewer2015' 41 | version = '' 42 | }, 43 | @{ 44 | id = 'sql-2014-smo' 45 | version = '' 46 | } 47 | ) 48 | } 49 | files = @( 50 | @{ 51 | src = 'tools\**' 52 | target = 'tools' 53 | } 54 | ) 55 | } 56 | } -------------------------------------------------------------------------------- /examples/sql-2014-smo/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'sql-2014-smo' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'tools/SharedManagementObjectsx86.msi' 6 | installerPath64 = 'tools/SharedManagementObjectsx64.msi' 7 | installerType = 'msi' 8 | exitCodes = @(0, 1641, 3010) 9 | flags = '/qn /norestart' 10 | } 11 | remoteFiles = @( 12 | @{ 13 | url = 'https://download.microsoft.com/download/6/7/8/67858AF1-B1B3-48B1-87C4-4483503E71DC/ENU/x86/SharedManagementObjects.msi' 14 | sha1 = 'C07B882538863A2B125A2EDA29D269D803CD0F0D' 15 | importPath = 'tools/SharedManagementObjectsx86.msi' 16 | } 17 | @{ 18 | url = 'https://download.microsoft.com/download/6/7/8/67858AF1-B1B3-48B1-87C4-4483503E71DC/ENU/x64/SharedManagementObjects.msi' 19 | sha1 = '2754C510EB14CCABF5E57E784A7E69B845531B5B' 20 | importPath = 'tools/SharedManagementObjectsx64.msi' 21 | } 22 | ) 23 | manifest = @{ 24 | metadata = @{ 25 | id = 'sql-2014-smo' 26 | title = 'Microsoft SQL Server 2014 Management Objects' 27 | version = '12.2.5000.0' 28 | authors = 'Microsoft' 29 | owners = 'Joshua Gilman' 30 | summary = 'Installs Microsoft SQL Server 2014 Management Objects' 31 | description = 'The SQL Server Management Objects (SMO) is a .NET Framework object model that enables software developers to create client-side applications to manage and administer SQL Server objects and services.' 32 | projectUrl = 'https://www.microsoft.com/en-us/download/details.aspx?id=53164' 33 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 34 | tags = 'microsoft-sql-server-2014-management-objects SQL SQL2014 SMO .NET XML CLR' 35 | copyright = '2021 Microsoft' 36 | licenseUrl = 'https://docs.microsoft.com/en-us/sql/relational-databases/server-management-objects-smo/smo-license-terms?view=sql-server-2014' 37 | requireLicenseAcceptance = 'false' 38 | dependencies = @( 39 | @{ 40 | id = 'sql-2014-clr' 41 | version = '' 42 | } 43 | ) 44 | } 45 | files = @( 46 | @{ 47 | src = 'tools\**' 48 | target = 'tools' 49 | } 50 | ) 51 | } 52 | } -------------------------------------------------------------------------------- /examples/veeam/veeam.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam' 3 | manifest = @{ 4 | metadata = @{ 5 | id = 'veeam' 6 | title = 'Veeam Backup & Replication' 7 | version = '11.0.0.837' 8 | authors = 'Veeam' 9 | owners = 'Joshua Gilman' 10 | summary = 'Installs Veeam Backup & Replication' 11 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 12 | projectUrl = 'http://www.veeam.com/' 13 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 14 | tags = 'veeam backup replication' 15 | copyright = '2021 Veeam' 16 | licenseUrl = 'https://www.veeam.com/eula.html' 17 | requireLicenseAcceptance = 'false' 18 | dependencies = @( 19 | @{ 20 | id = 'veeam-catalog' 21 | version = '[11.0.0.837]' 22 | }, 23 | @{ 24 | id = 'veeam-server' 25 | version = '[11.0.0.837]' 26 | }, 27 | @{ 28 | id = 'veeam-console' 29 | version = '[11.0.0.837]' 30 | }, 31 | @{ 32 | id = 'veeam-explorer-ad' 33 | version = '[11.0.0.837]' 34 | }, 35 | @{ 36 | id = 'veeam-explorer-exchange' 37 | version = '[11.0.0.837]' 38 | }, 39 | @{ 40 | id = 'veeam-explorer-oracle' 41 | version = '[11.0.0.837]' 42 | }, 43 | @{ 44 | id = 'veeam-explorer-sharepoint' 45 | version = '[11.0.0.837]' 46 | }, 47 | @{ 48 | id = 'veeam-explorer-sql' 49 | version = '[11.0.0.837]' 50 | }, 51 | @{ 52 | id = 'veeam-redistr-windows' 53 | version = '[11.0.0.837]' 54 | }, 55 | @{ 56 | id = 'veeam-redistr-linux' 57 | version = '[11.0.0.837]' 58 | }, 59 | @{ 60 | id = 'veeam-redistr-mac' 61 | version = '[11.0.0.837]' 62 | } 63 | ) 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /examples/veeam/packages/enterprise.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-enterprise' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'EnterpriseManager\BackupWeb_x64.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPTEULA = 'yes' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | INSTALLDIR = '' 13 | VBREM_LICENSE_FILE = '' 14 | VBREM_SERVICE_USER = '' 15 | VBREM_SERVICE_PASSWORD = '' 16 | VBREM_SERVICE_PORT = '' 17 | VBREM_SQLSERVER_SERVER = 'localhost\SQLEXPRESS' 18 | VBREM_SQLSERVER_DATABASE = '' 19 | VBREM_SQLSERVER_AUTHENTICATION = '' 20 | VBREM_SQLSERVER_USERNAME = '' 21 | VBREM_SQLSERVER_PASSWORD = '' 22 | VBREM_TCPPORT = '' 23 | VBREM_SSLPORT = '' 24 | VBREM_THUMBPRINT = '' 25 | VBREM_RESTAPISVC_PORT = '' 26 | VBREM_RESTAPISVC_SSLPORT = '' 27 | VBREM_CONFIG_SCHANNEL = '' 28 | VBR_CHECK_UPDATES = '0' 29 | } 30 | } 31 | manifest = @{ 32 | metadata = @{ 33 | id = 'veeam-enterprise' 34 | title = 'Veeam Backup Enterprise Manager' 35 | version = '11.0.0.837' 36 | authors = 'Veeam' 37 | owners = 'Joshua Gilman' 38 | summary = 'Installs Veeam Backup Enterprise Manager' 39 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 40 | projectUrl = 'http://www.veeam.com/' 41 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 42 | tags = 'veeam backup replication catalog' 43 | copyright = '2021 Veeam' 44 | licenseUrl = 'https://www.veeam.com/eula.html' 45 | requireLicenseAcceptance = 'false' 46 | dependencies = @( 47 | @{ 48 | id = 'veeam-iso' 49 | version = '[11.0.0.837]' 50 | }, 51 | @{ 52 | id = 'veeam-catalog' 53 | version = '[11.0.0.837]' 54 | } 55 | ) 56 | } 57 | files = @( 58 | @{ 59 | src = 'tools\**' 60 | target = 'tools' 61 | } 62 | ) 63 | } 64 | } -------------------------------------------------------------------------------- /examples/python/package.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'python' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'tools\python-3.9.5.exe' 6 | installerPath64 = 'tools\python-3.9.5-amd64.exe' 7 | installerType = 'exe' 8 | flags = '/quiet' 9 | arguments = @{ 10 | InstallAllUsers = '1' 11 | TargetDir = '' 12 | DefaultAllUsersTargetDir = '' 13 | DefaultJustForMeTargetDir = '' 14 | DefaultCustomTargetDir = '' 15 | AssociateFiles = '' 16 | CompileAll = '' 17 | PrependPath = '1' 18 | Shortcuts = '' 19 | Include_doc = '' 20 | Include_debug = '' 21 | Include_dev = '' 22 | Include_exe = '' 23 | Include_launcher = '' 24 | InstallLauncherAllUsers = '' 25 | Include_lib = '' 26 | Include_pip = '' 27 | Include_symbols = '' 28 | Include_tcltk = '' 29 | Include_test = '' 30 | Include_tools = '' 31 | LauncherOnly = '' 32 | SimpleInstall = '' 33 | SimpleInstallDescription = '' 34 | } 35 | } 36 | remoteFiles = @( 37 | @{ 38 | url = 'https://www.python.org/ftp/python/3.9.5/python-3.9.5.exe' 39 | sha1 = '1A71DD77D9EF8C39AEB3AE218CD4F0353F8B3AFD' 40 | importPath = 'tools/python-3.9.5.exe' 41 | } 42 | @{ 43 | url = 'https://www.python.org/ftp/python/3.9.5/python-3.9.5-amd64.exe' 44 | sha1 = '248F7CE21FE350B308EFD5D13447ED4375696D4B' 45 | importPath = 'tools/python-3.9.5-amd64.exe' 46 | } 47 | ) 48 | manifest = @{ 49 | metadata = @{ 50 | id = 'python' 51 | title = 'Python 3' 52 | version = '3.9.5' 53 | authors = 'Python Software Foundation' 54 | owners = 'Joshua Gilman' 55 | summary = 'Installs Python 3' 56 | description = 'Python is a programming language that lets you work quickly and integrate systems more effectively.' 57 | projectUrl = 'https://www.python.org/' 58 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 59 | tags = 'python programming language' 60 | copyright = '2021 Python Software Foundation' 61 | licenseUrl = 'https://docs.python.org/3/license.html' 62 | requireLicenseAcceptance = 'false' 63 | } 64 | files = @( 65 | @{ 66 | src = 'tools\**' 67 | target = 'tools' 68 | } 69 | ) 70 | } 71 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/functions/publish.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Publishes the given Chocolatey package to the given NuGet repository 4 | .DESCRIPTION 5 | Using the given API key, connects to and publishes the given Chocolatey 6 | package to the given NuGet repository. This function will fail if the API 7 | key has insufficient permissions on the repository. 8 | .PARAMETER Repository 9 | The url of the NuGet repository to push to 10 | .PARAMETER ApiKey 11 | A NuGet API key with sufficient privileges to publish the package 12 | .PARAMETER PackageFile 13 | The path to the Chocolatey package file 14 | .PARAMETER Tool 15 | The tool to use to perform the publish: Chocolatey or NuGet 16 | .PARAMETER ChocolateyPath 17 | The path to the choco binary - defaults to 'choco' 18 | .PARAMETER NuGetPath 19 | The path to the NuGet binary - defaults to 'nuget' 20 | .PARAMETER ExtraArguments 21 | Additional arguments to pass to the choco binary during the push process 22 | .PARAMETER Force 23 | Whether to force the push using the --force flag 24 | .EXAMPLE 25 | Publish-ChocolateyPackage ` 26 | -Repository nuget.my.com ` 27 | -ApiKey 'myapikey' ` 28 | -PackageFile 'path/to/package.nupkg' 29 | -Force 30 | .OUTPUTS 31 | The exit code of the choco push process 32 | #> 33 | Function Publish-ChocolateyPackage { 34 | [cmdletbinding()] 35 | param( 36 | [Parameter( 37 | Mandatory = $true, 38 | Position = 1 39 | )] 40 | [string] $Repository, 41 | [Parameter( 42 | Mandatory = $true, 43 | Position = 2 44 | )] 45 | [string] $ApiKey, 46 | [Parameter( 47 | Mandatory = $true, 48 | Position = 3 49 | )] 50 | [string] $PackageFile, 51 | [ValidateSet('Chocolatey', 'NuGet')] 52 | [string] $Tool = 'Chocolatey', 53 | [string] $ChocolateyPath = 'choco', 54 | [string] $NuGetPath = 'nuget', 55 | [string[]] $ExtraArguments = @(), 56 | [switch] $Force 57 | ) 58 | 59 | Write-Verbose ('Pushing Chocolatey package at {0}...' -f $PackageFile) 60 | switch ($Tool) { 61 | Chocolatey { 62 | $toolPath = $ChocolateyPath 63 | $toolArgs = [System.Collections.ArrayList]@( 64 | 'push', 65 | $PackageFile, 66 | ('--source "{0}"' -f $Repository), 67 | ('--api-key "{0}"' -f $ApiKey) 68 | ) 69 | 70 | if ($Force) { 71 | $toolArgs.Add('--force') | Out-Null 72 | } 73 | } 74 | NuGet { 75 | $toolPath = $NuGetPath 76 | $toolArgs = [System.Collections.ArrayList]@( 77 | 'push', 78 | $PackageFile, 79 | ('-source "{0}"' -f $Repository), 80 | ('-apikey "{0}"' -f $ApiKey) 81 | ) 82 | } 83 | } 84 | 85 | if ($ExtraArguments) { 86 | $toolArgs += $ExtraArguments 87 | } 88 | 89 | # Don't print out sensitive information 90 | $logStr = "Executing `"{0} {1}`"" -f $toolPath, ($toolArgs -join ' ') 91 | Write-Verbose ($logStr -replace $ApiKey, '') 92 | 93 | $proc = Start-Process $toolPath -ArgumentList $toolArgs -PassThru -NoNewWindow -Wait 94 | $proc.ExitCode 95 | } -------------------------------------------------------------------------------- /examples/veeam/packages/server.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | name = 'veeam-server' 3 | installer = @{ 4 | scriptPath = 'tools' 5 | installerPath = 'Backup\Server.x64.msi' 6 | installerType = 'msi' 7 | exitCodes = @(0, 1638, 1641, 3010) 8 | flags = '/qn /norestart' 9 | arguments = @{ 10 | ACCEPTEULA = 'yes' 11 | ACCEPT_THIRDPARTY_LICENSES = '1' 12 | INSTALLDIR = '' 13 | VBR_LICENSE_FILE = '' 14 | VBR_SERVICE_USER = '' 15 | VBR_SERVICE_PASSWORD = '' 16 | VBR_SERVICE_PORT = '' 17 | VBR_SECURE_CONNECTIONS_PORT = '' 18 | VBR_SQLSERVER_SERVER = 'localhost\SQLEXPRESS' 19 | VBR_SQLSERVER_DATABASE = '' 20 | VBR_SQLSERVER_AUTHENTICATION = '' 21 | VBR_SQLSERVER_USERNAME = '' 22 | VBR_SQLSERVER_PASSWORD = '' 23 | VBR_IRCACHE = '' 24 | VBR_CHECK_UPDATES = '0' 25 | VBR_AUTO_UPGRADE = '1' 26 | } 27 | } 28 | manifest = @{ 29 | metadata = @{ 30 | id = 'veeam-server' 31 | title = 'Veeam Backup & Replication Server' 32 | version = '11.0.0.837' 33 | authors = 'Veeam' 34 | owners = 'Joshua Gilman' 35 | summary = 'Installs the Veeam Backup & Replication Server' 36 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 37 | projectUrl = 'http://www.veeam.com/' 38 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 39 | tags = 'veeam backup replication catalog' 40 | copyright = '2021 Veeam' 41 | licenseUrl = 'https://www.veeam.com/eula.html' 42 | requireLicenseAcceptance = 'false' 43 | dependencies = @( 44 | @{ 45 | id = 'veeam-iso' 46 | version = '[11.0.0.837]' 47 | }, 48 | @{ 49 | id = 'veeam-catalog' 50 | version = '[11.0.0.837]' 51 | }, 52 | @{ 53 | id = 'dotnet-472' 54 | version = '' 55 | }, 56 | @{ 57 | id = 'ms-reportviewer2015' 58 | version = '' 59 | }, 60 | @{ 61 | id = 'sql-2014-smo' 62 | version = '' 63 | } 64 | @{ 65 | id = 'vcredist' 66 | version = '' 67 | } 68 | ) 69 | } 70 | files = @( 71 | @{ 72 | src = 'tools\**' 73 | target = 'tools' 74 | } 75 | ) 76 | } 77 | } -------------------------------------------------------------------------------- /ChocolateyPackageCreator/static/template/default/ChocolateyInstall.eps: -------------------------------------------------------------------------------- 1 | $packageName = '<%= $packageName %>' 2 | $filePath = '<%= $filePath %>' 3 | $filePath64 = '<%= $filePath64 %>' 4 | $fileType = '<%= $fileType %>' 5 | $flags = '<%= $flags %>' 6 | $exitCodes = @(<%= $exitCodes -Join ', ' %>) 7 | $argumentPrefix = '<%= $argumentPrefix %>' 8 | 9 | <% if ($arguments.Count -eq 0) { -%> 10 | $arguments = @{} 11 | <%} else { -%> 12 | $arguments = @{ 13 | <%= ($arguments.GetEnumerator() | ForEach-Object { ' ' + $_.Name + ' = "' + $_.Value + '"' }) -Join "`n" %> 14 | } 15 | <% } -%> 16 | 17 | $params = Get-PackageParameters 18 | Write-Verbose ('Received {0} parameters from user' -f $params.Count) 19 | Write-Verbose ('This package supports {0} arguments' -f $arguments.Count) 20 | if (Get-Command ConvertTo-Json -ErrorAction SilentlyContinue) { 21 | Write-Verbose ('Parameters passed: {0}' -f (ConvertTo-Json $params -ErrorAction SilentlyContinue)) 22 | } 23 | 24 | # Build arguments 25 | if (($params.Count -gt 0) -and ($arguments.Count -eq 0)) { 26 | Write-Warning 'Parameters were given but this package does not take any parameters' 27 | } elseif (($params.Count -gt 0) -and ($arguments.Count -gt 0)) { 28 | foreach($param in $params.GetEnumerator()) { 29 | if (!($param.Name -in $arguments.Keys)) { 30 | Write-Warning ('This package does not have a {0} parameter' -f $param.Name) 31 | continue 32 | } 33 | 34 | $arguments[$param.Name] = $param.Value 35 | } 36 | } 37 | 38 | if (Get-Command ConvertTo-Json -ErrorAction SilentlyContinue) { 39 | Write-Verbose ('Final package arguments: {0}' -f (ConvertTo-Json $arguments -ErrorAction SilentlyContinue)) 40 | } 41 | 42 | # Build argument string 43 | $silentArgs = $flags 44 | 45 | if ($fileType.ToLower() -eq 'msi') { 46 | $logLocation = '{0}\{1}.{2}.log' -f $env:TEMP,$env:ChocolateyPackageName,$env:ChocolateyPackageVersion 47 | $silentArgs += ' /l*v "{0}"' -f $logLocation 48 | } 49 | 50 | foreach($argument in $arguments.GetEnumerator()) { 51 | if ($argument.Value) { 52 | $silentArgs += ' {0}{1}="{2}"' -f $argumentPrefix, $argument.Name, $argument.Value 53 | } 54 | } 55 | Write-Verbose ('Final package argument string: {0}' -f $silentArgs) 56 | 57 | $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition 58 | $packageDir = Split-Path -Parent $scriptDir 59 | Write-Verbose ('Package directory is {0}' -f $packageDir) 60 | 61 | $fileLocation = Join-Path $packageDir $filePath 62 | $fileLocation = (Get-Item $fileLocation).FullName # Resolve relative paths 63 | Write-Verbose ('Using installer at {0}' -f $fileLocation) 64 | 65 | if ($filePath64) { 66 | $fileLocation64 = Join-Path $packageDir $filePath64 67 | $fileLocation64 = (Get-Item $fileLocation64).FullName 68 | Write-Verbose ('Using 64-bit installer at {0}' -f $fileLocation64) 69 | } 70 | 71 | Write-Host ('Log location is {0}' -f $logLocation) 72 | if ($filePath64) { 73 | Install-ChocolateyInstallPackage ` 74 | -PackageName $packageName ` 75 | -FileType $fileType ` 76 | -File $fileLocation ` 77 | -File64 $fileLocation64 ` 78 | -SilentArgs $silentArgs.Trim() ` 79 | -ValidExitCodes $exitCodes 80 | } else { 81 | Install-ChocolateyInstallPackage ` 82 | -PackageName $packageName ` 83 | -FileType $fileType ` 84 | -File $fileLocation ` 85 | -SilentArgs $silentArgs.Trim() ` 86 | -ValidExitCodes $exitCodes 87 | } 88 | -------------------------------------------------------------------------------- /ChocolateyPackageCreator/ChocolateyPackageCreator.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'ChocolateyPackageCreator' 3 | # 4 | # Generated by: Joshua Gilman 5 | # 6 | # Generated on: 3/27/2021 7 | # 8 | 9 | @{ 10 | # Script module or binary module file associated with this manifest. 11 | RootModule = './ChocolateyPackageCreator.psm1' 12 | 13 | # Version number of this module. 14 | ModuleVersion = '0.2.0' 15 | 16 | # Supported PSEditions 17 | CompatiblePSEditions = @( 'Desktop', 'Core' ) 18 | 19 | # ID used to uniquely identify this module 20 | GUID = 'bcd24428-27bd-441b-aa3a-3cf211fdca1b' 21 | 22 | # Author of this module 23 | Author = 'Joshua Gilman' 24 | 25 | # Company or vendor of this module 26 | CompanyName = '' 27 | 28 | # Copyright statement for this module 29 | Copyright = '(c) Joshua Gilman. All rights reserved.' 30 | 31 | # Description of the functionality provided by this module 32 | Description = 'Powershell module for creating internal Chocolatey packages' 33 | 34 | # Minimum version of the PowerShell engine required by this module 35 | PowerShellVersion = '5.1' 36 | 37 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 38 | FunctionsToExport = @( 39 | 'New-ChocolateyPackage', 40 | 'New-ChocolateyISOPackage', 41 | 'New-ChocolateyPackageConfig', 42 | 'Build-ChocolateyPackage', 43 | 'Build-ChocolateyISOPackage', 44 | 'Publish-ChocolateyPackage' 45 | ) 46 | 47 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 48 | CmdletsToExport = @() 49 | 50 | # Variables to export from this module 51 | VariablesToExport = @() 52 | 53 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 54 | AliasesToExport = @() 55 | 56 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 57 | PrivateData = @{ 58 | 59 | PSData = @{ 60 | 61 | # Tags applied to this module. These help with module discovery in online galleries. 62 | Tags = @('chocolatey', 'package', 'creator', 'management') 63 | 64 | # A URL to the license for this module. 65 | LicenseUri = 'https://www.mit.edu/~amini/LICENSE.md' 66 | 67 | # A URL to the main website for this project. 68 | ProjectUri = 'https://github.com/jmgilman/ChocolateyPackageCreator' 69 | 70 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save 71 | RequireLicenseAcceptance = $false 72 | 73 | # External dependent modules of this module 74 | ExternalModuleDependencies = @('EPS') 75 | 76 | } # End of PSData hashtable 77 | 78 | } # End of PrivateData hashtable 79 | 80 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 81 | # DefaultCommandPrefix = '' 82 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.2.0] - 2021-05-18 11 | 12 | ### Added 13 | - Adds documentation for package file schema 14 | 15 | ### Changed 16 | - Refactors the validation logic to use schema files 17 | - Package files only need to declare required properties now instead of every property 18 | 19 | ## [0.1.1] - 2021-05-05 20 | 21 | ### Added 22 | - Additional logging to generated installation scripts 23 | - Support for defining the argument prefix in installation scripts 24 | 25 | ## [0.1.0] - 2021-05-04 26 | 27 | ### Added 28 | - Adds `Installer` property to configuration file for dynamically creating the ChocolateyInstall.ps1 file 29 | - Adds `New-ChocolateyISOPackage` and `Build-ChocolateyISOPackage` for building multiple packages against a single ISO 30 | - Adds `Tool` parameter to `Publish-ChocolateyPackage` to support pushing via the NuGet CLI tool 31 | - Updates Chrome example to use new `Installer` property 32 | - Adds Veeam example demonstrating creation of a ChocolateyISOPackage 33 | - Adds getting started guide and supporting documentation for the ISO package format 34 | 35 | ## [0.0.6] - 2021-04-29 36 | 37 | ### Added 38 | - Adds force flag to cleanup operation 39 | 40 | ## [0.0.5] - 2021-04-27 41 | 42 | ### Fixed 43 | - Fixes bug where an empty process script has its path qualified 44 | 45 | ## [0.0.4] - 2021-04-24 46 | 47 | ### Added 48 | - Adds an example for packaging the Powershell EPS extension 49 | - Adds an example for packaging SQL Server Express 2019 (Advanced) 50 | 51 | ### Changed 52 | - Process scripts now receive two parameters, the build path and a copy of the ChocolateyPackage object 53 | - Updates Chrome example to use new process script parameter 54 | - Moves unshimming process to execute after the process script is executed 55 | - README improvements 56 | 57 | ### Removed 58 | - Removes example for packaging this repository as an extension 59 | 60 | ## [0.0.3] - 2021-04-24 61 | 62 | ### Changed 63 | - Moved the `dependencies` property to its correct place under `metadata` 64 | - Updated the NuSpec generation logic to be more dynamic 65 | - Improves verbose logging 66 | 67 | ## [0.0.2] - 2021-04-24 68 | 69 | ### Added 70 | - Example Azure DevOps pipeline file for Chrome example 71 | 72 | ### Changed 73 | - Updated Github repository URL to be correct 74 | 75 | ## [0.0.1] - 2021-04-24 76 | 77 | ### Added 78 | - Initial release 79 | 80 | [unreleased]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.2.0...HEAD 81 | [0.2.0]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.1.1...v0.2.0 82 | [0.1.1]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.1.0...v0.1.1 83 | [0.1.0]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.0.6...v0.1.0 84 | [0.0.6]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.0.5...v0.0.6 85 | [0.0.5]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.0.4...v0.0.5 86 | [0.0.4]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.0.3...v0.0.4 87 | [0.0.3]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.0.2...v0.0.3 88 | [0.0.2]: https://github.com/jmgilman/ChocolateyPackageCreator/compare/v0.0.1...v0.0.2 89 | [0.0.1]: https://github.com/jmgilman/ChocolateyPackageCreator/releases/tag/v0.0.1 -------------------------------------------------------------------------------- /docs/schema.md: -------------------------------------------------------------------------------- 1 | # Package File Schema 2 | 3 | Below is the schema for the various parts of the package file. Note that 4 | properties which are required and are not present in your final configuration 5 | file will result in the module failing the validation step. Any optional 6 | properties that are not defined in your configuration file will automatically 7 | have the default value from the schema applied to them. 8 | 9 | See the [schema directory](../ChocolateyPackageCreator/schema) for all of the schema files. 10 | 11 | 12 | ## [ChocolateyPackage](../ChocolateyPackageCreator/schema/ChocolateyPackage.psd1) 13 | | Name | Type | Required | Default Value | Description 14 | | --- | --- | --- | --- | --- | 15 | | Name | String | True | | The name of the package (used to identify it in logging) 16 | | ProcessScript | String | False | `''` | The relative path a script to use for processing package files 17 | | Shim | Boolean | False | False | Whether or not to shim exe files found in the package files 18 | | Installer | [PackageInstaller](#PackageInstaller) | False | `@{}` | Configuration data for automatically generated a `ChocolateyInstall.ps` file 19 | | LocalFiles | [LocalFile[]](#LocalFile) | False | `@()` | A list of local files to be copied to the package 20 | | RemoteFiles | [RemoteFile[]](#RemoteFile) | False | `@()` | A list of remote files to be downloaded to the package 21 | | Manifest | [PackageManifest](#PackageManifest) | True | | Configuration data for generating the package manifest file 22 | 23 | ## [ChocolateyISOPackage](../ChocolateyPackageCreator/schema/ChocolateyISOPackage.psd1) 24 | | Name | Type | Required | Default Value | Description 25 | | --- | --- | --- | --- | --- | 26 | | Name | String | True | | The name of the package (used to identify it in logging) 27 | | IsoFile | [RemoteFile](#RemoteFile) | True | | The remote file describing where the ISO file is to be downloaded from 28 | | Manifest | [PackageManifest](#PackageManifest) | True | | Configuration data for generating the package manifest file for the ISO file package 29 | | MetaPackage | [ChocolateyPackage](#ChocolateyPackage) | True | | The package object for the meta package which combines all other package files 30 | | Packages | [ChocolateyPackage[]](#ChocolateyPackage) | True | | A list of all sub-packages that will be compiled as part of the final package 31 | 32 | ## [PackageInstaller](../ChocolateyPackageCreator/schema/PackageInstaller.psd1) 33 | | Name | Type | Required | Default Value | Description 34 | | --- | --- | --- | --- | --- | 35 | | ScriptPath | String | True | | The relative path where the generated installer script will be placed 36 | | InstallerPath | String | True | | The relative path to the installer file (i.e. MSI file) 37 | | InstallerPath64 | String | False | `''` | The relative path to the 64-bit version of the installer file 38 | | InstallerType | String | True | | The installer file type (i.e. `msi` or `exe`) 39 | | ExitCodes | Integer[] | False | `@(0)` | An array of valid exit codes for the installer 40 | | Flags | String | False | `''` | A string of flags to pass to the installer 41 | | ArgumentPrefix | String | False | `''` | A prefix to prepend to every argument passed to the installer 42 | | Arguments | Hashtable | False | `@{}` | A hash table of arguments the end-user can supply which will be passed to the installer 43 | 44 | ## [LocalFile](../ChocolateyPackageCreator/schema/LocalFile.psd1) 45 | | Name | Type | Required | Default Value | Description 46 | | --- | --- | --- | --- | --- | 47 | | LocalPath | String | True | | The relative path (from the package configuration file) to a local file to include in the package 48 | | ImportPath | String | True | | The relative path (from the package root) where the file should be copied 49 | 50 | ## [RemoteFile](../ChocolateyPackageCreator/schema/RemoteFile.psd1) 51 | | Name | Type | Required | Default Value | Description 52 | | --- | --- | --- | --- | --- | 53 | | Url | String | True | | The URL the file will be downloaded from 54 | | Sha1 | String | False | `''` | The expected SHA1 hash of the remote file 55 | | ImportPath | String | True | | The relative path (from the package root) where the file should be downloaded to 56 | 57 | ## [PackageManifest](../ChocolateyPackageCreator/schema/PackageManifest.psd1) 58 | | Name | Type | Required | Default Value | Description 59 | | --- | --- | --- | --- | --- | 60 | | Metadata | [PackageMetadata](#PackageMetadata) | True | | Configuration data for generating the package metadata 61 | | Files | [PackageFile[]](#PackageFile) | False | `@()` | A list of relative package file or file paths to include in the final compiled package file 62 | 63 | ## [PackageMetadata](../ChocolateyPackageCreator/schema/PackageMetadata.psd1) 64 | | Name | Type | Required | Default Value | Description 65 | | --- | --- | --- | --- | --- | 66 | | Id | String | True | | The unique id of the package 67 | | Title | String | True | | The title of the package 68 | | Version | String | True | | The version of the package 69 | | Authors | String | True | | The original authors of the packaged software 70 | | Owners | String | True | | The maintainers of the package 71 | | Summary | String | True | | A brief summary of the packaged software 72 | | Description | String | True | | A longer description of the packaged software 73 | | ProjectUrl | String | True | | The URL to the project page of the packaged software 74 | | PackageSourceUrl | String | True | | The URL to the source code of the package 75 | | Tags | String | True | | A comma separated list of tags for identifying this package 76 | | Copyright | String | True | | The copyright statement for the packaged software 77 | | RequireLicenseAcceptance | String | True | | Whether the end-user is required to accept the software license before installing 78 | | Dependencies | [PackageDependency[]](#PackageDependency) | False | `@()` | A list of packages this package is dependent on 79 | 80 | ## [PackageFile](../ChocolateyPackageCreator/schema/PackageFile.psd1) 81 | | Name | Type | Required | Default Value | Description 82 | | --- | --- | --- | --- | --- | 83 | | Src | String | True | | A relative package file or file path to include in the final compiled package file 84 | | Target | String | True | | The relative package path where the source files will be placed in the final compiled package file 85 | 86 | ## [PackageDependency](../ChocolateyPackageCreator/schema/PackageDependency.psd1) 87 | | Name | Type | Required | Default Value | Description 88 | | --- | --- | --- | --- | --- | 89 | | Id | String | True | | The package ID of the dependent package 90 | | Version | String | False | `''` | The required version of the dependent package -------------------------------------------------------------------------------- /examples/sql-express-adv/files/config.eps: -------------------------------------------------------------------------------- 1 | ;SQL Server 2019 Configuration File 2 | [OPTIONS] 3 | 4 | ; By specifying this parameter and accepting Microsoft Python Open and Microsoft Python Server terms, you acknowledge that you have read and understood the terms of use. 5 | 6 | IACCEPTPYTHONLICENSETERMS="True" 7 | 8 | ; Specifies a Setup work flow, like INSTALL, UNINSTALL, or UPGRADE. This is a required parameter. 9 | 10 | ACTION="Install" 11 | 12 | ; Setup roles install SQL Server in a predetermined configuration. 13 | 14 | ROLE="<%= $ROLE %>" 15 | 16 | ; By specifying this parameter and accepting Microsoft R Open and Microsoft R Server terms, you acknowledge that you have read and understood the terms of use. 17 | 18 | IACCEPTROPENLICENSETERMS="True" 19 | 20 | ; Specifies that SQL Server Setup should not display the privacy statement when ran from the command line. 21 | 22 | SUPPRESSPRIVACYSTATEMENTNOTICE="True" 23 | 24 | ; Use the /ENU parameter to install the English version of SQL Server on your localized Windows operating system. 25 | 26 | ENU="<%= $ENU %>" 27 | 28 | ; Setup will not display any user interface. 29 | 30 | QUIET="True" 31 | 32 | ; Setup will display progress only, without any user interaction. 33 | 34 | QUIETSIMPLE="False" 35 | 36 | ; Parameter that controls the user interface behavior. Valid values are Normal for the full UI,AutoAdvance for a simplied UI, and EnableUIOnServerCore for bypassing Server Core setup GUI block. 37 | 38 | ; UIMODE="<%= $UIMODE %>" 39 | 40 | ; Specify whether SQL Server Setup should discover and include product updates. The valid values are True and False or 1 and 0. By default SQL Server Setup will include updates that are found. 41 | 42 | UpdateEnabled="<%= $UPDATEENABLED %>" 43 | 44 | ; If this parameter is provided, then this computer will use Microsoft Update to check for updates. 45 | 46 | USEMICROSOFTUPDATE="<%= $USEMICROSOFTUPDATE %>" 47 | 48 | ; Specifies that SQL Server Setup should not display the paid edition notice when ran from the command line. 49 | 50 | SUPPRESSPAIDEDITIONNOTICE="True" 51 | 52 | ; Specify the location where SQL Server Setup will obtain product updates. The valid values are "MU" to search Microsoft Update, a valid folder path, a relative path such as .\MyUpdates or a UNC share. By default SQL Server Setup will search Microsoft Update or a Windows Update service through the Window Server Update Services. 53 | 54 | UpdateSource="<%= $UPDATESOURCE %>" 55 | 56 | ; Specifies features to install, uninstall, or upgrade. The list of top-level features include SQL, AS, IS, MDS, and Tools. The SQL feature will install the Database Engine, Replication, Full-Text, and Data Quality Services (DQS) server. The Tools feature will install shared components. 57 | 58 | FEATURES=<%= $FEATURES %> 59 | 60 | ; Displays the command line parameters usage. 61 | 62 | HELP="False" 63 | 64 | ; Specifies that the detailed Setup log should be piped to the console. 65 | 66 | INDICATEPROGRESS="False" 67 | 68 | ; Specifies that Setup should install into WOW64. This command line argument is not supported on an IA64 or a 32-bit system. 69 | 70 | X86="<%= $X86 %>" 71 | 72 | ; Specify a default or named instance. MSSQLSERVER is the default instance for non-Express editions and SQLExpress for Express editions. This parameter is required when installing the SQL Server Database Engine (SQL), or Analysis Services (AS). 73 | 74 | INSTANCENAME="<%= $INSTANCENAME %>" 75 | 76 | ; Specify the root installation directory for shared components. This directory remains unchanged after shared components are already installed. 77 | 78 | INSTALLSHAREDDIR="<%= $INSTALLSHAREDIR %>" 79 | 80 | ; Specify the root installation directory for the WOW64 shared components. This directory remains unchanged after WOW64 shared components are already installed. 81 | 82 | INSTALLSHAREDWOWDIR="<%= $INSTALLSHAREDWOWDIR %>" 83 | 84 | ; Specify the Instance ID for the SQL Server features you have specified. SQL Server directory structure, registry structure, and service names will incorporate the instance ID of the SQL Server instance. 85 | 86 | INSTANCEID="<%= $INSTANCEID %>" 87 | 88 | ; Account for SQL Server CEIP service: Domain\User or system account. 89 | 90 | SQLTELSVCACCT="<%= $SQLTELSVCACCT %>" 91 | 92 | ; Startup type for the SQL Server CEIP service. 93 | 94 | SQLTELSVCSTARTUPTYPE="<%= $SQLTELSVCSTARTUPTYPE %>" 95 | 96 | ; Specify the installation directory. 97 | 98 | INSTANCEDIR="<%= $INSTANCEDIR %>" 99 | 100 | ; Agent account name 101 | 102 | AGTSVCACCOUNT="<%= $AGTSVCACCOUNT %>" 103 | 104 | ; Auto-start service after installation. 105 | 106 | AGTSVCSTARTUPTYPE="Disabled" 107 | 108 | ; CM brick TCP communication port 109 | 110 | COMMFABRICPORT="0" 111 | 112 | ; How matrix will use private networks 113 | 114 | COMMFABRICNETWORKLEVEL="0" 115 | 116 | ; How inter brick communication will be protected 117 | 118 | COMMFABRICENCRYPTION="0" 119 | 120 | ; TCP port used by the CM brick 121 | 122 | MATRIXCMBRICKCOMMPORT="0" 123 | 124 | ; Startup type for the SQL Server service. 125 | 126 | SQLSVCSTARTUPTYPE="Automatic" 127 | 128 | ; Level to enable FILESTREAM feature at (0, 1, 2 or 3). 129 | 130 | FILESTREAMLEVEL="0" 131 | 132 | ; The max degree of parallelism (MAXDOP) server configuration option. 133 | 134 | SQLMAXDOP="0" 135 | 136 | ; Set to "1" to enable RANU for SQL Server Express. 137 | 138 | ENABLERANU="True" 139 | 140 | ; Specifies a Windows collation or an SQL collation to use for the Database Engine. 141 | 142 | SQLCOLLATION="SQL_Latin1_General_CP1_CI_AS" 143 | 144 | ; Account for SQL Server service: Domain\User or system account. 145 | 146 | SQLSVCACCOUNT="<%= $SQLSVCACCOUNT %>" 147 | 148 | ; Set to "True" to enable instant file initialization for SQL Server service. If enabled, Setup will grant Perform Volume Maintenance Task privilege to the Database Engine Service SID. This may lead to information disclosure as it could allow deleted content to be accessed by an unauthorized principal. 149 | 150 | SQLSVCINSTANTFILEINIT="False" 151 | 152 | ; Windows account(s) to provision as SQL Server system administrators. 153 | 154 | SQLSYSADMINACCOUNTS="<%= $SQLSYSADMINACCOUNTS %>" 155 | 156 | ; The number of Database Engine TempDB files. 157 | 158 | SQLTEMPDBFILECOUNT="1" 159 | 160 | ; Specifies the initial size of a Database Engine TempDB data file in MB. 161 | 162 | SQLTEMPDBFILESIZE="8" 163 | 164 | ; Specifies the automatic growth increment of each Database Engine TempDB data file in MB. 165 | 166 | SQLTEMPDBFILEGROWTH="64" 167 | 168 | ; Specifies the initial size of the Database Engine TempDB log file in MB. 169 | 170 | SQLTEMPDBLOGFILESIZE="8" 171 | 172 | ; Specifies the automatic growth increment of the Database Engine TempDB log file in MB. 173 | 174 | SQLTEMPDBLOGFILEGROWTH="64" 175 | 176 | ; Provision current user as a Database Engine system administrator for SQL Server 2019 Express. 177 | 178 | ADDCURRENTUSERASSQLADMIN="<%= $ADDCURRENTUSERASSQLADMIN %>" 179 | 180 | ; Specify 0 to disable or 1 to enable the TCP/IP protocol. 181 | 182 | TCPENABLED="<%= $TCPENABLED %>" 183 | 184 | ; Specify 0 to disable or 1 to enable the Named Pipes protocol. 185 | 186 | NPENABLED="<%= $NPENABLED %>" 187 | 188 | ; Startup type for Browser Service. 189 | 190 | BROWSERSVCSTARTUPTYPE="Automatic" 191 | 192 | ; User account for Launchpad Service. 193 | 194 | EXTSVCACCOUNT="<%= $EXTSVCACCOUNT %>" 195 | 196 | ; User account for Full-text Filter Daemon Host. 197 | 198 | FTSVCACCOUNT="<%= $FTSVCACCOUNT %>" 199 | 200 | ; Use SQLMAXMEMORY to minimize the risk of the OS experiencing detrimental memory pressure. 201 | 202 | SQLMAXMEMORY="2147483647" 203 | 204 | ; Use SQLMINMEMORY to reserve a minimum amount of memory available to the SQL Server Memory Manager. 205 | 206 | SQLMINMEMORY="0" 207 | 208 | ; Accept the SQL Server License Terms 209 | 210 | IACCEPTSQLSERVERLICENSETERMS="True" -------------------------------------------------------------------------------- /ChocolateyPackageCreator/functions/package.ps1: -------------------------------------------------------------------------------- 1 | $TYPES = @( 2 | 'PackageManifest', 3 | 'PackageMetadata', 4 | 'PackageDependency', 5 | 'PackageFile', 6 | 'LocalFile', 7 | 'RemoteFile', 8 | 'PackageInstaller' 9 | ) 10 | 11 | <# 12 | .SYNOPSIS 13 | Returns a ChocolateyISOPackage object using the given packages 14 | .DESCRIPTION 15 | Returns a ChocolateyISOPackage object using the given packages. Each package 16 | is validated before it is created. 17 | .PARAMETER PackagePath 18 | The full file path to where the ISO package files are located 19 | .PARAMETER PackageConfig 20 | The package configuration data to use when creating the ChocolateyISOPackage 21 | .PARAMETER MetaPackage 22 | The meta package which ties the ISO and all sub-packages together 23 | .PARAMETER Packages 24 | A list of packages which are subordinate and require use of the ISO file 25 | contents 26 | .EXAMPLE 27 | $package = New-ChocolateyISOPackage ` 28 | -PackagePath 'C:\my\package' ` 29 | -PackageConfig $myConfig ` 30 | -MetaPackage $MetaPackae ` 31 | -Packages @($Package1, $Package2, $Package3) 32 | .OUTPUTS 33 | A new instance of the ChocolateyISOPackage object 34 | #> 35 | Function New-ChocolateyISOPackage { 36 | param( 37 | [string] $PackagePath, 38 | [hashtable] $PackageConfig, 39 | [ChocolateyPackage] $MetaPackage, 40 | [ChocolateyPackage[]] $Packages 41 | ) 42 | 43 | # Clone config to prevent modifying passed in hash table 44 | $config = $PackageConfig.Clone() 45 | 46 | # Add package path, meta package, and packages 47 | $config.Add('path', $PackagePath) 48 | $config.Add('metapackage', $MetaPackage) 49 | $config.Add('packages', $Packages) 50 | 51 | # Convert configuration to object 52 | $packageSchema = Get-Schema 'ChocolateyISOPackage' 53 | Invoke-Schema $packageSchema $config 'ChocolateyISOPackage' $TYPES 54 | } 55 | 56 | <# 57 | .SYNOPSIS 58 | Returns a ChocolateyPackage object using the given configuration 59 | .DESCRIPTION 60 | Validates the given package configuration data and then creates a new 61 | ChocolateyPackage object from the configuration data. 62 | .PARAMETER PackagePath 63 | The full file path to where the package files are located 64 | .PARAMETER PackageConfig 65 | The package configuration data to use when creating the ChocolateyPackage 66 | object 67 | .EXAMPLE 68 | $package = New-ChocolateyPackage ` 69 | -PackagePath 'C:\my\package' ` 70 | -PackageConfig $myConfig 71 | .OUTPUTS 72 | A new instance of the ChocolateyPackage object 73 | #> 74 | Function New-ChocolateyPackage { 75 | param( 76 | [string] $PackagePath, 77 | [hashtable] $PackageConfig 78 | ) 79 | 80 | # Clone config to prevent modifying passed in hash table 81 | $config = $PackageConfig.Clone() 82 | 83 | # Add package path and fully qualify local file paths 84 | $config.Add('path', $PackagePath) 85 | foreach ($localFile in $config.localFiles) { 86 | $localFile.localPath = Join-Path $config.Path $localFile.localPath 87 | } 88 | if ($config.processScript) { 89 | $config.processScript = Join-Path $config.Path $config.processScript 90 | } 91 | 92 | # Convert configuration to object 93 | $packageSchema = Get-Schema 'ChocolateyPackage' 94 | Invoke-Schema $packageSchema $config 'ChocolateyPackage' $TYPES 95 | } 96 | 97 | <# 98 | .SYNOPSIS 99 | Creates an example package configuration structure at the given path 100 | .DESCRIPTION 101 | Creates an example package configuration file along with an example process 102 | and Chocolatey install file at the given path. This is the easiest way to 103 | get started with making a new package. 104 | .PARAMETER OutPath 105 | The full file path to where the package files will be created 106 | .EXAMPLE 107 | New-ChocolateyPackageConfig C:\my\package 108 | .OUTPUTS 109 | None 110 | #> 111 | Function New-ChocolateyPackageConfig { 112 | param( 113 | [string] $OutPath 114 | ) 115 | 116 | if (!(Test-Path $OutPath)) { 117 | Write-Verbose ('Creating {0}...' -f $OutPath) 118 | New-Item -ItemType Directory $OutPath | Out-Null 119 | } 120 | 121 | $packageFile = Join-Path $PSScriptRoot '..\static\package.psd1' 122 | Write-Verbose ('Copying package file from {0} to {1}...' -f $packageFile, $OutPath) 123 | Copy-Item $packageFile $OutPath | Out-Null 124 | } 125 | 126 | <# 127 | .SYNOPSIS 128 | Loads the schema file for the given custom object type 129 | .DESCRIPTION 130 | Searches in the module schema directory ($MODULEROOT\schema) for a schema 131 | file for the given custom object type. It assumes a .PSD1 file with the name 132 | of the object type will exist in the schema directory and will automatically 133 | import the contents and return them. 134 | .PARAMETER Name 135 | The name of the custom object to load the schema for 136 | .EXAMPLE 137 | $schema = Get-Schema ChocolateyPackage 138 | .OUTPUTS 139 | A hashtable containing the imported contents of the schema file 140 | #> 141 | Function Get-Schema { 142 | param( 143 | [string] $Name 144 | ) 145 | 146 | $schemaFile = Join-Path $PSScriptRoot ('..\schema\{0}.psd1' -f $Name) 147 | if (!(Test-Path $schemaFile)) { 148 | throw ('Could not find schema file for {0} at {1}' -f $Name, $schemaFile) 149 | } 150 | 151 | Import-PowerShellDataFile $schemaFile 152 | } 153 | 154 | <# 155 | .SYNOPSIS 156 | Applies the given schema against the given input object 157 | .DESCRIPTION 158 | The given input object is first validated against the schema and then any 159 | custom types are converted from their hashtable values to their respective 160 | object type. Optional properties that are not present in the input object 161 | have the default value contained in the schema applied to them. Only the 162 | custom types contained in the $CustomTypes parameter are automaticaly 163 | converted, the remaining types are left as is after validation. This 164 | function is recursive and will operate down the tree of an object performing 165 | validation and conversion on all applicable properties. 166 | .PARAMETER Name 167 | The schema to apply to the input object 168 | .PARAMETER InputObject 169 | The object to validate and transform 170 | .PARAMETER InputObjectType 171 | The type of the input object (used for conversion) 172 | .PARAMETER CustomTypes 173 | A list of types to validate and transform. Each type in the list must have 174 | a schema file located in the schema directory. 175 | .EXAMPLE 176 | $transformedObject = Invoke-Schema $mySchema $object 'MyObjectType' @('CustomObjectType') 177 | .OUTPUTS 178 | The validated and transformed input object 179 | #> 180 | Function Invoke-Schema { 181 | param( 182 | [hashtable] $Schema, 183 | [hashtable] $InputObject, 184 | [string] $InputObjectType, 185 | [string[]] $CustomTypes 186 | ) 187 | 188 | $InputObject = $InputObject.Clone() 189 | 190 | foreach ($property in $InputObject.GetEnumerator()) { 191 | if (!($property.Name -in $Schema.Keys)) { 192 | throw ('Error validating configuration: {0} does not have a {1} property' -f $InputObjectType, $property.Name) 193 | } 194 | } 195 | 196 | foreach ($property in $Schema.GetEnumerator()) { 197 | if (($property.Value.required) -and (!($property.Name -in $InputObject.Keys))) { 198 | throw ('Error validating configuration: {0} must have a {1} property' -f $InputObjectType, $property.Name) 199 | } 200 | 201 | if (!($property.Value.Required) -and (!($property.Name -in $InputObject.Keys))) { 202 | $InputObject.Add($property.Name, $property.Value.default) 203 | } 204 | 205 | if ($property.Value.type -match '\[\]') { 206 | $inputType = $InputObject[$property.Name].GetType() 207 | if (!(($inputType.Name -eq 'ArrayList') -or ($inputType.BaseType.Name -eq 'Array'))) { 208 | throw ('Error validating configuration: {0} property of {1} must be an array' -f $property.Name, $InputObjectType) 209 | } 210 | 211 | $type = $property.Value.type -replace '\[\]', '' 212 | if ($type -in $CustomTypes) { 213 | foreach ($subObject in $InputObject[$property.Name]) { 214 | $InputObject[$property.Name] = $InputObject[$property.Name].Clone() 215 | $index = $InputObject[$property.Name].IndexOf($subObject) 216 | 217 | $propertySchema = Get-Schema $type 218 | $InputObject[$property.Name][$index] = Invoke-Schema $propertySchema $subObject $type $CustomTypes 219 | } 220 | } 221 | } 222 | else { 223 | if ($property.Value.type -in $CustomTypes) { 224 | if (($property.Value.required) -and ($InputObject[$property.Name].Count -eq 0)) { 225 | throw ('Error validating configuration: {0} property of {1} cannot be empty' -f $property.Name, $InputObjectType) 226 | } 227 | 228 | if ($InputObject[$property.Name].Count -gt 0) { 229 | $propertySchema = Get-Schema $property.Value.type 230 | $InputObject[$property.Name] = Invoke-Schema $propertySchema $InputObject[$property.Name] $property.Value.type $CustomTypes 231 | } 232 | } 233 | } 234 | } 235 | 236 | if ($InputObject.GetType() -ne $InputObjectType) { 237 | New-Object $InputObjectType -Property $InputObject 238 | } 239 | else { 240 | $InputObject 241 | } 242 | } -------------------------------------------------------------------------------- /docs/getting_started.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The ChocolateyPackageCreator Powershell module is a tool which can be used to 4 | simplify the process of creating internal Chocolatey packages, especially when 5 | easy automation is desired. It has been built to provide support for the most 6 | basic package types, like shimming a single executable, to complex package types, 7 | like installing multiple packages off a single ISO image. The purpose of this 8 | guide is to provide enough of an introduction to the methodology underlying 9 | the module to get you up to speed on creating your first few packages. 10 | 11 | # The Basics 12 | 13 | The easiest way to come up to speed on using this module is by example. We will 14 | start with a very basic example which packages the 7zip CLI tool and then move 15 | onto a more complex example. 16 | 17 | ## Package Configuration File 18 | 19 | ```powershell 20 | @{ 21 | name = '7zip' 22 | processScript = '' 23 | shim = $True 24 | installer = @{} 25 | localFiles = @() 26 | remoteFiles = @( 27 | @{ 28 | url = 'https://www.7-zip.org/a/7z1900-x64.exe' 29 | sha1 = '9FA11A63B43F83980E0B48DC9BA2CB59D545A4E8' 30 | importPath = 'tools/7z.exe' 31 | } 32 | ) 33 | manifest = @{ 34 | metadata = @{ 35 | id = '7zip' 36 | title = '7Zip File Archiver' 37 | version = '19.00' 38 | authors = 'Igor Pavlov' 39 | owners = 'Joshua Gilman' 40 | summary = 'Installs 7Zip CLI tool' 41 | description = '7-Zip is a file archiver with a high compression ratio.' 42 | projectUrl = 'https://www.7-zip.org/' 43 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 44 | tags = '7zip file archive' 45 | copyright = '2021 Igor Pavlov' 46 | licenseUrl = 'http://www.7-zip.org/license.txt' 47 | requireLicenseAcceptance = 'false' 48 | dependencies = @() 49 | } 50 | files = @( 51 | @{ 52 | src = 'tools\**' 53 | target = 'tools' 54 | } 55 | ) 56 | } 57 | } 58 | ``` 59 | 60 | This can be intimidating at first, but most of it becomes easy to digest once 61 | the general architecture is understood: 62 | 63 | * **Name:** A unique name used to identify the package in logs 64 | * **processScript:** A optional path to a Powershell file that will be executed 65 | prior to the package being built. We will cover this more in-depth in another 66 | example. 67 | * **Shim:** Whether or not executables in this package should be [shimmed](https://docs.chocolatey.org/en-us/features/shim). In other words, whether any found executables should be made 68 | available in the system PATH. Setting this to false will automatically generate 69 | .ignore files to prevent Chocolatey from shimming which is its default behavior. 70 | * **Installer:** Whether or not to generate a `ChocolateyInstall.ps1` file for 71 | installing this package. This is optional and is provided for convenience and 72 | we will cover it more in-depth in another example. 73 | * **LocalFiles:** Which local files, if any, to copy to the package before 74 | building. The `localPath` to the files are relative to the `PackagePath` parameter 75 | which is defined when creating a new package with `New-ChocolateyPackage`. The 76 | `importPath` is relative to the root of the package directory. 77 | * **RemoteFiles:** Similar to the local files except the source is a remote URL 78 | from which to download the file. Additionally, an optional hash can be provided 79 | in order to validate the downloaded file before building. 80 | * **Manifest:** This property is simply a wrapper around the [Chocolatey NuSpec](https://docs.chocolatey.org/en-us/create/create-packages#nuspec) 81 | file which is required in all packages. When a package is created the NuSpec 82 | file is automatically generated from this property and imported into the package. 83 | 84 | To see all of the schema information for a package file refer to the 85 | [schema documentation](schema.md). 86 | 87 | ## Building a Package 88 | 89 | Now that we understand the basics of package file format, how would we actually 90 | use the above example? First, we would create the `ChocolateyPackage` object: 91 | 92 | ```powershell 93 | $packageConfigPath = 'C:\packages\7zip\package.psd1' 94 | $packageConfig = Import-PowerShellDataFile $packageConfigPath 95 | $package = New-ChocolateyPackage (Split-Path -Parent $packageConfigPath) $package 96 | ``` 97 | 98 | In the above example we assume the path to the package file we created earlier 99 | is `C:\packages\7zip\package.psd1` and so we pass that file to 100 | `Import-PowerShellDataFile` which returns an object containing the configuration 101 | data within the file. We then call `New-ChocolateyPackage` with two parameters, 102 | the path to the package root and the contents of the package configuration file. 103 | Recall that the module uses the package path to find the subsidiary files 104 | associated with a package - like `LocalFiles` or a `ProcessScript`. This 105 | function will take the raw configuration data and turn it into a 106 | `ChocolateyPackage` object which we can further use in other functions. 107 | 108 | The next step is to actually build the package and produce a package file: 109 | 110 | ```powershell 111 | $packagePath = Build-ChocolateyPackage -Package $package -OutPath 'C:\packages\bin' 112 | ``` 113 | 114 | The above function has many more parameters that can be utilized, but only the 115 | two used here are required. The `Package` parameter is the `ChocolateyPackage` 116 | object we created earlier and the `OutPath` parameter is the location where we 117 | would like the package file created at. The function returns the fully qualified 118 | path to the package, which in this case would be `C:\packages\bin\7zip.19.00.nupkg`. 119 | 120 | ## Publishing a Package 121 | 122 | With the package created, all that's left is to upload it to our local NuGet 123 | repository for consumption by Chocolatey: 124 | 125 | ```powershell 126 | Publish-ChocolateyPackage ` 127 | -Repository 'http://my.nuget.com/nuget' ` 128 | -ApiKey 'myapikey' ` 129 | -PackageFile $packagePath 130 | ``` 131 | 132 | Again, there are a few additional parameters available, but only the three used 133 | here are required. The `Repository` is the URL path to the desired NuGet 134 | repository, the `ApiKey` is an API key with sufficient privileges to publish 135 | the package, and the `PackageFile` is the path to the package file to publish. 136 | 137 | ## Understanding the Output 138 | 139 | Let's expand the contents of the `7zip.19.00.nupkg` file generated above: 140 | 141 | ``` 142 | /_rels/.rels 143 | /package/services/metadata/core-properties/.psmdcp 144 | /tools/7z.exe 145 | /[Content Types].xml 146 | /7zip.nuspec 147 | ``` 148 | 149 | Most of these files are automatically generated by Chocolatey and are required 150 | for NuGet packages, but two of them were created by the build process: the 151 | `7z.exe` file was automatically downloded from the URL provided in our 152 | `RemoteFiles` property and imported into the `tools` directory as specified by 153 | the `ImportPath`. Since `Shim` was set to true, Chocolatey will automatically 154 | make this file available via with system PATH environment variable. The 155 | `7zip.nuspec` file was automatically generated using the manifest data provided 156 | in the package configuration. You can open it up and see that it matches: 157 | 158 | ```xml 159 | 160 | 161 | 162 | 7zip 163 | 19.00 164 | 7Zip File Archiver 165 | Igor Pavlov 166 | Joshua Gilman 167 | http://www.7-zip.org/license.txt 168 | https://www.7-zip.org/ 169 | false 170 | 7-Zip is a file archiver with a high compression ratio. 171 | Installs 7Zip CLI tool 172 | 2021 Igor Pavlov 173 | 7zip file archive 174 | https://github.com/jmgilman/ChocolateyPackageManager 175 | 176 | 177 | ``` 178 | 179 | # Advanced Example 180 | 181 | Let's make another package but this time use a few additional features of the 182 | module. This time we'll create a package that installs Chrome Enterprise. Here 183 | is the package configuration: 184 | 185 | ```powershell 186 | @{ 187 | name = 'chrome-enterprise' 188 | processScript = 'process.ps1' 189 | shim = $True 190 | installer = @{ 191 | scriptPath = 'tools' 192 | installerPath = 'tools/GoogleChromeStandaloneEnterprise64.msi' 193 | installerPath64 = '' 194 | installerType = 'msi' 195 | exitCodes = @(0) 196 | flags = '/qn' 197 | arguments = @{} 198 | } 199 | localFiles = @() 200 | remoteFiles = @( 201 | @{ 202 | url = 'https://dl.google.com/tag/s/appguid%3D%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26iid%3D%7B28B3FC2A-8F28-9145-D051-455305F69948%7D%26lang%3Den%26browser%3D4%26usagestats%3D0%26appname%3DGoogle%2520Chrome%26needsadmin%3Dtrue%26ap%3Dx64-stable-statsdef_0%26brand%3DGCEB/dl/chrome/install/GoogleChromeEnterpriseBundle64.zip' 203 | sha1 = '191A76F3084CD293FB8B56AEF9952236930BFE7D' 204 | importPath = 'tools/chrome.zip' 205 | } 206 | ) 207 | manifest = @{ 208 | metadata = @{ 209 | id = 'chrome-enterprise' 210 | title = 'Google Chrome' 211 | version = '90.0.4430.85' 212 | authors = 'Google' 213 | owners = 'Joshua Gilman' 214 | summary = 'Installs Google Chrome' 215 | description = "Get more done with the new Google Chrome. A more simple, secure, and faster web browser than ever, with Google's smarts built-in." 216 | projectUrl = 'https://www.google.com/chrome/' 217 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 218 | tags = 'Google Chrome Browser Web' 219 | copyright = '2021 Google' 220 | licenseUrl = 'https://chromeenterprise.google/terms/chrome-service-license-agreement/' 221 | requireLicenseAcceptance = 'false' 222 | dependencies = @() 223 | } 224 | files = @( 225 | @{ 226 | src = 'tools\**' 227 | target = 'tools' 228 | } 229 | ) 230 | } 231 | } 232 | ``` 233 | 234 | Most of this should be easy to understand at this point - we've only added two 235 | new things: an installation script and a process script. 236 | 237 | ## The Installation Script 238 | 239 | By defining the `Installer` property, the module will automatically generate a 240 | `ChocolateyInstall.ps1` file at build time. It has the following attributes: 241 | 242 | * **ScriptPath:** The path, relative from the package root, where the 243 | installation script will be created. It's best practice to include the script 244 | in the same directory as the rest of your files, however, Chocolatey looks for 245 | the script anywhere in the package and so it's technically not required to be in 246 | one place. 247 | * **InstallerPath:** The path, relative from the package root, where the package 248 | installer file is located. This is the file that is passed to Chocolatey and is 249 | usually an MSI or EXE file that installs the program. 250 | * **InstallerPath64:** An optional 64-bit version of the package installer file. 251 | This is typically only used when a program offers both a 32-bit and 64-bit 252 | version. By specifying the 32-bit installer in `InstallerPath` and the 64-bit 253 | installer in `InstallerPath64`, Chocolatey will automatically install the 254 | correct one based on the host's architecture at install time. 255 | * **InstallerType:** The type of installer. Usually either `msi` or `exe`. 256 | * **ExitCodes:** An array of valid exit codes that the installer can exit with. 257 | Any exit code not in this array is considered a failure. 258 | * **Flags:** A list of flags to pass to the installer. This is usually used to 259 | pass the parameters that perform a silent installation of the program. 260 | * **Arguments:** A dictionary of valid arguments that the installer can take. 261 | Most installers have a range of arguments that instruct it on how to install to 262 | the local system and the installation script will automatically convert these 263 | into the final string of arguments sent to the installer. It's important that 264 | **all** valid arguments be specified here as the installation script also allows 265 | the end-user to specify values for these arguments via parameters passed to 266 | Chocolatey during the install. 267 | 268 | The above configuration file produces the following `ChocolateyInstall.ps` 269 | script: 270 | 271 | ``` 272 | $packageName = 'chrome-enterprise' 273 | $filePath = 'GoogleChromeStandaloneEnterprise64.msi' 274 | $filePath64 = '' 275 | $fileType = 'msi' 276 | $flags = '/qn' 277 | $exitCodes = @(0) 278 | $logLocation = '{0}\{1}.{2}.log' -f $env:TEMP,$env:ChocolateyPackageName,$env:ChocolateyPackageVersion 279 | 280 | $arguments = @{} 281 | 282 | $params = Get-PackageParameters 283 | 284 | # Build arguments 285 | if (($params.Count -gt 0) -and ($arguments.Count -eq 0)) { 286 | Write-Warning 'Parameters were given but this package does not take any parameters' 287 | } elseif (($params.Count -gt 0) -and ($arguments.Count -gt 0)) { 288 | foreach($param in $params.GetEnumerator()) { 289 | if (!($param.Name -in $arguments.Keys)) { 290 | Write-Warning ('This package does not have a {0} parameter' -f $param.Name) 291 | continue 292 | } 293 | 294 | $arguments[$param.Name] = $param.Value 295 | } 296 | } 297 | 298 | # Build argument string 299 | $silentArgs = $flags 300 | $silentArgs += ' /l*v "{0}"' -f $logLocation 301 | foreach($argument in $arguments.GetEnumerator()) { 302 | if ($argument.Value) { 303 | if ($fileType -eq 'exe') { 304 | $argString = ' /{0}="{1}"' -f $argument.Name, $argument.Value 305 | } else { 306 | $argString = ' {0}="{1}"' -f $argument.Name, $argument.Value 307 | } 308 | $silentArgs += $argString 309 | } 310 | } 311 | 312 | $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition 313 | $packageDir = Split-Path -Parent $scriptDir 314 | 315 | $fileLocation = Join-Path $packageDir $filePath 316 | $fileLocation = (Get-Item $fileLocation).FullName # Resolve relative paths 317 | 318 | if ($filePath64) { 319 | $fileLocation64 = Join-Path $packageDir $filePath64 320 | $fileLocation64 = (Get-Item $fileLocation64).FullName 321 | } 322 | 323 | Write-Host ('Log location is {0}' -f $logLocation) 324 | if ($filePath64) { 325 | Install-ChocolateyInstallPackage ` 326 | -PackageName $packageName ` 327 | -FileType $fileType ` 328 | -File $fileLocation ` 329 | -File64 $fileLocation64 ` 330 | -SilentArgs $silentArgs.Trim() ` 331 | -ValidExitCodes $exitCodes 332 | } else { 333 | Install-ChocolateyInstallPackage ` 334 | -PackageName $packageName ` 335 | -FileType $fileType ` 336 | -File $fileLocation ` 337 | -SilentArgs $silentArgs.Trim() ` 338 | -ValidExitCodes $exitCodes 339 | } 340 | ``` 341 | 342 | As you can see, the installation script does a number of things by default. Of 343 | note is that, as already mentioned, it builds the final argument string passed 344 | to the installer by combining the arguments specified in the package 345 | configuration and any parameters supplied by the end-user. Other than that, the 346 | rest is a pretty typicaly install script, for more information on this file, see 347 | the [Chocolatey documentation](https://docs.chocolatey.org/en-us/chocolatey-install-ps1). 348 | 349 | ## The Process Script 350 | 351 | A process script can be supplied which will be run during the build after all 352 | files have been copied to the package directory but before the package is 353 | actually built. This is useful for performing additional operations on package 354 | files, like extracting the contents of a zip archive in our case: 355 | 356 | ```powershell 357 | param($BuildPath, $Package) 358 | 359 | $toolsDir = Join-Path $BuildPath 'tools' 360 | $chromeDir = Join-Path $toolsDir 'chrome' 361 | $zipFile = Join-Path $BuildPath $Package.RemoteFiles[0].ImportPath 362 | 363 | New-Item -ItemType Directory $chromeDir 364 | Expand-Archive $zipFile $chromeDir 365 | 366 | Copy-Item (Join-Path $chromeDir 'installers/GoogleChromeStandaloneEnterprise64.msi') $toolsDir 367 | Remove-Item $chromeDir -Recurse -Force 368 | Remove-Item $zipFile 369 | ``` 370 | 371 | A process script takes two parameters: 372 | 373 | * **BuildPath:** The full path to the root of the package folder 374 | * **Package:** A copy of the `ChocolateyPackage` object for the current package 375 | 376 | In the above example, we extract the zip archive previously downloaded by the 377 | module for us and then copy the Chrome installer to the `tools` directory. Note 378 | that the name of this file is the same one we specified in the `Installer` 379 | property as this is the file that the installation script will call to actually 380 | perform the install of Chrome. After grabbing the installer we delete the rest 381 | of the contents of the zip archive (including the archive itself) to minimize 382 | the size of our package. 383 | 384 | # Conclusion 385 | 386 | The above two examples cover a majority of the features offered by this module. 387 | Additional parameters offered by the various functions can be found using the 388 | normal Powershell documentation methods (i.e. `Get-Help`). To easily get started 389 | with creating your first package, use the built-in generator: 390 | 391 | ```powershell 392 | New-ChocolateyPackageConfig 'C:\packages\mypackage' 393 | ``` -------------------------------------------------------------------------------- /docs/iso.md: -------------------------------------------------------------------------------- 1 | # Creating an ISO Package 2 | 3 | In this example we will run through creating an ISO package for the popular 4 | disaster recovery software, Veeam Backup & Replication. An ISO package is 5 | nothing more than a combination of Chocolatey packages that, together, install 6 | complex software often distributed in an ISO file. In the case of Veeam, the 7 | installation process spans 11 MSI installers, not including dependencies. To 8 | ease the package creation process, the ISO package format was created. 9 | 10 | # Structure 11 | 12 | The build process for ISO packages imposes a structure on how the directory 13 | containing your package configurations is laid out. It looks like this: 14 | 15 | ``` 16 | /iso.psd1 17 | /packagename.psd1 18 | /packages 19 | /packages/subpackage1.psd1 20 | /packages/subpackage2.psd1 21 | ``` 22 | 23 | The first file, `iso.psd1`, is the ISO package file that is responsible for 24 | downloading the ISO image to the local machine. Since ISO files tend to be very 25 | large, and NuGet repositories tend to struggle with large files, the ISO package 26 | format does not package the ISO file into itself. Instead, it creates an 27 | installation script which downloads the ISO to the end-user's local hard drive. 28 | This file is responsible for pointing to the source where the ISO can be 29 | downloaded from. In on-premise environments with no internet connectivity, it's 30 | recommended you host the ISO file on an internal machine and point the 31 | installation file to that. 32 | 33 | The second file, `packagename.psd1`, is the meta package that ties all the other 34 | packages together. This package will not have any files associated with it and 35 | will instead have all other packages as depdendencies. The end result is that 36 | when a user runs `choco install packagename` the entirety of the software will 37 | be installed on the users computer. Note that care should be taken in ordering 38 | the dependencies correctly to ensure a successful installation of the software. 39 | 40 | The remaining files exist under the `packages` subdirectory and are simply 41 | normal package configuration files with one unique exception which will be 42 | covered later. There should be one file per MSI/EXE installer in the ISO image. 43 | 44 | 45 | ## The ISO package 46 | 47 | As noted above, the ISO package points to the source of the ISO file and is 48 | responsible for downloading it to the end-user's hard drive. The configuration 49 | for Veeam looks like this: 50 | 51 | ```powershell 52 | @{ 53 | name = 'veeam-iso' 54 | isoFile = @{ 55 | url = 'https://download2.veeam.com/VBR/v11/VeeamBackup&Replication_11.0.0.837_20210220.iso' 56 | sha1 = 'D6E9F7DB3BA1A4782028773562AA036365724AE4' 57 | importPath = 'veeam.iso' 58 | } 59 | manifest = @{ 60 | metadata = @{ 61 | id = 'veeam-iso' 62 | title = 'Veeam Backup & Replication ISO' 63 | version = '11.0.0.837' 64 | authors = 'Veeam' 65 | owners = 'Joshua Gilman' 66 | summary = 'Installs the contents of the Veeam Backup & Replication ISO' 67 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 68 | projectUrl = 'http://www.veeam.com/' 69 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 70 | tags = 'veeam backup replication iso' 71 | copyright = '2021 Veeam' 72 | licenseUrl = 'https://www.veeam.com/eula.html' 73 | requireLicenseAcceptance = 'false' 74 | dependencies = @() 75 | } 76 | files = @( 77 | @{ 78 | src = 'tools\**' 79 | target = 'tools' 80 | } 81 | ) 82 | } 83 | } 84 | ``` 85 | 86 | The format should look familiar, the only deviation from the normal package 87 | configuration is the existence of the `isoFile` property and the lack of most 88 | of the other properties. The `isoFile` property follows the same format as the 89 | `remoteFiles` section of a normal configuration and should point to the location 90 | where the required ISO file can be downloaded. Underneath the hood, this package 91 | has a custom installation script which downloads and unpacks the ISO: 92 | 93 | ```powershell 94 | Function Expand-DiskImage { 95 | param( 96 | [string] $Path, 97 | [string] $Destination 98 | ) 99 | 100 | Write-Host ('Mounting image at {0}...' -f $Path) 101 | Mount-DiskImage -ImagePath $Path 102 | $img = Get-DiskImage -ImagePath $Path 103 | $driveLetter = $img | Get-Volume | Select-Object -ExpandProperty DriveLetter 104 | $drivePath = Get-PSDrive -Name $driveLetter | Select-Object -ExpandProperty Root 105 | 106 | Write-Host ('Copying ISO files from {0} to {1}' -f $drivePath, $Destination) 107 | Copy-Item (Join-Path $drivePath '*') $Destination -Recurse | Out-Null 108 | 109 | Write-Host 'Unmounting image...' 110 | Dismount-DiskImage -ImagePath $Path | Out-Null 111 | } 112 | 113 | Function Invoke-Unshim { 114 | param($BuildPath) 115 | 116 | $exeFiles = Get-ChildItem $BuildPath -Filter '*.exe' -Recurse 117 | foreach ($file in $exeFiles) { 118 | $ignoreFile = $file.FullName + '.ignore' 119 | 120 | Write-Host('Preventing shim of {0} with {1}...' -f $file.FullName, $ignoreFile) 121 | Set-Content $ignoreFile '' 122 | } 123 | } 124 | 125 | $packageName = 'veeam-iso' 126 | $filePath = 'veeam.iso' 127 | $url = 'https://download2.veeam.com/VBR/v11/VeeamBackup&Replication_11.0.0.837_20210220.iso' 128 | $hash = 'D6E9F7DB3BA1A4782028773562AA036365724AE4' 129 | 130 | $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition 131 | $packageDir = Split-Path -parent $scriptDir 132 | $fileFullPath = Join-Path $packageDir $filePath 133 | 134 | Write-Host 'Downloading ISO file...' 135 | Get-ChocolateyWebFile ` 136 | -PackageName $env:ChocolateyPackageName ` 137 | -FileFullpath $fileFullPath ` 138 | -Url $url ` 139 | -Checksum $hash ` 140 | -ChecksumType sha1 141 | 142 | Write-Host 'Extracting ISO contents...' 143 | Expand-DiskImage $fileFullPath $packageDir 144 | 145 | Write-Host 'Removing ISO file...' 146 | Remove-Item $fileFullPath -Force 147 | 148 | Write-Host 'Preventing shimming of exe files...' 149 | Invoke-Unshim $packageDir 150 | ``` 151 | 152 | This script does the following: 153 | 154 | * Calls `Get-ChocolateyWebFile` to download the ISO file to the local system 155 | * Calls `Expand-DiskImage` to mount the ISO image, copy the contents to the 156 | local package directory, and then unmounts the image 157 | * Deletes the ISO image 158 | * Prevents the shimming of any EXE's found in the image contents 159 | 160 | The result is a local copy of the ISO contents at the following path: 161 | `C:\ProgramData\chocolatey\lib\veeam-iso`. This is the most important detail to 162 | understand about the ISO package format as the existence of the ISO on the local 163 | system is what enables the sub-packages to work correctly. All sub-packages will 164 | have a hard dependency on this ISO package to ensure that the contents have been 165 | downloaded already. 166 | 167 | ## The Meta Package 168 | 169 | The meta package is in the normal package format and only contains dependencies 170 | on the rest of the packages belonging to the ISO: 171 | 172 | ```powershell 173 | @{ 174 | name = 'veeam' 175 | processScript = '' 176 | shim = $False 177 | installer = @{} 178 | localFiles = @() 179 | remoteFiles = @() 180 | manifest = @{ 181 | metadata = @{ 182 | id = 'veeam' 183 | title = 'Veeam Backup & Replication' 184 | version = '11.0.0.837' 185 | authors = 'Veeam' 186 | owners = 'Joshua Gilman' 187 | summary = 'Installs Veeam Backup & Replication' 188 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 189 | projectUrl = 'http://www.veeam.com/' 190 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 191 | tags = 'veeam backup replication' 192 | copyright = '2021 Veeam' 193 | licenseUrl = 'https://www.veeam.com/eula.html' 194 | requireLicenseAcceptance = 'false' 195 | dependencies = @( 196 | @{ 197 | id = 'veeam-catalog' 198 | version = '[11.0.0.837]' 199 | }, 200 | @{ 201 | id = 'veeam-server' 202 | version = '[11.0.0.837]' 203 | }, 204 | @{ 205 | id = 'veeam-console' 206 | version = '[11.0.0.837]' 207 | }, 208 | @{ 209 | id = 'veeam-explorer-ad' 210 | version = '[11.0.0.837]' 211 | }, 212 | @{ 213 | id = 'veeam-explorer-exchange' 214 | version = '[11.0.0.837]' 215 | }, 216 | @{ 217 | id = 'veeam-explorer-oracle' 218 | version = '[11.0.0.837]' 219 | }, 220 | @{ 221 | id = 'veeam-explorer-sharepoint' 222 | version = '[11.0.0.837]' 223 | }, 224 | @{ 225 | id = 'veeam-explorer-sql' 226 | version = '[11.0.0.837]' 227 | }, 228 | @{ 229 | id = 'veeam-redistr-windows' 230 | version = '[11.0.0.837]' 231 | }, 232 | @{ 233 | id = 'veeam-redistr-linux' 234 | version = '[11.0.0.837]' 235 | }, 236 | @{ 237 | id = 'veeam-redistr-mac' 238 | version = '[11.0.0.837]' 239 | } 240 | ) 241 | } 242 | files = @() 243 | } 244 | } 245 | ``` 246 | 247 | As can be seen, the package lacks any local files, remote files, or installers. 248 | Instead, it consists of a series of dependencies that, together, install a fully 249 | working instance of the Veeam Backup & Replication server. The goal should be 250 | to replicate what is produced when a user runs the normal GUI installer. In 251 | other words, if there are optional packages not normally installed by the GUI 252 | installer, they should be left out of this configuration. 253 | 254 | Note that the order is important as Chocolatey will instal the dependencies in 255 | the order given above unless the dependency graph forces it out of order. Not 256 | all dependencies are listed here - the `veeam-server` package has a number of 257 | third-party dependencies that will be picked up when Chocolatey reads the 258 | package metadata. The best way to think of this package is the "glue" of the 259 | whole thing - it brings it all together and installs the full software stack on 260 | the user's machine. 261 | 262 | ## The Sub Packages 263 | 264 | The remaining files should exist under the `packages` subdirectory and should 265 | be individual package configuration files that each reference an MSI/EXE 266 | installer in the ISO file. As mentioned above, these are normal package 267 | configuration files, with one notable exception: 268 | 269 | ```powershell 270 | @{ 271 | name = 'veeam-catalog' 272 | processScript = '' 273 | shim = $False 274 | installer = @{ 275 | scriptPath = 'tools' 276 | installerPath = 'Catalog\VeeamBackupCatalog64.msi' 277 | installerPath64 = '' 278 | installerType = 'msi' 279 | exitCodes = @(0, 1638, 1641, 3010) 280 | flags = '/qn /norestart' 281 | arguments = @{ 282 | ACCEPT_THIRDPARTY_LICENSES = '1' 283 | INSTALLDIR = '' 284 | VM_CATALOGPATH = '' 285 | VBRC_SERVICE_USER = '' 286 | VBRC_SERVICE_PASSWORD = '' 287 | VBRC_SERVICE_PORT = '' 288 | } 289 | } 290 | localFiles = @() 291 | remoteFiles = @() 292 | manifest = @{ 293 | metadata = @{ 294 | id = 'veeam-catalog' 295 | title = 'Veeam Backup & Replication Catalog' 296 | version = '11.0.0.837' 297 | authors = 'Veeam' 298 | owners = 'Joshua Gilman' 299 | summary = 'Installs the Veeam Backup & Replication Catalog service' 300 | description = 'Veeam Backup & Replication is a backup solution developed for VMware vSphere and Microsoft Hyper-V virtual environments. Veeam Backup & Replication provides a set of features for performing data protection and disaster recovery tasks.' 301 | projectUrl = 'http://www.veeam.com/' 302 | packageSourceUrl = 'https://github.com/jmgilman/ChocolateyPackageManager' 303 | tags = 'veeam backup replication catalog' 304 | copyright = '2021 Veeam' 305 | licenseUrl = 'https://www.veeam.com/eula.html' 306 | requireLicenseAcceptance = 'false' 307 | dependencies = @( 308 | @{ 309 | id = 'veeam-iso' 310 | version = '[11.0.0.837]' 311 | }, 312 | @{ 313 | id = 'dotnet-472' 314 | version = '' 315 | } 316 | ) 317 | } 318 | files = @( 319 | @{ 320 | src = 'tools\**' 321 | target = 'tools' 322 | } 323 | ) 324 | } 325 | } 326 | ``` 327 | 328 | Notice in the above configuration that the `installerPath` property is pointing 329 | to a relative directory that will not exist in the package: 330 | `Catalog\VeeamBackupCatalog64.msi`. So how does this work? When the ISO package 331 | is being built, the module will automatically append a relative path to the 332 | `installerPath` that will force it to point to the directory where the ISO 333 | file contents have already been downloaded. For example, here is what the 334 | compiled `ChocolateyInstall.ps1` script looks like for the above configuration: 335 | 336 | ```powershell 337 | $filePath = '..\veeam-iso\Catalog\VeeamBackupCatalog64.msi' 338 | ``` 339 | 340 | Later on in the code this is expanded to a fully qualified path: 341 | 342 | ```powershell 343 | $fileLocation = (Get-Item $fileLocation).FullName # Resolve relative paths 344 | ``` 345 | 346 | Which would result in a final location of: 347 | `C:\ProgramData\chocolatey\lib\veeam-iso\Catalog\VeeamBackupCatalog64.msi`. 348 | 349 | The point to understand, then, is that in the subpackages of an ISO package the 350 | **installer path should be relative from the root of the ISO file**. If you were 351 | to mount the contents of the Veeam ISO image, you would find something like the 352 | following: `E:\Catalog\VeeamBackupCatalog64.msi`. The benefit of this approach 353 | is you don't need to be concerend about where or how the files are getting to 354 | the local system, only with creating the packages and referencing the installer 355 | path as shown above. 356 | 357 | # Building the ISO Package 358 | 359 | With the structure in place we can now build out the contents of the ISO 360 | package. Note that we reference the singular form of the word package here, but 361 | technically an ISO package is a conglomeration of multiple packages. The build 362 | process will end up producing several `.nupkg` files which, together, make up 363 | the ISO package. Recall that the meta package is what is tying all of these 364 | packages together via dependencies - so in a production environment all of these 365 | packages will need to be pushed to the local NuGet repository and the end-user 366 | only needs to be aware of the existence of the metapackage 367 | (i.e. `choco install veeam`). 368 | 369 | Building out the package does take a bit more work than a normal package as 370 | all the configurations must be loaded and passed to the function which creates 371 | the `ChocolateyISOPackage` object. Here is an excerpt from the build script 372 | which can be found in the examples directory: 373 | 374 | ```powershell 375 | [cmdletbinding()] 376 | param( 377 | [string] $PackageFile, 378 | [string] $OutPath 379 | ) 380 | 381 | $ErrorActionPreference = 'Stop' 382 | Import-Module (Join-Path $PSScriptRoot '..\ChocolateyPackageCreator') -Force 383 | 384 | if (!(Test-Path $PackageFile)) { 385 | throw 'Cannot find meta package file at {0}' -f $ConfigFile 386 | } 387 | 388 | if (!(Test-Path $OutPath)) { 389 | throw 'The output path must already exist at {0}' -f $OutPath 390 | } 391 | 392 | $verbose = $PSCmdlet.MyInvocation.BoundParameters['Verbose'] 393 | $hasDefender = Test-Path (Join-Path $env:ProgramFiles 'Windows Defender/MpCmdRun.exe' -ErrorAction SilentlyContinue) 394 | $packagePath = Split-Path -Parent $PackageFile 395 | 396 | # Load meta package 397 | Write-Verbose ('Loading meta package at {0}' -f $PackageFile) 398 | $metaConfig = Import-PowerShellDataFile $PackageFile 399 | $metaPackage = New-ChocolateyPackage $packagePath $metaConfig 400 | 401 | # Load ISO package 402 | $isoPackagePath = Join-Path $packagePath 'iso.psd1' 403 | if (!(Test-Path $isoPackagePath)) { 404 | throw 'Could not find ISO package at {0}' -f $isoPackagePath 405 | } 406 | 407 | Write-Verbose ('Loading iso package at {0}' -f $isoPackagePath) 408 | $isoConfig = Import-PowerShellDataFile $isoPackagePath 409 | 410 | # Load all sub packages 411 | $packages = [System.Collections.ArrayList]@() 412 | $packagesPath = Join-Path $packagePath 'packages' 413 | 414 | Write-Verbose ('Searching for sub-packages at {0}...' -f $packagesPath) 415 | $subPackagePaths = Get-ChildItem $packagesPath -Filter '*.psd1' -Recurse 416 | foreach ($subPackageFile in $subPackagePaths) { 417 | Write-Verbose ('Loading sub-package at {0}...' -f $subPackageFile.FullName) 418 | $packageConfig = Import-PowerShellDataFile $subPackageFile.FullName 419 | $packages.Add((New-ChocolateyPackage $subPackageFile.Parent.FullName $packageConfig)) 420 | } 421 | 422 | # Create ISO package 423 | $isoPackage = New-ChocolateyISOPackage $PackagePath $isoConfig $metaPackage $packages 424 | ``` 425 | 426 | The general flow is as follows: 427 | 428 | * Load the contents of the meta package configuration 429 | * Load the contents of the ISO package configuration 430 | * Iterate through all sub-packages present in the `packages` subdirectory and 431 | load their package configurations. 432 | * Pass all these packages to the `New-ChocolateyISOPackage` function to get a 433 | `ChocolateyISOPackage` object back 434 | 435 | The resulting object can then be passed to the build function: 436 | 437 | ```powershell 438 | $packageFiles = Build-ChocolateyISOPackage ` 439 | -Package $IsoPackage ` 440 | -OutPath $OutPath ` 441 | -ScanFiles:$hasDefender ` 442 | -Verbose:$verbose 443 | ``` 444 | 445 | This looks indetical to the `Build-ChocolateyPackage` function except that it 446 | takes a `ChocolateyISOPackage` object and, of course, builds out many more 447 | packages. The `$OutPath` directory, after the build finishes, will contain 448 | multiple `.nugpk` files that, together, make up the ISO package. 449 | 450 | # Publishing the ISO Image 451 | 452 | Publishing the ISO package is as simply as calling `Publish-ChocolateyPackage` 453 | on each of the packages generated by the build. The build function will return 454 | an array of fully qualified paths to each of the packages generated in order to 455 | ease this process: 456 | 457 | ```powershell 458 | foreach ($packageFile in $packageFiles) { 459 | Publish-ChocolateyPackage ` 460 | -Repository $Repository ` 461 | -ApiKey $env:API_KEY ` 462 | -PackageFile $PackageFile 463 | } 464 | ``` -------------------------------------------------------------------------------- /ChocolateyPackageCreator/functions/build.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Compiles and builds the chocolatey package defined in the ChocolateyPackage 4 | .DESCRIPTION 5 | Using the given ChocolateyPackage object, performs the following: 6 | * Creates a NuSpec file using the package manifest section 7 | * Downloads all remote files defined in the package 8 | * Copies all local files defined in the package 9 | * Runs an optional process script for post-processing of package files 10 | * Builds the package using choco pack 11 | The path to the final package file is returned. Note that during the build 12 | process a temporary directory is created in the OutPath directory to hold 13 | files and appropriate write permissions are required. 14 | .PARAMETER Package 15 | The ChocolateyPackage to build 16 | .PARAMETER OutPath 17 | The output directory where the final package file will be placed 18 | .PARAMETER PreProcess 19 | An optional script block that is ran before the package process script. This 20 | script block receives the same parameters as the package process script. 21 | .PARAMETER ChocolateyPath 22 | The path to the choco binary - defaults to 'choco' 23 | .PARAMETER KeepFiles 24 | If set, does not delete the package files gathered during the build process. 25 | This is usually useful for debugging packages. 26 | .PARAMETER ScanFiles 27 | Whether or not to scan any downloaded files using Windows Defender 28 | .EXAMPLE 29 | Build-ChocolateyPackae ` 30 | -Package $myPackage ` 31 | -OutPath C:\path\to\package\output ` 32 | -ScanFiles 33 | .OUTPUTS 34 | The path to the final package file 35 | #> 36 | Function Build-ChocolateyPackage { 37 | [cmdletbinding()] 38 | param( 39 | [Parameter( 40 | Mandatory = $true, 41 | Position = 1, 42 | ValueFromPipeline = $true 43 | )] 44 | [ChocolateyPackage] $Package, 45 | [Parameter( 46 | Mandatory = $true, 47 | Position = 2 48 | )] 49 | [string] $OutPath, 50 | [scriptblock] $PreProcess = {}, 51 | [string] $ChocolateyPath = 'choco', 52 | [switch] $ScanFiles, 53 | [switch] $KeepFiles 54 | ) 55 | 56 | $buildDir = Join-Path $OutPath ($Package.Name + '-build') 57 | 58 | Write-Verbose ('Creating build directory at {0}...' -f $buildDir) 59 | New-Item -ItemType Directory $buildDir | Out-Null 60 | 61 | $nuspecPath = (Join-Path $buildDir ($Package.Manifest.Metadata.Id + '.nuspec')) 62 | 63 | Write-Verbose ('Creating NuSpec file at {0}...' -f $nuspecPath) 64 | $xml = New-ChocolateyNuSpec $Package.Manifest 65 | $xml.Save($nuspecPath) 66 | 67 | if ($Package.RemoteFiles.Count -gt 0) { 68 | Write-Verbose 'Downloading remote files...' 69 | foreach ($remoteFile in $Package.RemoteFiles) { 70 | $remoteFile | Get-RemoteFile -OutPath $buildDir -Scan:$ScanFiles | Out-Null 71 | } 72 | } 73 | 74 | if ($Package.LocalFiles.Count -gt 0) { 75 | Write-Verbose 'Copying local files...' 76 | foreach ($localFile in $Package.LocalFiles) { 77 | $outFile = Join-Path $buildDir $localFile.ImportPath 78 | if (!(Test-Path (Split-Path $outFile))) { 79 | New-Item -ItemType Directory -Path (Split-Path $outFile) | Out-Null 80 | } 81 | 82 | Write-Verbose ('Copying {0} to {1}...' -f $localFile.LocalPath, $outFile) 83 | Copy-Item $localFile.LocalPath $outFile | Out-Null 84 | } 85 | } 86 | 87 | if ($Package.Installer.InstallerPath) { 88 | $installerFolder = Join-Path $buildDir $Package.Installer.ScriptPath 89 | if (!(Test-Path $installerFolder)) { 90 | New-Item -ItemType Directory $installerFolder | Out-Null 91 | } 92 | 93 | $installerFilePath = Join-Path $installerFolder 'ChocolateyInstall.ps1' 94 | $installerFileContents = Build-InstallerFile $Package 95 | 96 | Write-Verbose ('Writing installer file to {0}...' -f $installerFilePath) 97 | Set-Content $installerFilePath $installerFileContents | Out-Null 98 | } 99 | 100 | $PreProcess.Invoke($buildDir, $Package) 101 | 102 | if ($Package.processScript) { 103 | Write-Verbose ('Calling process script at {0}...' -f $Package.processScript) 104 | $proc = Get-Command $Package.processScript | Select-Object -ExpandProperty ScriptBlock 105 | $proc.Invoke($buildDir, $Package) | Out-Null 106 | } 107 | 108 | if (!$Package.Shim) { 109 | Write-Verbose "Preventing shimming of exe's..." 110 | Invoke-Unshim $buildDir | Out-Null 111 | } 112 | 113 | $exitCode = Invoke-ChocolateyBuild ` 114 | -NuspecFile $nuspecPath ` 115 | -BuildPath $buildDir ` 116 | -OutPath $OutPath ` 117 | -ChocolateyPath $ChocolateyPath 118 | 119 | if ($exitCode -ne 0) { 120 | throw 'The Chocolatey package process exited with non-zero exit code: {0}' -f $proc.ExitCode 121 | } 122 | 123 | if (!$KeepFiles) { 124 | Write-Verbose 'Cleaning up...' 125 | Remove-Item $buildDir -Recurse -Force | Out-Null 126 | } 127 | 128 | $packageName = '{0}.{1}.nupkg' -f $Package.Manifest.Metadata.Id, $Package.Manifest.Metadata.Version 129 | Join-Path $OutPath $packageName 130 | } 131 | 132 | <# 133 | .SYNOPSIS 134 | Compiles and builds the chocolatey ISO package defined in the ChocolateyISOPackage 135 | .DESCRIPTION 136 | Using the given ChocolateyISOPackage object, performs the following: 137 | * Builds the ISO package using the static installer file 138 | * Iterates through and builds all subpackages, modifying their installer 139 | path to point to the ISO package folder 140 | The path to all built packages are returned. Note that during the build 141 | process a temporary directory is created in the OutPath directory to hold 142 | files and appropriate write permissions are required. 143 | .PARAMETER Package 144 | The ChocolateyISOPackage to build 145 | .PARAMETER OutPath 146 | The output directory where the final package files will be placed 147 | .PARAMETER ChocolateyPath 148 | The path to the choco binary - defaults to 'choco' 149 | .PARAMETER KeepFiles 150 | If set, does not delete the package files gathered during the build process. 151 | This is usually useful for debugging packages. 152 | .PARAMETER ScanFiles 153 | Whether or not to scan any downloaded files using Windows Defender 154 | .EXAMPLE 155 | Build-ChocolateyISOPackae ` 156 | -Package $myPackage ` 157 | -OutPath C:\path\to\package\output 158 | .OUTPUTS 159 | An array of fully qualified paths pointing to all built package files 160 | #> 161 | Function Build-ChocolateyISOPackage { 162 | param( 163 | [Parameter( 164 | Mandatory = $true, 165 | Position = 1, 166 | ValueFromPipeline = $true 167 | )] 168 | [ChocolateyISOPackage] $Package, 169 | [Parameter( 170 | Mandatory = $true, 171 | Position = 2 172 | )] 173 | [string] $OutPath, 174 | [string] $ChocolateyPath = 'choco', 175 | [switch] $ScanFiles, 176 | [switch] $KeepFiles 177 | ) 178 | 179 | Write-Verbose 'Building ISO package...' 180 | $packageFiles = [System.Collections.ArrayList]@() 181 | $buildDir = Join-Path $OutPath ($Package.Name + '-build') 182 | 183 | Write-Verbose ('Creating build directory at {0}...' -f $buildDir) 184 | New-Item -ItemType Directory $buildDir | Out-Null 185 | 186 | $nuspecPath = (Join-Path $buildDir ($Package.Manifest.Metadata.Id + '.nuspec')) 187 | 188 | Write-Verbose ('Creating NuSpec file at {0}...' -f $nuspecPath) 189 | $xml = New-ChocolateyNuSpec $Package.Manifest 190 | $xml.Save($nuspecPath) 191 | 192 | $installerFolder = Join-Path $buildDir 'tools' 193 | if (!(Test-Path $installerFolder)) { 194 | New-Item -ItemType Directory $installerFolder | Out-Null 195 | } 196 | 197 | $installerFilePath = Join-Path $installerFolder 'ChocolateyInstall.ps1' 198 | $installerFileContents = Build-ISOInstallerFile $Package 199 | 200 | Write-Verbose ('Writing installer file to {0}...' -f $installerFilePath) 201 | Set-Content $installerFilePath $installerFileContents | Out-Null 202 | 203 | $exitCode = Invoke-ChocolateyBuild ` 204 | -NuspecFile $nuspecPath ` 205 | -BuildPath $buildDir ` 206 | -OutPath $OutPath ` 207 | -ChocolateyPath $ChocolateyPath 208 | 209 | if ($exitCode -ne 0) { 210 | throw 'The Chocolatey package process exited with non-zero exit code: {0}' -f $proc.ExitCode 211 | } 212 | 213 | if (!$KeepFiles) { 214 | Write-Verbose 'Cleaning up...' 215 | Remove-Item $buildDir -Recurse -Force | Out-Null 216 | } 217 | 218 | $packageName = '{0}.{1}.nupkg' -f $Package.Manifest.Metadata.Id, $Package.Manifest.Metadata.Version 219 | $packageFiles.Add((Join-Path $OutPath $packageName)) | Out-Null 220 | 221 | Write-Verbose 'Building sub packages...' 222 | foreach ($subPackage in $Package.Packages) { 223 | Write-Verbose ('Building {0}...' -f $subPackage.Name) 224 | $subPackage.Installer.InstallerPath = '..\{0}\{1}' -f $Package.Manifest.Metadata.Id, $subPackage.Installer.InstallerPath 225 | $packageFile = Build-ChocolateyPackage ` 226 | -Package $subPackage ` 227 | -OutPath $OutPath ` 228 | -ChocolateyPath $ChocolateyPath ` 229 | -ScanFiles:$ScanFiles ` 230 | -KeepFiles:$KeepFiles 231 | $packageFiles.Add($packageFile) | Out-Null 232 | } 233 | 234 | Write-Verbose 'Building meta package...' 235 | Write-Verbose ('Building {0}...' -f $Package.MetaPackage.Name) 236 | $metaPackageFile = Build-ChocolateyPackage ` 237 | -Package $Package.MetaPackage ` 238 | -OutPath $OutPath ` 239 | -ChocolateyPath $ChocolateyPath ` 240 | -ScanFiles:$ScanFiles ` 241 | -KeepFiles:$KeepFiles 242 | $packageFiles.Add($metaPackageFile) | Out-Null 243 | 244 | $packageFiles 245 | } 246 | 247 | 248 | <# 249 | .SYNOPSIS 250 | Downloads a RemoteFile to its local path and optionally scans it for viruses 251 | .DESCRIPTION 252 | Using the given RemoteFile object, downloads the contents at the url and 253 | saves it to the import path. If the Scan flag is set the file will 254 | automatically be scanned using Windows Defeneder. This function will throw 255 | an exception if the Scan flag is passed but Windows Defender is not 256 | available. 257 | .PARAMETER RemoteFile 258 | The RemoteFile object to download 259 | .PARAMETER OutPath 260 | The output path to download to. The final file location will be the given 261 | output path + the RemoteFile import path. For example, if the output path 262 | is 'C:\myfolder' and the import path is 'files\myfile.exe' then the final 263 | file path will be 'C:\myfolder\files\myfile.exe'. 264 | .PARAMETER Scan 265 | Whether or not to scan the downloaded file using Windows Defender 266 | .EXAMPLE 267 | Get-RemoteFile -RemoteFile $myFile -OutPath C:\myfolder -Scan 268 | .OUTPUTS 269 | None 270 | #> 271 | Function Get-RemoteFile { 272 | param( 273 | [Parameter( 274 | Mandatory = $true, 275 | Position = 1, 276 | ValueFromPipeline = $true 277 | )] 278 | [RemoteFile] $File, 279 | [Parameter( 280 | Mandatory = $true, 281 | Position = 2 282 | )] 283 | [string] $OutPath, 284 | [switch] $Scan 285 | ) 286 | 287 | $filePath = Join-Path $OutPath $File.ImportPath 288 | if (!(Test-Path (Split-Path $filePath))) { 289 | New-Item -ItemType Directory -Path (Split-Path $filePath) 290 | } 291 | 292 | Write-Verbose ('Downloading {0} to {1}...' -f $File.Url, $filePath) 293 | Invoke-WebRequest $File.Url -OutFile $filePath 294 | 295 | if ($File.Sha1) { 296 | Write-Verbose ('Computing file hash for {0}...' -f $filePath) 297 | $hash = Get-FileHash $filePath -Algorithm SHA1 298 | 299 | Write-Verbose ('Downloaded file hash: {0}' -f $hash.Hash) 300 | Write-Verbose ('Expected file hash: {0}' -f $File.Sha1) 301 | if ($File.Sha1 -ne $hash.Hash) { 302 | throw 'The downloaded file hash did not match the expected hash' 303 | } 304 | } 305 | 306 | if ($Scan) { 307 | Write-Verbose ('Scanning {0}...' -f $filePath) 308 | $exitCode = Invoke-WindowsDefenderScan $filePath 309 | 310 | if ($exitCode -ne 0) { 311 | throw '{0} was flagged by Windows Defender as dangerous' -f $filePath 312 | } 313 | } 314 | } 315 | 316 | <# 317 | .SYNOPSIS 318 | Scans the given file using Windows Defender 319 | .DESCRIPTION 320 | Executes MpCmdRun.exe and performs a custom scan against the given file, 321 | returning the exit code of the process. 322 | .PARAMETER FilePath 323 | The path to the file the scan 324 | .EXAMPLE 325 | $exitCode = Invoke-WindowsDefenderScan path\to\file.exe 326 | .OUTPUTS 327 | The exit code of the scan process: 0 is safe, 2 is unsafe. 328 | #> 329 | Function Invoke-WindowsDefenderScan { 330 | param( 331 | [Parameter( 332 | Mandatory = $true 333 | )] 334 | [string] $FilePath 335 | ) 336 | $mpCmd = Join-Path $env:ProgramFiles 'Windows Defender/MpCmdRun.exe' -ErrorAction SilentlyContinue 337 | if (!(Test-Path $mpCmd)) { 338 | throw 'Unable to locate Windows Defender at {0}' -f (Join-Path $env:ProgramFiles 'Windows Defender/MpCmdRun.exe') 339 | } 340 | 341 | $mpArgs = @( 342 | '-Scan', 343 | '-ScanType 3', 344 | '-File "{0}"' -f $FilePath 345 | ) 346 | 347 | $proc = Start-Process $mpCmd -ArgumentList $mpArgs -PassThru -NoNewWindow -Wait 348 | $proc.ExitCode 349 | } 350 | 351 | 352 | <# 353 | .SYNOPSIS 354 | Runs choco pack on the given NuSpec file 355 | .DESCRIPTION 356 | Executes the Chocolatey binary, passing arguments for building the given 357 | NuSpec file at the given build path. The OutPath is also passed and 358 | instructs Chocolatey where to place the build artifacts. 359 | .PARAMETER NuSpecFile 360 | The path to the NuSpec file 361 | .PARAMETER BuildPath 362 | The path to the package contents 363 | .PARAMETER OutPath 364 | The path where Chocolatey will output build artifacts 365 | .PARAMETER ChocolateyPath 366 | The path to the choco binary - defaults to 'choco' 367 | .EXAMPLE 368 | $exitCode = Invoke-ChocolateyBuild ` 369 | -NuSpecFile 'C:\my\package.nuspec' ` 370 | -BuildPath 'C:\my\' ` 371 | -OutPath 'C:\my\bin' 372 | .OUTPUTS 373 | The exit code of the Chocolatey build process 374 | #> 375 | Function Invoke-ChocolateyBuild { 376 | param( 377 | [string] $NuspecFile, 378 | [string] $BuildPath, 379 | [string] $OutPath, 380 | [string] $ChocolateyPath = 'choco' 381 | ) 382 | 383 | $chocoArgs = @( 384 | 'pack', 385 | $NuspecFile, 386 | '--outputdirectory {0}' -f $OutPath 387 | ) 388 | 389 | Write-Verbose ("Executing `"{0} {1}`" in directory {2}" -f $ChocolateyPath, ($chocoArgs -join ' '), $OutPath) 390 | $proc = Start-Process $ChocolateyPath -ArgumentList $chocoArgs -WorkingDirectory $BuildPath -PassThru -NoNewWindow -Wait 391 | $proc.ExitCode 392 | } 393 | 394 | <# 395 | .SYNOPSIS 396 | Creates a NuSpec file from the given object 397 | .DESCRIPTION 398 | Given a package manifest, constructs the appropriate XML to create a valid 399 | NuSpec file and returns it as an XML document 400 | .PARAMETER Manifest 401 | The PackageManifest object to construct from 402 | .EXAMPLE 403 | New-ChocolateyNuSpec -Manifest $package.Manifest 404 | .OUTPUTS 405 | A System.Xml.XmlDocument containing the NuSpec configuration 406 | #> 407 | Function New-ChocolateyNuSpec { 408 | [OutputType([System.Xml.XmlDocument])] 409 | param( 410 | [Parameter( 411 | Mandatory = $true, 412 | ValueFromPipeline = $true 413 | )] 414 | [PackageManifest] $Manifest 415 | ) 416 | 417 | # Create root element 418 | [xml]$xml = New-Object System.Xml.XmlDocument 419 | $xml.AppendChild($xml.CreateXmlDeclaration('1.0', 'UTF-8', $null)) | Out-Null 420 | 421 | # Create package element 422 | $package = $xml.CreateNode('element', 'package', $null) 423 | $package.SetAttribute('xmlns', 'http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd') 424 | 425 | # Create metadata element 426 | $metadata = $xml.CreateNode('element', 'metadata', $null) 427 | Add-PropertiesToNode $Manifest.Metadata $metadata -Ignore @('Dependencies') -Uncapitalize | Out-Null 428 | 429 | # Create metadata dependencies element if present 430 | if ($Manifest.Metadata.Dependencies) { 431 | $dependencies = $xml.CreateNode('element', 'dependencies', $null) 432 | foreach ($dependency in $Manifest.Metadata.Dependencies) { 433 | $dependencyNode = $xml.CreateNode('element', 'dependency', $null) 434 | Add-PropertiesToNode $dependency $dependencyNode -Uncapitalize -UseAttributes | Out-Null 435 | $dependencies.AppendChild($dependencyNode) | Out-Null 436 | } 437 | $metadata.AppendChild($dependencies) | Out-Null 438 | } 439 | $package.AppendChild($metadata) | Out-Null 440 | 441 | # Create files element if present 442 | if ($Manifest.Files) { 443 | $files = $xml.CreateNode('element', 'files', $null) 444 | foreach ($file in $Manifest.Files) { 445 | $fileNode = $xml.CreateNode('element', 'file', $null) 446 | Add-PropertiesToNode $file $fileNode -Uncapitalize -UseAttributes | Out-Null 447 | $files.AppendChild($fileNode) | Out-Null 448 | } 449 | $package.AppendChild($files) | Out-Null 450 | } 451 | 452 | $xml.AppendChild($package) | Out-Null 453 | $xml 454 | } 455 | 456 | <# 457 | .SYNOPSIS 458 | Adds properties from the given object to the given XML node 459 | .DESCRIPTION 460 | Iterates through all properties on the given object and assigns each 461 | property to a child element on the given node. If UseAttributes is passed 462 | then the properties are assigned to the given node as attributes instead. 463 | .PARAMETER Object 464 | The object to copy properties from 465 | .PARAMETER Node 466 | The XML node to add the properties to 467 | .PARAMETER Ignore 468 | An array of property names to ignore and not add to the node 469 | .PARAMETER UseAttributes 470 | Assigns the properties to the node as attributes instead of creating child 471 | elements. 472 | .PARAMETER Uncapitalize 473 | Removes capitalization from the property names before adding them 474 | .EXAMPLE 475 | Add-PropertiesToNode $object $objectNode -Uncapitalize -UseAttributes 476 | .OUTPUTS 477 | The XML node passed in is modified in place 478 | #> 479 | Function Add-PropertiesToNode { 480 | param( 481 | [Parameter( 482 | Mandatory = $true, 483 | Position = 1 484 | )] 485 | [object] $Object, 486 | [Parameter( 487 | Mandatory = $true, 488 | Position = 2 489 | )] 490 | [System.Xml.XmlLinkedNode] $Node, 491 | [string[]] $Ignore = @(), 492 | [switch] $UseAttributes, 493 | [switch] $Uncapitalize 494 | ) 495 | 496 | $properties = $Object | Get-Member | Where-Object MemberType -EQ 'Property' | Select-Object -ExpandProperty Name 497 | foreach ($property in $properties) { 498 | $propertyName = $property 499 | $propertyValue = $Object | Select-Object -ExpandProperty $property 500 | 501 | if ($propertyName -in $Ignore) { 502 | continue 503 | } 504 | 505 | if ($Uncapitalize) { 506 | $propertyName = $property.Insert(0, $property.Substring(0, 1).ToLower()).Remove(1, 1) 507 | } 508 | 509 | if ($UseAttributes) { 510 | $Node.SetAttribute($propertyName, $propertyValue) | Out-Null 511 | } 512 | else { 513 | $xmlProperty = $xml.CreateNode('element', $propertyName, $null) 514 | $xmlProperty.InnerText = $propertyValue 515 | $Node.AppendChild($xmlProperty) | Out-Null 516 | } 517 | } 518 | } 519 | 520 | <# 521 | .SYNOPSIS 522 | Creates ignore files for all executables at the given path 523 | .DESCRIPTION 524 | Recursively scans the given path for .exe files and, for each file found, 525 | creates an assocated .ignore file in the same location as the exe file. 526 | This prevents exe files from being automatically shimmed by Chocolatey. 527 | .PARAMETER BuildPath 528 | The path to search and unshim files for 529 | .EXAMPLE 530 | Invoke-Unshim C:\my\build\path 531 | .OUTPUTS 532 | None 533 | #> 534 | Function Invoke-Unshim { 535 | param($BuildPath) 536 | 537 | $exeFiles = Get-ChildItem $BuildPath -Filter '*.exe' -Recurse 538 | foreach ($file in $exeFiles) { 539 | $ignoreFile = $file.FullName + '.ignore' 540 | 541 | Write-Verbose ('Preventing shim of {0} with {1}...' -f $file.FullName, $ignoreFile) 542 | Set-Content $ignoreFile '' 543 | } 544 | } 545 | 546 | <# 547 | .SYNOPSIS 548 | Returns the contents of a ChocolateyInstall.ps1 file using the given ChocolateyPackage 549 | .DESCRIPTION 550 | Using the built-in template, dynamically generates the contents of a 551 | ChocolateyInstall.ps1 file for the given ChocolateyPackage. The contents of 552 | the file are returned. 553 | .PARAMETER Package 554 | The Chocolatey package to create the installer for 555 | .EXAMPLE 556 | Set-Content 'ChocolateyInstall.ps1' (Build-InstallerFile $Package) 557 | .OUTPUTS 558 | The contents of the ChocolateyInstall.ps1 file 559 | #> 560 | Function Build-InstallerFile { 561 | param( 562 | [ChocolateyPackage] $Package 563 | ) 564 | 565 | $staticFilePath = Join-Path $PSScriptRoot '..\static' 566 | $installerTemplate = Join-Path $staticFilePath 'template\default\ChocolateyInstall.eps' 567 | $binding = @{ 568 | packageName = $Package.Manifest.Metadata.Id 569 | filePath = $Package.Installer.InstallerPath 570 | filePath64 = $Package.Installer.InstallerPath64 571 | fileType = $Package.Installer.InstallerType 572 | exitCodes = $Package.Installer.ExitCodes 573 | flags = $Package.Installer.Flags 574 | argumentPrefix = $Package.Installer.ArgumentPrefix 575 | arguments = $Package.Installer.Arguments 576 | } 577 | 578 | Invoke-EpsTemplate -Path $installerTemplate -Safe -Binding $binding 579 | } 580 | 581 | <# 582 | .SYNOPSIS 583 | Returns the contents of a ChocolateyInstall.ps1 file using the given ChocolateyISOPackage 584 | .DESCRIPTION 585 | Using the built-in template, dynamically generates the contents of a 586 | ChocolateyInstall.ps1 file for the given ChocolateyISOPackage. The contents 587 | of the file are returned. 588 | .PARAMETER Package 589 | The Chocolatey ISO package to create the installer for 590 | .EXAMPLE 591 | Set-Content 'ChocolateyInstall.ps1' (Build-ISOInstallerFile $Package) 592 | .OUTPUTS 593 | The contents of the ChocolateyInstall.ps1 file 594 | #> 595 | Function Build-ISOInstallerFile { 596 | param( 597 | [ChocolateyISOPackage] $Package 598 | ) 599 | 600 | $staticFilePath = Join-Path $PSScriptRoot '..\static' 601 | $installerTemplate = Join-Path $staticFilePath 'template\iso\ChocolateyInstall.eps' 602 | $binding = @{ 603 | packageName = $Package.Manifest.Metadata.Id 604 | filePath = $Package.IsoFile.ImportPath 605 | url = $Package.IsoFile.Url 606 | hash = $Package.IsoFile.Sha1 607 | } 608 | 609 | Invoke-EpsTemplate -Path $installerTemplate -Safe -Binding $binding 610 | } --------------------------------------------------------------------------------