98

The command

choco list -lo

lists the installed packages. But how do I determine where a Chocolatey application installs? So far I've had to hunt around for them.

Some examples:

  • NUnit goes to Program Files (x86)
  • WGET goes to %ALLUSERSPROFILE%\chocolatey\bin and %ALLUSERSPROFILE%\chocolatey\lib\[Package Name]\tools
  • ConsoleZ went to %ALLUSERSPROFILE%\chocolatey\lib\[Package Name]\tools

Is there a flag on choco list that will tell me where they went? ChocolateyGUI doesn't seem to do this either.

Sort of like Debian's:

dpkg-query

Or RedHat's:

rpm -ql [package-name]

Or YUM's repoquery:

repoquery --list [package-name]

Homebrew:

brew list [package-name]

8 Answers 8

37

Currently, there is no way to do what you are asking.

Each Chocolatey package is unique in the sense that it could be a wrapper around an MSI or an EXE, or it could be a simple extraction of a compressed archive to a known location i.e. C:\tools, or it could be a PowerShell module that extracts to PSModulePath, or it could be something completely custom.

This is a side effect of the Windows ecosystem, where there are multiple ways to do the same thing. Chocolatey is trying to bring some sort of order to this by providing a mechanism to at least find all the packages that you want in one place, but there is only so much Chocolatey can do.

If you look at things completely differently, it is possible to pass installation arguments to a Chocolatey package using the following:

https://github.com/chocolatey/chocolatey/wiki/CommandsInstall#installarguments-optional---v09813

This could, in theory, alter the installation arguments of an MSI or EXE based Chocolatey package to change where the files are installed to. You can see an example of this approach being used here:

http://chocolatey.org/packages/VisualStudio2013Ultimate

However, this approach is limited. Not everyone takes the time like Matt to mention the possible installation arguments that are possible, and it is quite a convoluted process to extract the installation arguments that are possible to be sent into an MSI or EXE.

In terms of ChocolateyGUI, and as the current maintainer of that product, I can tell you that it does nothing clever in this area :-). It is simply a wrapper around the command line tools that Chocolatey provides, and aims to make it easier for people who don't like using the command line.

8
  • 2
    There is solution as chocolatey generates shim file for package which keeps the path to executable and exposes the target if called with --shimgen-noop switch, see my answer
    – maoizm
    Mar 2, 2017 at 9:18
  • 26
    Nearly 3 years later, this is still the thing I find most frustrating about choco: "installed a thing. now....where is it?" May 16, 2017 at 19:53
  • @BenCollins I'm assuming you've upgraded Chocolatey recently as well? It now reports where it installs things - and it has for almost a year now (since 0.9.10). github.com/chocolatey/choco/issues/689 May 16, 2017 at 22:26
  • 3
    "Software installed to '$toolsDir'" Gee, thanks Chocolatey.
    – blueben
    May 16, 2018 at 12:32
  • 2
    Maybe storing the installation log in some chocolatey directory and give users the ability to retrieve it by package name... Sep 17, 2018 at 8:54
8

I found some usefull stuff in

C:\ProgramData\chocolatey\logs\choco.summary.log
C:\ProgramData\chocolatey\logs\chocolatey.log

Surely, these logs contain lots of redundant (for this case) info. But at least they can be viewed to better understand what actually chocolatey does.

8

This is likely missing some results, but helped me locate some packages:

(Get-Content C:\ProgramData\chocolatey\logs\choco.summary.log) -match 'Software installed to'
2
  • For the specific package I was interested in, that file wasn't much help, but I did find the information in C:\ProgramData\chocolatey\logs\chocolatey.log (yes, the full log is in the same directory as the summary log!)
    – AJM
    Mar 7, 2023 at 19:07
  • If Chocolatey was installed with WingetUI: (Get-Content $env:LOCALAPPDATA\Programs\WingetUI\choco-cli\logs\choco.summary.log) -match 'Software installed to'
    – cachius
    Mar 14 at 14:31
7

If Chocolatey generates a shim for the package, e.g. yourprogram.exe you can tell the path to executable file by the following Powershell command:

$a="path to executable:"
(yourprogram --shimgen-noop | Select-String $a) -split $a | ForEach-Object Trim

This works only if shim is .exe file. This is very common, though some packages generate .ps1, .cmd or even .bat files. In these rare cases this recipe won't work.

