Public/Tests/New-APFDeployment.Tests.ps1
|
BeforeAll { $env:TCS_CONFIG_ROOT = Join-Path -Path $TestDrive -ChildPath 'config' $env:TCS_SKIP_UPDATE_CHECK = '1' $env:TCS_TELEMETRY_OPTOUT = '1' $ModuleRoot = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent Import-Module -Name (Join-Path -Path $ModuleRoot -ChildPath 'tcs.intune.packaging.psd1') -Force } AfterAll { Remove-Module -Name tcs.intune.packaging -Force -ErrorAction SilentlyContinue } Describe 'New-APFDeployment' { BeforeEach { $Destination = Join-Path -Path $TestDrive -ChildPath ([guid]::NewGuid().ToString()) $null = New-Item -Path $Destination -ItemType Directory $Installer = Join-Path -Path $TestDrive -ChildPath 'Setup.exe' Set-Content -Path $Installer -Value 'installer' } It 'Creates the package folder with the installer, templates and filled-in configuration' { $output = New-APFDeployment -Path $Installer -Name 'My App' -Version '1.2.3.4' -InstallSwitches '/S' -UninstallSwitches '/U' -DestinationFolder $Destination -Confirm:$false $appFolder = Join-Path -Path $Destination -ChildPath 'My App' Join-Path -Path $appFolder -ChildPath 'Setup.exe' | Should -Exist Join-Path -Path $appFolder -ChildPath 'Intune-I-MainInstaller.ps1' | Should -Exist $config = Get-Content -Path (Join-Path -Path $appFolder -ChildPath 'config.installer.json') -Raw | ConvertFrom-Json $config.name | Should -Be 'My App' $config.version | Should -Be '1.2.3.4' $config.filename | Should -Be 'Setup.exe' $config.target | Should -Be 'system' $config.installswitches | Should -Be '/S' $config.uninstallswitches | Should -Be '/U' $detection = Get-Content -Path (Join-Path -Path $appFolder -ChildPath 'Intune-D-AppDetection.ps1') -Raw $detection | Should -Match "\`$AppName = 'My App'" $detection | Should -Match "\`$Version = '1\.2\.3\.4'" $output -join "`n" | Should -Match 'successfully packaged' # The Intune Management Extension is 32-bit: the command must start the 64-bit Windows PowerShell $output -join "`n" | Should -Match ([regex]::Escape("'%windir%\sysnative\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy RemoteSigned -WindowStyle Hidden -File Intune-I-MainInstaller.ps1' for the install command")) $output -join "`n" | Should -Match ([regex]::Escape('Intune-I-MainInstaller.ps1 -Uninstall')) } It 'Uses the file name as the default application name for EXE installers' { $null = New-APFDeployment -Path $Installer -Version '1.0' -DestinationFolder $Destination -Confirm:$false Join-Path -Path $Destination -ChildPath 'Setup' | Should -Exist } It 'Writes an error when the version cannot be read from the EXE' { $null = New-APFDeployment -Path $Installer -DestinationFolder $Destination -ErrorVariable apfError -ErrorAction SilentlyContinue -Confirm:$false $apfError | Should -Not -BeNullOrEmpty "$apfError" | Should -Match 'Specify it with -Version' } It 'Supports -WhatIf' { $null = New-APFDeployment -Path $Installer -Name 'WhatIfApp' -Version '1.0' -DestinationFolder $Destination -WhatIf Join-Path -Path $Destination -ChildPath 'WhatIfApp' | Should -Not -Exist } It 'Rejects installers that are not MSI or EXE files' { $zip = Join-Path -Path $TestDrive -ChildPath 'setup.zip' Set-Content -Path $zip -Value 'x' { New-APFDeployment -Path $zip -Name 'x' -Version '1.0' -DestinationFolder $Destination } | Should -Throw '*Only .msi and .exe*' } It 'Creates the intunewin package with the shared helper when requested' { Mock -ModuleName tcs.intune.packaging New-APFIntuneWinPackage { [System.IO.FileInfo](Join-Path -Path $OutputFolder -ChildPath 'Setup.intunewin') } $output = New-APFDeployment -Path $Installer -Name 'Pkg' -Version '1.0' -DestinationFolder $Destination -CreateIntuneWinPackage -Confirm:$false Should -Invoke -ModuleName tcs.intune.packaging New-APFIntuneWinPackage -Times 1 -Exactly -ParameterFilter { $SourceFolder -eq (Join-Path -Path $Destination -ChildPath 'Pkg') -and $OutputFolder -eq $Destination } $output -join "`n" | Should -Match 'Setup\.intunewin' } It 'Leaves an existing folder unchanged when the overwrite is declined' { $existing = Join-Path -Path $Destination -ChildPath 'Existing' $null = New-Item -Path $existing -ItemType Directory Set-Content -Path (Join-Path -Path $existing -ChildPath 'old.txt') -Value 'old' Mock -ModuleName tcs.intune.packaging Confirm-FolderOverwrite { $false } $output = New-APFDeployment -Path $Installer -Name 'Existing' -Version '1.0' -DestinationFolder $Destination -Confirm:$false -WarningVariable apfWarning -WarningAction SilentlyContinue Join-Path -Path $existing -ChildPath 'old.txt' | Should -Exist Join-Path -Path $existing -ChildPath 'Setup.exe' | Should -Not -Exist "$apfWarning" | Should -Match 'was not changed' $output | Should -BeNullOrEmpty } It 'Writes a name with quotes and a subexpression into a detection script that parses' { $name = "O'Brien `$(Get-Date)" $null = New-APFDeployment -Path $Installer -Name $name -Version '1.0' -DestinationFolder $Destination -Confirm:$false $script = Join-Path -Path (Join-Path -Path $Destination -ChildPath $name) -ChildPath 'Intune-D-AppDetection.ps1' $tokens = $null $errors = $null $ast = [System.Management.Automation.Language.Parser]::ParseFile($script, [ref]$tokens, [ref]$errors) $errors | Should -BeNullOrEmpty $assignment = $ast.Find({ param($node) $node -is [System.Management.Automation.Language.AssignmentStatementAst] -and $node.Left.VariablePath.UserPath -eq 'AppName' }, $true) $assignment.Right.Expression.Value | Should -BeExactly $name } It 'Rejects a name that would leave the destination folder' { $null = New-APFDeployment -Path $Installer -Name '..' -Version '1.0' -DestinationFolder $Destination -Confirm:$false -ErrorVariable apfError -ErrorAction SilentlyContinue "$apfError" | Should -Match 'not a valid name' @(Get-ChildItem -LiteralPath $Destination).Count | Should -Be 0 } } |