winget-cli
winget-cli copied to clipboard
winget should not install an already installed package
Description of the new feature/enhancement
winget should check if an application is already installed before it runs the installer
Proposed technical implementation details (optional)
check for installed software (could be a registry key) before you run the install command.
example: if the winget install <software>
is run once, then the next time it runs, it should prompt that the <software>
is already installed and not proceed to reinstall it again.
Current implementation will reinstall the software over and over:
PS C:\Windows\system32> winget install "Visual Studio Code"
Found Visual Studio Code [Microsoft.VisualStudioCode]
This application is licensed to you by its owner.
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages.
Downloading https://az764295.vo.msecnd.net/stable/3c4e3df9e89829dce27b7b5c24508306b151f30d/VSCodeUserSetup-x64-1.55.2.exe
██████████████████████████████ 68.9 MB / 68.9 MB
Successfully verified installer hash
Starting package install...
Successfully installed
PS C:\Windows\system32> winget install "Visual Studio Code"
Found Visual Studio Code [Microsoft.VisualStudioCode]
This application is licensed to you by its owner.
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages.
Downloading https://az764295.vo.msecnd.net/stable/3c4e3df9e89829dce27b7b5c24508306b151f30d/VSCodeUserSetup-x64-1.55.2.exe
██████████████████████████████ 68.9 MB / 68.9 MB
Successfully verified installer hash
Starting package install...
Successfully installed
There may be cases where a subsequent install is intentional. A user might be attempting a downgrade scenario.
We might also prompt "Did you want to upgrade?" or something like that as well.
Can we add option reinstall or flag --force?
We should notify the user that the package is already installed and inform them it's possible to use "upgrade". We will still likely keep the --force
option for install, and may add this to upgrade. There are scenarios like an unknown version that might be helped out in this case. It might seem a bit strange in the case it's actually a downgrade. That might be a case where we can't detect when the version is unknown, but if the version is known, we might recommend using force as well.
How about:
The current version is installed on the system:
>winget install "visual studio code"
Warning: Microsoft Visual Studio Code [Microsoft.VisualStudioCode] is already installed.
No upgrade is available.
>
An upgrade is available:
>winget install "visual studio code"
Warning: Microsoft Visual Studio Code [Microsoft.VisualStudioCode] is already installed.
Upgrading Microsoft Visual Studio Code [Microsoft.VisualStudioCode]
Found Microsoft Visual Studio Code [Microsoft.VisualStudioCode] Version 1.62.1
This application is licensed to you by its owner.
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages.
Downloading https://az764295.vo.msecnd.net/stable/f4af3cbf5a99787542e2a30fe1fd37cd644cc31f/VSCodeUserSetup-x64-1.62.1.exew
██████████████████████████████ 76.2.8 MB / 76.2 MB
Successfully verified installer hash
Starting package install...
Successfully installed
>
We could optionally add a setting for the default behavior. The default setting would be to perform the upgrade, users could also specify not automatically running the upgrade. In that case, the user would be informed an upgrade is available, but they would need to run the upgrade command themselves in that case:
>winget install "visual studio code"
Warning: Microsoft Visual Studio Code [Microsoft.VisualStudioCode] is already installed.
An upgrade is available.
Found Microsoft Visual Studio Code [Microsoft.VisualStudioCode] Version 1.62.1
>
I like this one. makes more sense
We could have three settings "automatic-upgrade", "inform-only", and "prompt" which could give a [Y] | [N] option for the upgrade. Note this would also be impacted by the future work for package pinning.
i'm extremely frustrated that winget is bundled with windows 11 by default, built on a stolen idea, and awfully incompetently executed.
meanwhile, the great scoop community which does not have weird bugs like this is worried the'll be exticted by microsoft.
the end result is that all windows users will get worse in the end. https://github.com/ScoopInstaller/Scoop/issues/3992
@keentext please stop showing your frustration on every issue.
+1 here.
My scenario: I'm creating my own windows dotfiles
repo. I would like it to have a declarative definition of my environment. Kind of a poor's man puppet/cheff recipe. I thought it would be trivial with winget and a install.ps1
:
winget install Notepad++.Notepad++
winget install Docker.DockerDesktop
winget install minikube
(...)
The thing is, Docker may require a restart, which breaks blocks minikube
install. That is something I can handle by manually re-running the script. Nonetheless, every already installed app will attempt a reinstall, including the 500mb Docker wich gets downloaded again and it takes some time...
My script is meant to install, not upgrade the components. To upgrade I already have winget upgrade
command.
Others mentioned a command to install or upgrade winget install --upgrade
. I would find that usefull too.
These are the semantics that feel natural to me and would allow me to script my environment:
-
winget install pkg
: Install if not installed (never upgrade): -
winget install pkg --force
: Reinstall, or upgrade (IMO) -
winget install pkg --upgrade
: Install only if not installed, upgrade if newer available, do nothing if already on latest.. -
winget upgrade pkg
: Upgrade if installed, fail if not installed.
+1 here.
My scenario: I'm creating my own windows
dotfiles
repo. I would like it to have a declarative definition of my environment. Kind of a poor's man puppet/cheff recipe. I thought it would be trivial with winget and ainstall.ps1
:winget install Notepad++.Notepad++ winget install Docker.DockerDesktop winget install minikube (...)
The thing is, Docker may require a restart, which breaks blocks
minikube
install. That is something I can handle by manually re-running the script. Nonetheless, every already installed app will attempt a reinstall, including the 500mb Docker wich gets downloaded again and it takes some time...My script is meant to install, not upgrade the components. To upgrade I already have
winget upgrade
command. Others mentioned a command to install or upgradewinget install --upgrade
. I would find that usefull too.These are the semantics that feel natural to me and would allow me to script my environment:
winget install pkg
: Install if not installed (never upgrade):winget install pkg --force
: Reinstall, or upgrade (IMO)winget install pkg --upgrade
: Install only if not installed, upgrade if newer available, do nothing if already on latest..winget upgrade pkg
: Upgrade if installed, fail if not installed.
this seems like the best solution to me.
- Default behavior doesn't needlessly install already installed apps
- You can re-install if you need (troubleshooting? e.g downgrounding? can use --version to specify in combination with --force?)
- You can guarantee by scripts end (I also use winget in various scripts) that the image a) has every program installed, b) are all up-to-date, c) doesn't take any longer then needed and d) no settings files etc for the apps are over-written (which currently happens for some apps when installing over the top of the currently installed app)
in before "you can use a combination of winget list, winget upgrade and winget install in a script to achieve this already'
Just in case somebody needs a workaround for a script:
set app=Microsoft.DotNet.Runtime.6
winget list %app% | findstr /c:"No installed package found" /c:"Es wurde kein installiertes Paket gefunden" > nul && (
winget install %app%
) || (
winget upgrade %app%
)
Change it to your wanted app.
Also you have to change the findstr
search text if you need a different/further language than English/German.
Of course it would be way better if winget had a simple flag or command to avoid such mess 😉
If apps don't set the "DisplayVersion" in Win Registry, isn't possible to winget to get the version from the EXE using PowerShell command?
It is possible to get the "file version" from an .exe, but that doesn't always correlate to the registry entries that are used to display package versions in Windows Apps & Features. That could also lead to other unintended consequences when the package does decide to write something to the registry. There are also cases where there is a "marketing version" for a product that publishers prefer to display to users. Sometimes a program will also display a different version itself than the file version.
There are just too many edge cases that lead to unreliable or confusing behavior for users which is why we defer to the version reported to Windows Apps & Features, and we allow a different "marketing version" to be displayed in the manifest than the version reported in the registry. The .NET packages are a perfect example of that use case as well.
in my opinion the moment an app is installed with winget (just like choco) a version is stored either in a manifest file or in the registry so that the next time winget will parse the app version prior to decide what to do with the install option
The issue with that is it doesnt take into account anything that may happen outside of winget between runs, meaning things can get out of sync quite fast depending on the installed apps and their hastiness of automatically updating or users not bothering to use winget and just updating something manually. It would basically lock people into only using winget or never having winget work correctly
in my opinion the moment an app is installed with winget (just like choco) a version is stored either in a manifest file or in the registry
In a way, it already does that @besmirzanaj. When you install a store app, the store has its's own registry. If it is a winget manifest, then is tracked in the "Add/Remove Programs" windows registry. I think there is no technical barrier preventing to implement this. The problem is the different visions & expectations of what each command should do between previous version and users coming from different ecosystems, including former winget versions.
@yao-msft can we take a look at the new spec?
TLDR;
If you call install <package>
and a version of that package is already installed, we will switch to the upgrade flow.
That should also be able to honor the pinning feature currently in progress:
- #476
Adding "--force" will essentially force the install flow rather than switching to the upgrade flow.
If you call install
and a version of that package is already installed, we will switch to the upgrade flow.
That's disappointing. Wasn't this issue about how winget install
should fail if the app is already installed? (no matter which version).
I already explained myself in this comment?
Muscle memory seems to be driving this behavior more than anything else. I'd like to help people fall into the "pit of success" here. If a user is asking for a thing to be installed, and the latest version is present (or in the future, the pinned version is present) then it would essentially be a "no-op". If the package isn't pinned, and it's an "older" version, then the action would be upgrade.
We could certainly consider a setting to change the behavior. A user could essentially say "I don't want an upgrade if any version of a package is installed and I try to install it again", but the default would be if a user tries to install an existing package, WinGet would upgrade it.
If we had such a "setting", then it makes sense to also have an argument that could override the default behavior or the behavior in a user's settings.
A setting is persistent, which is not really script-friendly, or at least a second class citizen. Would force me to do read-setting; store-somewhere; set-new-setting; try{ install } finally{ set-previous-setting }
in each script. Not really Ctrl-C
friendly.
I may settle with an argument like winget instal XX --no-upgrade
.
- Choco and scoop install fails if already installed.
-
Apt-get install XX
does upgrade if installed, but provides a--no-upgrade
option.
I like the idea of following prior art to avoid some muscle memory confusion "--no-upgrade" makes sense as an argument to "override" settings if they are different in my opinion.
i dont get why reinvent the wheel. if i want to install something, just return "already installed. bye". thats all. no need to trigger a upgrade or error message. makes our scripts easier.
currently checking each package before installing...
winget list Git.Git || winget install --accept-package-agreements --accept-source-agreements --exact --silent -q Git.Git