- Search Event Logs and error codes with Netikus.net System32 - Thu, Jan 10 2019
- Netikus.net IPMon+ – GUI for ipmon.exe - Tue, Nov 20 2018
- Understanding PowerShell Begin, Process, and End blocks - Mon, Oct 15 2018
In my previous post, we talked about the structure of our internal Chocolatey packages. This includes understanding the basics of the nuspec specification and the binary package manager Chocolatey.
As a reminder, here is our internal folder structure of the packages we need to generate. We have a top-level Packages folder followed by our package name. Under each package name, we have a nuspec XML file and a subfolder called tools that contains our chocolateyInstall.ps1 file.
|__Packages |__MyLocalChocolateyPackage |__MyLocalChocolateyPackage.nuspec |__tools |__chocolateyInstall.ps1 |__AnotherPackage |__AnotherPackage.nuspec |__tools |__chocolateyInstall.ps1
Now that we understand the basics of our nuspec packages, we now need to call our New-LocalChocoPackage.ps1 script that will loop through a directory of packages and generate new NuGet package (nupkg) files.
<# .SYNOPSIS Creates new internal Chocolatey package(s) .DESCRIPTION Creates new internal Chocolatey package(s) from nuspec definition files .EXAMPLE C:\choco_packages\source_packages\ contains the following package directories: OfficeProfessionalPlus2013x64 OfficeProfessionalPlus2013x86 And running the New-LocalChocoPackage command below... New-LocalChocoPackage -SourcePath C:\choco_packages\source_packages\ OutputPath C:\choco_packages\new_packages\ ...will generate two nupkg files in C:\choco_packages\new_packages\: OfficeProfessionalPlus2013x64.2013.64.20180717.nupkg OfficeProfessionalPlus2013x86.2013.64.20180717.nupkg #> function New-LocalChocoPackage { [CmdletBinding(DefaultParameterSetName = 'Parameter Set 1', PositionalBinding = $false, HelpUri = 'http://www.microsoft.com/', ConfirmImpact = 'Medium')] Param ( # Param1 help description [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Parameter Set 1')] [ValidateNotNull()] [ValidateNotNullOrEmpty()] [string]$SourcePath, # Param2 help description [Parameter(Mandatory = $true, Position = 1, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Parameter Set 1')] [ValidateNotNull()] [ValidateNotNullOrEmpty()] [string]$OutputPath ) begin { Write-Verbose -Message 'Building local Chocolatey packages' if (-not (Test-Path $OutputPath)) { New-Item $OutputPath -Type Directory Write-Verbose -Message "Creating $OutputPath" } $pkgs = Get-ChildItem -Directory $srcPath } process { foreach ($pkg in $pkgs) { $pkgPath = "$SourcePath\$pkg" Push-Location $pkgPath Write-Verbose -Message "Trying to build NuGet package for $pkg" choco pack --outputdirectory "$OutputPath" --use-system-powershell if ($LASTEXITCODE -ne 0) { Write-Warning -Message "Failed to build Chocolatey package for $pkg" Write-Error -ErrorRecord $Error[0] Pop-Location Exit -1 } Pop-Location } } end { Write-Verbose -Message 'Successfully built Chocolatey packages' } }
This PowerShell function takes two parameters: SourcePath and OutputPath. The SourcePath parameter is the root path of our package(s). The OutputPath is the location where we want to output our NuGet packages to.
The function first makes sure our OutputPath is available, and if not, it creates it. Next, it loops through our SourcePath packages (package folders) and uses the choco command-line interface (CLI) to build our NuGet packages.
We use the choco CLI utility to "pack" our nuspec definition file into a new NuGet package that ends in a .nupkg extension. This package is essentially a zipped container with a .nupkg extension. This package contains our definition file metadata as well as our chocolateyInstall.ps1 PowerShell script.
To easily inspect our .nupkg, we can use the NuGet Package Explorer, which we can install using Chocolatey:
choco install nugetpackageexplorer
After installing this, you can open the generated nupkg files using the Package Explorer to see their contents.
After we have generated our internal NuGet Packages, we can use the following PowerShell function to install them.
<# .SYNOPSIS Installs internal Chocolatey package(s) .DESCRIPTION Installs internal .nupkg Chocolatey package(s) .EXAMPLE Install-LocalChocoPackage -PackageSource package-build-output-directory #> function Install-LocalChocoPackage { [CmdletBinding(DefaultParameterSetName = 'Parameter Set 1', PositionalBinding = $false, HelpUri = 'http://www.microsoft.com/', ConfirmImpact = 'Medium')] Param ( # Param3 help description [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Parameter Set 1')] [ValidateNotNull()] [ValidateNotNullOrEmpty()] [string]$PackageSource ) Write-Verbose -Message "Current package: $PackageName" $Packages = Get-ChildItem -Path $PackageSource foreach ($package in $Packages) { Write-Verbose -Message "choco install -y $($package.FullName)" choco install -y $($package.FullName) if ($LASTEXITCODE -eq 3010 -or $LASTEXITCODE -eq -2147205120) { Write-Information -Message 'Reboot pending...' Write-Information -Message 'Please reboot the machine and then rerun this script' Write-Information -Message 'ACTION REQUIRED -- reboot pending' Exit -1 } elseif ($LASTEXITCODE -ne 0) { Write-Warning -Message "FAILED TO INSTALL $PackageName" Write-Error -ErrorRecord $Error[0] Exit -1 } } Write-Verbose -Message 'Successfully built Chocolatey packages' }
Install-LocalChocoPackage has a single mandatory parameter: PackageSource.
PackageSource is the location of the nupkgs you generated earlier. Typically, this parameter's value would be the same as the OutputPath you passed to the New-LocalChocoPackage function.
That's it! You've successfully built and installed your own internal Chocolatey packages. You are one step closer toward automating your third-party software installations on your systems.
Subscribe to 4sysops newsletter!
Chocolatey is extremely powerful on its own, but having the ability to generate your own internal packages puts Chocolatey on a whole new level.
Hi
First at all, you are missing a ‘}’ at the end. Secondly, how about an example on how to use this? I’m a newbie in PowerShell. I tried saving your script into a filed called: “install-local.ps1”.
Inside that file I put this at the end:
Install-LocalChocoPackage “C:\Users\my_user\Desktop\local_choco\paint.net.portable”
I previously downloaded paint.net.portable from here:
https://github.com/SebastianK90/chocolateyautomaticpackages/tree/master/paint.net.portable
Then I ran it as follows:
Set-ExecutionPolicy AllSigned
Set-ExecutionPolicy Bypass -Scope Process -Force; .\install-local.ps1
But now, I’m getting the error at the bottom of this message.
How can I solve it?
Best regards
Josef
Chocolatey v1.3.1
Installing the following packages:
C:\Users\my_user\Desktop\local_choco\paint.net.portable\legal
By installing, you accept licenses for the packages.
Chocolatey installed 0/0 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
Second path fragment must not be a drive or UNC name.
Parameter name: path2
WARNING: FAILED TO INSTALL
Write-Error : Cannot bind parameter ‘ErrorRecord’. Cannot convert the “System.Management.Automation.ParseException: At line:5 char:2
+ + .\install-local.ps1
+ ~
Missing expression after unary operator ‘+’.
At line:5 char:3
+ + .\install-local.ps1
+ ~~~~~~~~~~~~~~~~~~~
Unexpected token ‘.\install-local.ps1’ in expression or statement.
At line:6 char:2
+ + ~~~~~~~~~~~~~~~~~~~
+ ~
Missing expression after unary operator ‘+’.
At line:6 char:3
+ + ~~~~~~~~~~~~~~~~~~~
+ ~~~~~~~~~~~~~~~~~~~
Unexpected token ‘~~~~~~~~~~~~~~~~~~~’ in expression or statement.
At line:7 char:6
+ + CategoryInfo : SecurityError: (:) [], PSSecurityExcept …
+ ~
Missing expression after unary operator ‘+’.
At line:7 char:7
+ + CategoryInfo : SecurityError: (:) [], PSSecurityExcept …
+ ~~~~~~~~~~~~
Unexpected token ‘CategoryInfo’ in expression or statement.
At line:8 char:6
+ + FullyQualifiedErrorId : UnauthorizedAccess
+ ~
Missing expression after unary operator ‘+’.
At line:8 char:7
+ + FullyQualifiedErrorId : UnauthorizedAccess
+ ~~~~~~~~~~~~~~~~~~~~~
Unexpected token ‘FullyQualifiedErrorId’ in expression or statement.
at System.Management.Automation.AutomationEngine.ParseScriptBlock(String script, String fileName, Boolean interactiveCommand)
at System.Management.Automation.Runspaces.Command.CreateCommandProcessor(ExecutionContext executionContext, CommandFactory commandFactory, Boolean addToHistory, CommandOrigin origin)
at System.Management.Automation.Runspaces.LocalPipeline.CreatePipelineProcessor()
at System.Management.Automation.Runspaces.LocalPipeline.InvokeHelper()
at System.Management.Automation.Runspaces.LocalPipeline.InvokeThreadProc()” value of type “System.Management.Automation.ParseException” to type “System.Management.Automation.ErrorRecord”.
At C:\Users\my_user\Desktop\local_choco\install-local.ps1:49 char:38
+ Write-Error -ErrorRecord $Error[0]
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Write-Error], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.WriteErrorCommand
Sorry, I just saw that there is an example on the source comments. I will try it that way
I added the missing }. Thanks!
I wonder why your error occurred in line 5 because in the script of the article line 5 only contains a comment.
I guess you have to count after the comments
I don’t think so.
But anyway, I ran this differently:
Install-LocalChocoPackage -PackageSource “C:\Users\my_user\Desktop\local_choco\paint.net.portable”
Then I’m getting this:
Chocolatey v1.3.1
Installing the following packages:
C:\Users\my_user\Desktop\local_choco\paint.net.portable\legal
By installing, you accept licenses for the packages.
Chocolatey installed 0/0 packages.
See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).
Second path fragment must not be a drive or UNC name.
Parameter name: path2
WARNING: FAILED TO INSTALL
Install-LocalChocoPackage : Cannot bind parameter ‘ErrorRecord’. Cannot convert the “System.Management.Automation.ParseException: At line:5 char:2
+ + .\install-local.ps1
+ ~
Missing expression after unary operator ‘+’.
At line:5 char:3
+ + .\install-local.ps1
+ ~~~~~~~~~~~~~~~~~~~
Unexpected token ‘.\install-local.ps1’ in expression or statement.
At line:6 char:2
+ + ~~~~~~~~~~~~~~~~~~~
+ ~
Missing expression after unary operator ‘+’.
At line:6 char:3
+ + ~~~~~~~~~~~~~~~~~~~
+ ~~~~~~~~~~~~~~~~~~~
Unexpected token ‘~~~~~~~~~~~~~~~~~~~’ in expression or statement.
At line:7 char:6
+ + CategoryInfo : SecurityError: (:) [], PSSecurityExcept …
+ ~
Missing expression after unary operator ‘+’.
At line:7 char:7
+ + CategoryInfo : SecurityError: (:) [], PSSecurityExcept …
+ ~~~~~~~~~~~~
Unexpected token ‘CategoryInfo’ in expression or statement.
At line:8 char:6
+ + FullyQualifiedErrorId : UnauthorizedAccess
+ ~
Missing expression after unary operator ‘+’.
At line:8 char:7
+ + FullyQualifiedErrorId : UnauthorizedAccess
+ ~~~~~~~~~~~~~~~~~~~~~
Unexpected token ‘FullyQualifiedErrorId’ in expression or statement.
at System.Management.Automation.AutomationEngine.ParseScriptBlock(String script, String fileName, Boolean interactiveCommand)
at System.Management.Automation.Runspaces.Command.CreateCommandProcessor(ExecutionContext executionContext, CommandFactory commandFactory, Boolean addToHistory, CommandOrigin origin)
at System.Management.Automation.Runspaces.LocalPipeline.CreatePipelineProcessor()
at System.Management.Automation.Runspaces.LocalPipeline.InvokeHelper()
at System.Management.Automation.Runspaces.LocalPipeline.InvokeThreadProc()” value of type “System.Management.Automation.ParseException” to type “System.Management.Automation.ErrorRecord”.
At C:\Users\my_user\Desktop\local_choco\install-local.ps1:56 char:1
+ Install-LocalChocoPackage -PackageSource “C:\Users\my_user\Desktop\loc …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Write-Error], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Install-LocalChocoPackage
Hard to debug this if it is not clear to which lines the error messages refer to.
Ok, I found the source of your problem. You can’t use a path on the “install” argument. You need to specify either a path to a .nupkg or .nuspec file, which is now deprecated. Or you use the –source option
On my example, to install paint.net.portable from a local source, I just did:
choco install paint.net.portable –source “C:\Users\my_user\Desktop\local_choco\packages\paint.net.portable”
So, I guess you will have to modify your script in order to make it work.
Since I only want to install a package, this is enough for me.
Best regards
Josef