5

Unfortunately, not that I know of. I believe the install directory is determined by the package itself. It's not defined in the .nuspec file, and I can't see anywhere that it's explicitly defined in the Chocolatey source code.

Source code: https://github.com/chocolatey/chocolatey

3
  • This is correct. Looking at the docs for creating a package you'll see that for most packages the MSI installer created by the original software creator defines the installation path. Chocolatey has no idea where the MSI puts files.
    – heavyd
    Jul 21, 2014 at 21:13
  • 1
    This is actually insane. I just installed a bunch of stuff from a choco package, now choco itself can't uninstall those packages and I need to manually find all of them.. Great. Aug 20, 2020 at 23:03
  • Well, Chocolatey GUI is a really bad tool and quite pathetic if it can't tell you where it installed something. This is the reason that package manager under Windows are horrible garbage compared to what you get on Linux. Software Management under Windows is a royal P.i.t.A. Jan 9, 2022 at 23:52
2
cinst notepadplusplus.install -ia "'/D=E:\SomeDirectory\npp'"

If it was an MSI, then usually you could pass -ia:

INSTALLDIR=""E:\SomeDirectory\npp""

 

0
0

Based on maoizm's fine answer, here is a command to iterate over all files in Chocolatey bin:

cd C:\ProgramData\Chocolatey\bin
$a="path to executable:"
dir *.exe |
 %{ $prog=$_
    $dest = (( ( ( & $prog --shimgen-noop) | select-string $a ) -split $a)[1]).Trim()
    [pscustomobject]@{ Shim=$prog.Name; target=$dest}
  } | Format-Table -AutoSize

[Related, but not an answer to the original question.] The following command helped me to remove all ghc-8.10.4 shims from my bin directory. Remove Echo to actually delete files:

cd C:\ProgramData\Chocolatey\bin
dir *.exe | 
 %{ $prog=$_ 
   ( & $prog --shimgen-noop) | 
   findstr "ghc-8.10.4" | 
   %{ Echo Remove-Item $prog } }
0

I wrote a Python script to handle this, based on @DonBecker 's answer

Here's a living gist: https://gist.github.com/tigerhawkvok/aad3f184b37bb869df5bd337d4b4c22e

But here's a static copy for this answer:

#!python3
import subprocess
import re
from pathlib import Path
import warnings
from typing import Optional
import argparse

def getChocoInstalledPath(pathComponent:Optional[str]= None) -> Path:
    """
    Spawn a subprocess to get the last installed path of a chocolatey package.

    Parameters
    ----------
    pathComponent : Optional[str]
        A known path component of the path to be found.
        If `None`, the last installed path is returned.

    Returns
    -------
    Path

    Raises
    ------
    ValueError
    """
    if pathComponent == "":
        pathComponent = None
    # TODO be clever about Chocolatey install path
    command = """(Get-Content "$env:PROGRAMDATA\chocolatey\logs\choco.summary.log") -match 'Software installed to'"""
    if pathComponent is None:
        command += " | Select-Object -Last 1"
    result = subprocess.run(["powershell", "-Command", command], capture_output= True, text= True, encoding= "utf-8", shell= True, check= True)
    stdout = result.stdout
    if pathComponent is not None:
        # Search for the path component
        found = False
        for entry in reversed(stdout.splitlines()):
            # Search most recent first
            if pathComponent in entry:
                stdout = entry
                found = True
                break
        if not found:
            raise ValueError(f"No path found containing substring `{pathComponent}`")
    # A single candidate line has been found
    output = re.search(r"Software installed to '(.*)'", stdout)
    if output is not None:
        # Do some path validation
        outPath = Path(output.group(1))
        if outPath.exists():
            if not outPath.is_dir():
                warnings.warn("The path found is not a directory")
            return outPath
        warnings.warn("The path found does not exist")
        return outPath
    raise ValueError("No path found")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description= "Get the path of a chocolatey install matching the pathComponent, or, if none provided, the last installed path")
    parser.add_argument('pathComponent', type= str, nargs= '?',
                    help='a known path component of the path to be found')
    args = parser.parse_args()
    print(getChocoInstalledPath(args.pathComponent))

You can save it as a CLI script or import getChocoInstalledPath and use that.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .