DSCResources/ChocolateyPackages/ChocolateyPackages.schema.psm1
configuration ChocolateyPackages { param ( [Parameter()] [hashtable]$Software, [Parameter()] [hashtable[]]$Sources, [Parameter()] [hashtable[]]$Features, [Parameter()] [boolean] $ForceRebootBefore = $false, [Parameter()] [hashtable[]]$Packages ) Import-DscResource -ModuleName PSDesiredStateConfiguration Import-DscResource -ModuleName ComputerManagementDsc Import-DscResource -ModuleName Chocolatey $chocoSwExecName = 'Choco_Software' if( $Software -ne $null ) { if( [String]::IsNullOrWhiteSpace($Software.OfflineInstallZip) -eq $false ) { # reduce footprint of serialized script parameter objects $swInstallationDirectory = $Software.InstallationDirectory $swOfflineInstallZip = $Software.OfflineInstallZip Script OfflineInstallChocolatey { TestScript = { # origin: https://github.com/chocolatey-community/Chocolatey/blob/master/Chocolatey/public/Test-ChocolateyInstall.ps1 try { Write-Verbose "Loading machine Path Environment variable into session." $envPath = [Environment]::GetEnvironmentVariable('Path','Machine') [Environment]::SetEnvironmentVariable($envPath,'Process') $installDir = $using:swInstallationDirectory if ($installDir -and (Test-Path $installDir) ) { $installDir = (Resolve-Path $installDir -ErrorAction Stop).Path } if ($chocoCmd = get-command choco.exe -CommandType Application -ErrorAction SilentlyContinue) { if ( !$installDir -or $chocoCmd.Path -match [regex]::Escape($installDir) ) { Write-Verbose ('Chocolatey Software found in {0}' -f $chocoCmd.Path) return $true } else { Write-Verbose ( 'Chocolatey Software not installed in {0}`n but in {1}' -f $installDir,$chocoCmd.Path ) return $false } } else { Write-Verbose "Chocolatey Software not found." return $false } } catch { Write-Verbose "Test for Chocolatey Software aborted with an exception.`n$_" return $false } } SetScript = { # origin: https://github.com/chocolatey-community/Chocolatey/blob/master/Chocolatey/public/Install-ChocolateySoftware.ps1 if ($null -eq $env:TEMP) { $env:TEMP = Join-Path $Env:SYSTEMDRIVE 'temp' } $tempDir = [io.path]::Combine($Env:TEMP,'chocolatey','chocInstall') if (![System.IO.Directory]::Exists($tempDir)) { $null = New-Item -path $tempDir -ItemType Directory } if( -not (Test-Path $using:swOfflineInstallZip) ) { Write-Error "ERROR: Offline installation package '$($using:swOfflineInstallZip)' not found." return } # copy the package with zip extension $file = Resolve-Path $using:swOfflineInstallZip $zipFile = [io.path]::Combine($Env:TEMP,'chocolatey','chocolatey.zip') Write-Verbose "Copy install package '$file' to '$zipFile'..." Copy-Item -Path $file -Destination $zipFile -Force # unzip the package Write-Verbose "Extracting $zipFile to $tempDir..." if ($PSVersionTable.PSVersion.Major -ge 5) { Expand-Archive -Path "$zipFile" -DestinationPath "$tempDir" -Force } else { try { $shellApplication = new-object -com shell.application $zipPackage = $shellApplication.NameSpace($zipFile) $destinationFolder = $shellApplication.NameSpace($tempDir) $destinationFolder.CopyHere($zipPackage.Items(),0x10) } catch { Write-Error "ERROR: Unable to unzip package using built-in compression. Error: `n $_" return } } # Call chocolatey install Write-Verbose "Installing chocolatey on this machine." $TempTools = [io.path]::combine($tempDir,'tools') # To be able to mock $chocInstallPS1 = Join-Path $TempTools 'chocolateyInstall.ps1' $chocoInstallDir = $using:swInstallationDirectory if ($chocoInstallDir -ne $null -and $chocoInstallDir -ne '') { Write-Verbose "Set Chocolatey installation directory to '$chocoInstallDir'" [Environment]::SetEnvironmentVariable('ChocolateyInstall', $chocoInstallDir, 'Machine') [Environment]::SetEnvironmentVariable('ChocolateyInstall', $chocoInstallDir, 'Process') } Write-Verbose "EnvVar 'ChocolateyInstall': $([Environment]::GetEnvironmentVariable('ChocolateyInstall'))" & $chocInstallPS1 | Write-Verbose Write-Verbose 'Ensuring chocolatey commands are on the path.' $chocoPath = [Environment]::GetEnvironmentVariable('ChocolateyInstall') if ($chocoPath -eq $null -or $chocoPath -eq '') { $chocoPath = "$env:ALLUSERSPROFILE\Chocolatey" } if (!(Test-Path ($chocoPath))) { $chocoPath = "$env:SYSTEMDRIVE\ProgramData\Chocolatey" } $chocoExePath = Join-Path $chocoPath 'bin' if ($($env:Path).ToLower().Contains($($chocoExePath).ToLower()) -eq $false) { $env:Path = [Environment]::GetEnvironmentVariable('Path',[System.EnvironmentVariableTarget]::Machine) } Write-Verbose 'Ensuring chocolatey.nupkg is in the lib folder' $chocoPkgDir = Join-Path $chocoPath 'lib\chocolatey' $nupkg = Join-Path $chocoPkgDir 'chocolatey.nupkg' $null = [System.IO.Directory]::CreateDirectory($chocoPkgDir) Copy-Item "$file" "$nupkg" -Force -ErrorAction SilentlyContinue if ($ChocoVersion = & "$chocoPath\choco.exe" -v) { Write-Verbose "Installed Chocolatey Version: $ChocoVersion" } # reboot machine to activate the new environment variables for DSC $global:DSCMachineStatus = 1 } GetScript = { return @{result = 'N/A'} } } $Software.Remove('OfflineInstallZip') $Software.DependsOn = '[Script]OfflineInstallChocolatey' } (Get-DscSplattedResource -ResourceName ChocolateySoftware -ExecutionName $chocoSwExecName -Properties $Software -NoInvoke).Invoke($Software) } if( $Sources -ne $null ) { foreach ($s in $Sources) { # Remove Case Sensitivity of ordered Dictionary or Hashtables $s = @{}+$s $executionName = $s.Name -replace '\(|\)|\.| ', '' $executionName = "Choco_Source_$executionName" if (-not $s.ContainsKey('Ensure')) { $s.Ensure = 'Present' } if( $Software -ne $null ) { $s.DependsOn = "[ChocolateySoftware]$chocoSwExecName" } (Get-DscSplattedResource -ResourceName ChocolateySource -ExecutionName $executionName -Properties $s -NoInvoke).Invoke($s) } } if( $Features -ne $null ) { foreach ($f in $Features) { # Remove Case Sensitivity of ordered Dictionary or Hashtables $f = @{}+$f $executionName = $f.Name -replace '\(|\)|\.| ', '' $executionName = "ChocolateyFeature_$executionName" if (-not $f.ContainsKey('Ensure')) { $f.Ensure = 'Present' } (Get-DscSplattedResource -ResourceName ChocolateyFeature -ExecutionName $executionName -Properties $f -NoInvoke).Invoke($f) } } if ($ForceRebootBefore -eq $true) { $rebootKeyName = 'HKLM:\SOFTWARE\DSC Community\CommonTasks\RebootRequests' $rebootVarName = 'RebootBefore_ChocolateyPackages' Script $rebootVarName { TestScript = { $val = Get-ItemProperty -Path $using:rebootKeyName -Name $using:rebootVarName -ErrorAction SilentlyContinue if ($val -ne $null -and $val.$rebootVarName -gt 0) { return $true } return $false } SetScript = { if( -not (Test-Path -Path $using:rebootKeyName) ) { New-Item -Path $using:rebootKeyName -Force } Set-ItemProperty -Path $rebootKeyName -Name $using:rebootVarName -value 1 $global:DSCMachineStatus = 1 } GetScript = { return @{result = 'result'}} } } if( $Packages -ne $null ) { $clonedPackageList = [System.Collections.ArrayList]@() [uint16]$i = 0 # set Rank attribute to allow a later ordering foreach ($p in $Packages) { # Remove Case Sensitivity of ordered Dictionary or Hashtables $p = @{}+$p # counter to keep original list order on equal rank values $i++ if( [string]::IsNullOrWhiteSpace($p.Rank) ) { # set default Rank to 1000 $p.Rank = [UInt64](1000 * 100000 + $i) } else { $p.Rank = [UInt64]($p.Rank * 100000 + $i) } $clonedPackageList.Add( $p ) } foreach ($p in ($clonedPackageList | Sort-Object {[UInt64]($_.Rank)}) ) { $p.Remove( 'Rank' ) $executionName = $p.Name -replace '\(|\)|\.| ', '' $executionName = "Chocolatey_$executionName" $p.ChocolateyOptions = [hashtable]$p.ChocolateyOptions if (-not $p.ContainsKey('Ensure')) { $p.Ensure = 'Present' } if( $Software -ne $null ) { $p.DependsOn = "[ChocolateySoftware]$chocoSwExecName" } [boolean]$forceReboot = $false if ($p.ContainsKey('ForceReboot')) { $forceReboot = $p.ForceReboot $p.Remove( 'ForceReboot' ) } (Get-DscSplattedResource -ResourceName ChocolateyPackage -ExecutionName $executionName -Properties $p -NoInvoke).Invoke($p) if ($forceReboot -eq $true) { $rebootKeyName = 'HKLM:\SOFTWARE\DSC Community\CommonTasks\RebootRequests' $rebootVarName = "RebootAfter_$executionName" Script $rebootVarName { TestScript = { $val = Get-ItemProperty -Path $using:rebootKeyName -Name $using:rebootVarName -ErrorAction SilentlyContinue if ($val -ne $null -and $val.$rebootVarName -gt 0) { return $true } return $false } SetScript = { if( -not (Test-Path -Path $using:rebootKeyName) ) { New-Item -Path $using:rebootKeyName -Force } Set-ItemProperty -Path $rebootKeyName -Name $using:rebootVarName -value 1 $global:DSCMachineStatus = 1 } GetScript = { return @{result = 'result'}} DependsOn = "[ChocolateyPackage]$executionName" } } } } } |