PowerShell cmdlets #1407
PowerShell cmdlets #1407
Conversation
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
This comment has been hidden.
Added my feedback
|
|
||
| ```PowerShell | ||
| Get-WinGetSource | convertto-json -compress |
Since this would entirely rely on the output object structure this approach could break easily. It might make more sense to handle this via a -Raw parameter, e.g.
Get-WinGetSource -RawThe cmdlets should emit .NET Objects (for consumption by other PowerShell cmdlets) along with JSON only where necessary.
NOte - if the intention is to handle cmdlets using Crescendo - then this can be met, provided the team do a good job at writing the necessary output handelers. And for the record, with Cresendo, this is NOT an easy task unless you are outstandingly good with regular expressions.
With that said, the cmdlets must emit objects - and some of those objects can contain json where json is relevant.
| ``` | ||
| **Parameters** | ||
|
|
||
| -Output |
-Path and -LiteralPath might be better parameter names for -Output. See Export-Csv
@megamorf what is the difference between the two?
Per convention, -Path accepts and interprets wildcards and globs. LiteralPath does not. There's probably official docs for this as it's very standard
Correct. The official documentation says the following:
Unlike Path, the value of the LiteralPath parameter is used exactly as it is typed. No characters are interpreted as wildcards. If the path includes escape characters, use single quotation marks. Single quotation marks tell PowerShell not to interpret any characters as escape sequences.
Why is that important? Let's consider that you have a folder with square brackets or an asterisk in its name. -Path will treat that as an expression rather than a true representantion of the path. Users have learned to use -LiteralPath when they literally want PowerShell to treat the user specified path as it is.
OK, so rather than "-Output" I believe what I'm reading is we should support both "-Path" and "-LiteralPath". Is it safe to assume PowerShell handles the wildcards when "-Path" is used?
So far as I can recall, -Path takes a wildcarded string and the cmdlet does the variable expansion.
OK, so rather than "-Output" I believe what I'm reading is we should support both "-Path" and "-LiteralPath". Is it safe to assume PowerShell handles the wildcards when "-Path" is used?
AFAIK the -Path string is passed to the so called "provider" and the interpretation of wildcards is up to the implementation of that provider. PowerShells "path-related" cmdlets can interact with multiple providers, e.g. the Certificate Store, ActiveDirectory, the registry OR the filesystem. So the meaning of * may be different for an NTFS filesystem path / provider implementation than for the registry or for an ActiveDirectory LDAP path. It would be best to speak to the professionals, PowerShell team, about their preference here. Another existing cmdlet that creates a file and writes content to it is Set-Content - it too supports -Path and -LiteralPath but when trying to use it with a registry-path I got an error that the functionality is not implemented by the provider - similar to how winget wouldn't support exporting a packageset to the registry or certificate store I imagine:
❯ Set-Content -path "HKCU:\Software\XD" -Value 'kek'
Set-Content: Cannot use interface. The IContentCmdletProvider interface is not implemented by this provider.| >Note: The current behavior for `winget show vscode` would look like the example below. | ||
| ```PowerShell | ||
| Find-WinGetPackage -Moniker vscode | Get-WinGetPackageVersion -Detail | ||
| ``` | ||
|
|
||
| >Note: The current behavior for `winget show vscode --versions` would look like the example below. | ||
| ```PowerShell | ||
| Find-WinGetPackage -Moniker vscode | Get-WinGetPackageVersion -All | ||
| ``` |
This is valid PowerShell code but needlessly complicated from a user experience perspective. Many users will expect these actions to be done with a single command. It'll be interesting to see what feedback you'll get here :-)
Find-Package should, uhh, find packages and return all the information. C/F Find-Module. Please do not introduce needless complexity where it can be avoided.
I disagree. AFAIK winget repositories use a cached index to speed up searches. It makes a ton of sense to return only the minimal, cached set of data first and then get all the information (which is an expensive operation) only for the package you're really interested in. Other existing cmdlets such as Get-ADUser and Get-WindowsDriver take a similar approach for performance and server-load reasons.
If the approach is to return a minimal amount of properties, then two things:
- The Find-WinGetPackage should return enough properties, by default, to be useful. As you mantion, like Get-ADuser etc.
- If there are more properties not returned by default - then use a -Property parameter to specify which optional properties to return.
In this case, I'd argue that the version of a package is important and probably should be returned by default.
There are two issues therefore: what properties get returned by default and how to get more. I do not support adding cmdlets in the proposed manner.
Just checking, since it's not in this spec file, these cmdlets will be targeting Windows PowerShell (5.1), not PowerShell Core, right? We can't guarantee that PowerShell Core is installed since it's not shipped with Windows (and it isn't usually installed on systems that aren't used for development unless you work at a really hip company).
I sure hope not. It would be crazy, this long after PowerShell 7 has shipped to be so backwards as to ONLY target WIndows PowerShell.
I sure hope not. It would be crazy, this long after PowerShell 7 has shipped to be so backwards as to ONLY target WIndows PowerShell.
I'd disagree. For all that Microsoft want PowerShell 7 to be the future, I don't know a single enterprise that's using it, precisely because it's not a backwards compatible, drop in replacement for PowerShell 5. In every current, supported version of Windows, PowerShell 7 is a side by side addon and the chance of MS actually ever releasing an in place upgrade from PS5 to PS7+ is slim to none, so PowerShell 5 is going to continue to be what is used by enterprise admins for years to come.
So yeah, IMHO this module absolutely needs to be PS 5.1 compatible.
@JustSomeGuyNZ I agree with your point that there are companies that will never allow PS 7 to be deployed. I do not get the reason to be honest. I consult customers to deploy it widely just for the same of improved commandlets like test-connection etc.
It's an MSI package, easy to deploy with a small mst. What is their issues with PS 7? Do you have more information about it? I just know it is a controversy because of patchmanagement.org and also some ConfigMgr MEMCM pals.
It's not a drop in replacement, and it breaks backwards compatibility. In my experience enterprise IT is pretty resistant to change that breaks backwards compatibility and unforced changes lol.
I've been engaging the PowerShell team in the discussions with our design, and the crescendo team to aid in rapid prototyping. We will follow their guidance with respect to which versions of PowerShell behave differently so we can maintain the greatest compatibility level. I am certainly not a PowerShell expert, so I'm learning from the experts on that front. I wanted to get this draft out quickly so we could get community feedback. I'm building on the list of concerns brought up here so they can be clearly addressed in the document.
This is excellent news and much to be welcomed. Knowing what I do, Crescendo should provide a good way forward and helps to move this forward and makes the best out of the decision to do this all in C++. But we are where we are, and Crescendo does look promising as a way forward. It also gives the winget team to re-write certain cmdlets in C# where that makes business sense.
As I stated a while ago, creating the object model is very important. With Crescendo, as I understand it, you use regular expressions to create objects that the Crescendo-generated cmdlet emits. As I have said elsewhere, this is going to be a very difficult task to do well and completely - string to object translation is not an exact science. Thus my first concern is the objects emitted. It should be a goal for winget-ps to emit objects that are as rich and functional as those emitted by other modules and usable in rich cross-silo scenarios.
The second concern is over verb usage. As mentioned a long time ago, the subcommand of winget do not line up completely with PowerShell standard verb naming. For example, the show command in winget should probably be get. And hash should be something else. I would like to see the command to verb translation table - and please, please, please only uses approved verbs in all cmdlets.
I look forward to seeing how this progresses.
I've been going through the process of learning the PowerShell verbs and continuing to expand the draft to others so we can get a sense of the best verbs and behaviors. First impressions are very valuable in this area. There is definitely some impedance to overcome between the .exe cli syntax and PowerShell. We're heads down on the v1.1 release, and then I'll have more time to dedicate to fleshing this out. We have been discussing the rich object model needed for a good PowerShell experience.
The verb choice is a vital component of the sacred vow. IT Pros would expect to use certain verbs and certain parameter names names. To create a truly great Powershell module means using approved verbs. :-)
|
Looks like a solid first draft overall. I have noticed there is no mention of ParameterSets, but some cmdlets parameters should probably be mutually exclusive e.g. these three wherever they are used: I think a user should not be able to specify more than one of these for any given command. |
|
Just checking, since it's not in this spec file, these cmdlets will be targeting Windows PowerShell (5.1), not PowerShell Core, right? We can't guarantee that PowerShell Core is installed since it's not shipped with Windows (and it isn't usually installed on systems that aren't used for development unless you work at a really hip company). |
These cmdlets should be validated and fully tested for both Windows PowerShell and PowerShell 7.x and should NOT rely on the PowerShell 7 compatibility mechanism. MUCH more importantly, the team should not use techniques that only work with Windows PowerShell. The WSUS team's cmdlets and a few others, use classes that exist in .NET Framework, but don't in (open source) .NET. That makes it much more complex for IT Pros who do use PowerShell 7 when it doesn't need to be that way. Please ensure the cmdlets can run on both versions of PowerShell. That is not to say that many (most?) users at first would be using Windows PowerShell. But PowerShell 7 has been around for a couple of years (7.0, 7.1, and very soon 7.2). But if my book sales are anything to go by, there are many IT pros investigating and moving across to PowerShell 7 and it would be wrong to just not to take advantage. And in enterprise arenas, there are many PowerShell 7 features that would be useful in a Package Management Scenairo. |
I agree with this.
Kind of off-topic, but why the heck isn't it shipped with Windows then? I don't mind the changes in Core, but I don't use it because I can't guarantee it will be there when I run something. I can guarantee Windows PowerShell is there, and if I need to install a language, why not one I like? (I kid. but something like PowerShell needs to be in the box to be of the best use).
Which ones are you thinking of? Just curious. |
I can only agree, but if it were that simple, they would have done it a long time ago. I suspect it's mainly due to licensing. .NET and PowerShell are both open source and not a proprietary Microsoft Product. I can only imagine the number of lawyers it would take to get this done. I suspect it will happen, just not soon. There is also t;he issue of support - if it;s in the box, MSFT needs to support it. So NOT simple - In the meantime, there are numerous ways to install it (including WInget). And despite this, I hope that the team doesn't do anything that would stop winget's ability to work with PowerShell 7.
Using |
|
Parallel install is a challenge. MSIX supports up to five concurrent installs (I believe). MSI is a singleton scenario due to msiexec. We also don't know what would happen with parallel installs in a dependency required scenario. |
| Get-WinGetPackageVersion | ||
| ``` | ||
|
|
||
| -Detail |
it would be good to elaborate what these different parameters do. since the name of the cmdlet includes version i'm a little puzzled why you need a version parameter
This is an interesting position. If I think about this in text, it seemed logical for one to say "I want software by Adobe with Acrobat in the name". This seems counter to that proposal. It would also be a breaking change to implement this mutual exclusion in the command line interface. I'd like to avoid breaking changes until we're ready to make a 2.0 release. I also want to clarify it's not a function of a date on a calendar, but more about the right time to take in a series of breaking changes. We should ensure that the 1.x versions are stable enough to go into a bug fix support mode when we make a semantically different release. |
I, uh, wasn't even aware you could currently do a query like this: |
|
A better approach might be to do this: |
True - but you could (again in an Enterprise scenairo) install packages on multiple systems in parallel - and given that the actual installation time is the bottle neck, updating multiple machines at once could deliver significantly faster installations. |
That'd be quite a lot of extra work, to implement a (proprietary) querying and filtering syntax for winget. The
Respectfully, I think you're getting lost and arguing about details that don't actually matter. Even the old versions of PowerShell can run arbitrary commands against a list of computers in parallel just using the old Let's focus on getting a good and extensible v1 of the winget PowerShell cmdlets finalized before we dive into fantasies about what non-essential functionality we could possibly tack on in the future. The cmdlets should align somewhat with the capabilities of the winget.exe program and there should probably not be too much custom functionality directly embedded into them that the exe doesn't have. - just for consitency. Anything else we can use the existing capabilities of PowerShell for to accomplish, e.g. parallel runs on many computers, complex filter logic or runspaces or whatever. |
|
Yes, the filter parameter is based on existing methods built into PowerShell (and referencing late vs early filtering). The Get-ChildItem cmdlet, for example, uses a -Filter parameter, although it uses a string vs a script block, A string, as you mention, is a better choice especially as a string is serializable which might be relevant for cross-host action. If we are building PowerShell cmdlets, I would like to see the filter cmdlet follow PowerShell syntax - it's less for the IT Pro to learn and is an approach in keeping with the sacred vow. While Other query mechanisms might be interesting, they impose a learning curve which can be avoided)., I also take the point about v1 vs v2. I agree totally with getting a decent set of cmdlets out to begin with and improve them in V2. How about this - a) make sure that V1` produce all the properties necessary to pass to Where-Object et al (ie later filtering). And define a -Filter parameter that does filtering in V2. The PowerShell team might be able to point to some of the similar code as a head start on the coding. I do not know Crescendo enough, but could the filter be inserted into the crescendo module and NOT into the exe itself? |
|
In the context of PowerShell commandlets for WinGet will there be a method to following scenario?
Winget can read the import file txt file: example of inputfile.txt: inputfile.txt CSV file XML file: Result: this will install (or alternatively) upgrade all packages that contained in the file. Usecase: |
I'm not a PowerShell expert, but I would expect you could iterate over the list and run the install command for each of them. The "import" format for a collection of packages is JSON with a schema, so that is the "current" preferred method, but I believe PowerShell will open up a myriad of new possibilities. |
| **PowerShell Cmdlet** | ||
|
|
||
| ```PowerShell | ||
| Uninstall-WinGetPackage |
The Uninstall-WingetPackage cmdlet should definitely make use of PowerShells' ShouldProcess feature wherein you are asked to confirm every processed object (package) by default unless you pre-approve all operations with the -Confirm:$False parameter. Especially because of scenarios like the below example: Get-WingetPackage xbox | Uninstall-WingetPackage, because wingets' package name searching and matching often yields unexpected results a user could easily uninstall more packages than intended if no confirmation prompt occurs.
In a perfect world, Install-WinGetPackage AND Uninstall-WInGetPackage` would support all the common parameters, including both -WhatIfand-Confirm``.
What I don't know is how that would work with Crescendo. The Crescendo wrapper may be able to say "We are going to call winget now" but the internal winget processing probably would not be easy to expose to the ShouldProcess mechanism.
| ``` | ||
| **Parameters** | ||
|
|
||
| -Output |
OK, so rather than "-Output" I believe what I'm reading is we should support both "-Path" and "-LiteralPath". Is it safe to assume PowerShell handles the wildcards when "-Path" is used?
AFAIK the -Path string is passed to the so called "provider" and the interpretation of wildcards is up to the implementation of that provider. PowerShells "path-related" cmdlets can interact with multiple providers, e.g. the Certificate Store, ActiveDirectory, the registry OR the filesystem. So the meaning of * may be different for an NTFS filesystem path / provider implementation than for the registry or for an ActiveDirectory LDAP path. It would be best to speak to the professionals, PowerShell team, about their preference here. Another existing cmdlet that creates a file and writes content to it is Set-Content - it too supports -Path and -LiteralPath but when trying to use it with a registry-path I got an error that the functionality is not implemented by the provider - similar to how winget wouldn't support exporting a packageset to the registry or certificate store I imagine:
❯ Set-Content -path "HKCU:\Software\XD" -Value 'kek'
Set-Content: Cannot use interface. The IContentCmdletProvider interface is not implemented by this provider.| -Exact | ||
|
|
||
| -Interactive | ||
|
|
-Silent and -Interactive is another opportunity for mutually exclusive parametersets
A string-parameter with a validateset would also be an option, e.g. -InstallationMode Silent vs -InstallationMode Interactive but I have no strong preference. If the parameter was an enum it could be combined with Log to allow logic-OR-ing the flags or providing multiple in a list that are then OR-ed internally: -InstallationMode Silent, Log
Are multiple parameter sets possible with Crescendo?
Yes, that's my current understanding.
Maybe for -Silent and -Interactive would be better to have a single switch parameter
I would expect Install-WingetPackage to have a -Name parameter which is of the type [string[]]. Rather than ask Winget to worry about XML, CSV,(and probably JSON, let me workout where the strings come from and just pass them to the cmdlet as strings. |
|
I'm going to try and update this PR and convert to a draft. |
|
Here is the Fork/Branch with the "Fix, Hack, Learn" project for a PowerShell module. This is where I'm doing some learnings. https://github.com/denelon/winget-cli/tree/PowerShellFHL/PowerShell |
|
@doctordns & community We've been working on building some of the cmdlets out. At lest one of the team members feels strongly that we should be using the "get" verb and not necessarily the "find" verb for Get-WinGetPackage Find-WinGetPackage Get-WingetInstalledPackage Find-WingetInstalledPackage I think one of the challenges is when we execute The concerns are whether one verb or another makes better sense in the context of "I want to find something installed on my machine" and "I want to find something I could install on my machine". The differing opinions on this are whether the "Find" verb is used often enough to justify having both "Find" and "Get". One of the options considered was also having an alias from one to the other.
|
#674
Microsoft Reviewers: Open in CodeFlow
The text was updated successfully, but these errors were encountered: