PSResourceGet icon indicating copy to clipboard operation
PSResourceGet copied to clipboard

Get-CredentialInfo cmdlet request

Open Stephanevg opened this issue 2 years ago • 14 comments

Prerequisites

  • [X] Write a descriptive title.
  • [X] Make sure you are able to repro it on the latest released version
  • [X] Search the existing issues.

Steps to reproduce

Hi,

I was following the this article in order to register an Azure artifact reposistory. It specifically mentions: You can also use with the -Credential parameter.

I used the following snippet to try the register the PsResource:


import-module Microsoft.PowerShell.PSResourceGet -force
$Credential = Get-Credential -UserName "[email protected]" -Message "Enter your ADO credentials" #generated the PAT as described in the article

$FriendlyName = "MyFriendlyName"
$ProjectName = "MyProjectName"

Register-PSResourceRepository -Name $FriendlyName -Uri "https://pkgs.dev.azure.com/$($ProjectName)/_packaging/$($ProjectName)/nuget/v3/index.json" -Credential $Credential

But I get the following error:

Cannot bind parameter 'CredentialInfo'. Cannot convert the "System.Management.Automation.PSCredential" value of type "System.Management.Automation.PSCredential" to type
     | "Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo".

I guess this is a

Expected behavior

It should register the repository

Actual behavior

Cannot bind parameter 'CredentialInfo'. Cannot convert the "System.Management.Automation.PSCredential" value of type "System.Management.Automation.PSCredential" to type
     | "Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo".

Error details

Exception             : 
    Type              : System.Management.Automation.ParameterBindingException
    Message           : Cannot bind parameter 'CredentialInfo'. Cannot convert the "System.Management.Automation.PSCredential" value of type "System.Management.Automation.PSCredential" to type "Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo".
    ParameterName     : CredentialInfo
    ParameterType     : Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo
    TypeSpecified     : psobject
    ErrorId           : CannotConvertArgumentNoMessage
    Line              : 1
    Offset            : 166
    CommandInvocation : 
        MyCommand        : Register-PSResourceRepository
        BoundParameters  : 
            Comparer : System.OrdinalIgnoreCaseComparer
            Count    : 2
            Keys     : 
                Length : 4

                Length : 3
            Values   : 
                Length : 13

                Length : 93
            SyncRoot : 
                Comparer : System.OrdinalIgnoreCaseComparer
                Count    : 2
                Keys     : 
                    Length : 4

                    Length : 3
                Values   : 
                    Length : 13

                    Length : 93
                SyncRoot : 
                    Comparer : System.OrdinalIgnoreCaseComparer
                    Count    : 2
                    Keys     : 
                        Length : 4

                        Length : 3
                    Values   : 
                        Length : 13

                        Length : 93
                    SyncRoot : 
                        Comparer : System.OrdinalIgnoreCaseComparer
                        Count    : 2
                        Keys     : 
                            Length : 4

                            Length : 3
                        Values   : 
                            Length : 13

                            Length : 93
                        SyncRoot : 
                            Comparer : System.OrdinalIgnoreCaseComparer
                            Count    : 2
                            Keys     : 
                                Length : 4

                                Length : 3
                            Values   : 
                                Length : 13

                                Length : 93
                            SyncRoot : 
                                Comparer : System.OrdinalIgnoreCaseComparer
                                Count    : 2
                                Keys     : 
                                    Length : 4

                                    Length : 3
                                Values   : 
                                    Length : 13

                                    Length : 93
                                SyncRoot : 
                                    Comparer : System.OrdinalIgnoreCaseComparer
                                    Count    : 2
                                    Keys     : …
                                    Values   : …
                                    SyncRoot : …
        ScriptLineNumber : 1
        OffsetInLine     : 1
        HistoryId        : 26
        Line             : Register-PSResourceRepository -Name "FeedDistrict2" -Uri "https://pkgs.dev.azure.com/DigitalDistrict01/_packaging/DigitalDistrict01/nuget/v3/index.json" -Credential $Credential
        PositionMessage  : At line:1 char:1
                           + Register-PSResourceRepository -Name "FeedDistrict2" -Uri "https://pkg …
                           + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        InvocationName   : Register-PSResourceRepository
        PipelineLength   : 1
        PipelinePosition : 1
    ErrorRecord       : 
        Exception             : 
            Type    : System.Management.Automation.ParentContainsErrorRecordException
            Message : Cannot bind parameter 'CredentialInfo'. Cannot convert the "System.Management.Automation.PSCredential" value of type "System.Management.Automation.PSCredential" to type "Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo".
            HResult : -2146233087
        CategoryInfo          : InvalidArgument: (:) [Register-PSResourceRepository], ParentContainsErrorRecordException
        FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.PSResourceGet.Cmdlets.RegisterPSResourceRepository
        InvocationInfo        : 
            MyCommand        : Register-PSResourceRepository
            ScriptLineNumber : 1
            OffsetInLine     : 166
            HistoryId        : 26
            Line             : Register-PSResourceRepository -Name "FeedDistrict2" -Uri "https://pkgs.dev.azure.com/DigitalDistrict01/_packaging/DigitalDistrict01/nuget/v3/index.json" -Credential $Credential
            PositionMessage  : At line:1 char:166
                               + … kaging/DigitalDistrict01/nuget/v3/index.json" -Credential $Credential
                               +                                                             ~~~~~~~~~~~
            CommandOrigin    : Internal
        ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
    TargetSite        : 
        Name          : CoerceTypeAsNeeded
        DeclaringType : System.Management.Automation.ParameterBinderBase, System.Management.Automation, Version=7.3.4.500, Culture=neutral, PublicKeyToken=31bf3856ad364e35
        MemberType    : Method
        Module        : System.Management.Automation.dll
    Data              : System.Collections.ListDictionaryInternal
    InnerException    : 
        Type        : System.Management.Automation.PSInvalidCastException
        ErrorRecord : 
            Exception             : 
                Type    : System.Management.Automation.ParentContainsErrorRecordException
                Message : Cannot convert the "System.Management.Automation.PSCredential" value of type "System.Management.Automation.PSCredential" to type "Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo".
                HResult : -2146233087
            CategoryInfo          : InvalidArgument: (:) [], ParentContainsErrorRecordException
            FullyQualifiedErrorId : ConvertToFinalInvalidCastException
        TargetSite  : 
            Name          : ThrowInvalidCastException
            DeclaringType : System.Management.Automation.LanguagePrimitives
            MemberType    : Method
            Module        : System.Management.Automation.dll
        Message     : Cannot convert the "System.Management.Automation.PSCredential" value of type "System.Management.Automation.PSCredential" to type "Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo".
        Source      : System.Management.Automation
        HResult     : -2147467262
        StackTrace  : 
   at System.Management.Automation.LanguagePrimitives.ThrowInvalidCastException(Object valueToConvert, Type resultType)
   at System.Management.Automation.LanguagePrimitives.ConvertNoConversion(Object valueToConvert, Type resultType, Boolean recurse, PSObject originalValueToConvert, IFormatProvider formatProvider, TypeTable backupTable)
   at System.Management.Automation.LanguagePrimitives.ConversionData`1.Invoke(Object valueToConvert, Type resultType, Boolean recurse, PSObject originalValueToConvert, IFormatProvider formatProvider, TypeTable backupTable)
   at System.Management.Automation.LanguagePrimitives.ConvertTo(Object valueToConvert, Type resultType, Boolean recursion, IFormatProvider formatProvider, TypeTable backupTypeTable)
   at System.Management.Automation.ParameterBinderBase.CoerceTypeAsNeeded(CommandParameterInternal argument, String parameterName, Type toType, ParameterCollectionTypeInformation collectionTypeInfo, Object currentValue)
    Source            : System.Management.Automation
    HResult           : -2146233087
    StackTrace        : 
   at System.Management.Automation.ParameterBinderBase.CoerceTypeAsNeeded(CommandParameterInternal argument, String parameterName, Type toType, ParameterCollectionTypeInformation collectionTypeInfo, Object currentValue)
   at System.Management.Automation.ParameterBinderBase.BindParameter(CommandParameterInternal parameter, CompiledCommandParameter parameterMetadata, ParameterBindingFlags flags)
   at System.Management.Automation.CmdletParameterBinderController.BindParameter(CommandParameterInternal argument, MergedCompiledCommandParameter parameter, ParameterBindingFlags flags)
   at System.Management.Automation.CmdletParameterBinderController.BindParameter(UInt32 parameterSets, CommandParameterInternal argument, MergedCompiledCommandParameter parameter, ParameterBindingFlags flags)
   at System.Management.Automation.CmdletParameterBinderController.BindNamedParameter(UInt32 parameterSets, CommandParameterInternal argument, MergedCompiledCommandParameter parameter)
   at System.Management.Automation.ParameterBinderController.BindNamedParameters(UInt32 parameterSets, Collection`1 arguments)
   at System.Management.Automation.CmdletParameterBinderController.BindCommandLineParametersNoValidation(Collection`1 arguments)
   at System.Management.Automation.CmdletParameterBinderController.BindCommandLineParameters(Collection`1 arguments)
   at System.Management.Automation.CommandProcessor.BindCommandLineParameters()
   at System.Management.Automation.CommandProcessor.Prepare(IDictionary psDefaultParameterValues)
   at System.Management.Automation.CommandProcessorBase.DoPrepare(IDictionary psDefaultParameterValues)
   at System.Management.Automation.Internal.PipelineProcessor.Start(Boolean incomingStream)
   at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input)
--- End of stack trace from previous location ---
   at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input)
   at System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput, CommandParameterInternal[][] pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][] commandRedirections, FunctionContext funcContext)
   at System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
CategoryInfo          : InvalidArgument: (:) [Register-PSResourceRepository], ParameterBindingException
FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.PSResourceGet.Cmdlets.RegisterPSResourceRepository
InvocationInfo        : 
    MyCommand        : Register-PSResourceRepository
    ScriptLineNumber : 1
    OffsetInLine     : 166
    HistoryId        : 26
    Line             : Register-PSResourceRepository -Name "FeedDistrict2" -Uri "https://pkgs.dev.azure.com/DigitalDistrict01/_packaging/DigitalDistrict01/nuget/v3/index.json" -Credential $Credential
    PositionMessage  : At line:1 char:166
                       + … kaging/DigitalDistrict01/nuget/v3/index.json" -Credential $Credential
                       +                                                             ~~~~~~~~~~~
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1

Environment data

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Binary     0.5.22     beta22     Microsoft.PowerShell.PSResourceGet  {Find-PSResource, Get-InstalledPSResource, Get-PSResourceRepository, Get-PSScriptFileInfo…}


Name                           Value
----                           -----
PSVersion                      7.3.4
PSEdition                      Core
GitCommitId                    7.3.4
OS                             Microsoft Windows 10.0.22000
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

Stephanevg avatar Jun 20 '23 06:06 Stephanevg

The problem is literally in the error message you provided: the "Credential" parameter for this cmdlet doesn't accept a pscredential object like you would expect it to, but instead is looking for a "PSCredentialinfo" object that is native to the psresourceget module (Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo). The actual problem is that Microsoft, in its infinite wisdom, has not created documentation that tells us how to create instances of this new object, since the documentation that they link to on the main github page literally links to help content for the very first version of the module, which is completely unacceptable. I would tell microsoft to get its act together, but it is clear where their priorities lie, and it is not in making this an easy to use, quality module.

youngturk2 avatar Jun 20 '23 15:06 youngturk2

I for one, had to use Ilspy to look at the resources defined in the psresourceget module in order to find the answer on my own (thanks for absolutely nothing, Microsoft), and this is what I found:

public PSCredentialInfo(string vaultName, string secretName, PSCredential credential = null)
{
	VaultName = vaultName;
	SecretName = secretName;
	Credential = credential;
}

So, this would indicate to me that, in order to create the pscredentialinfo object, you need to install the Microsoft.PowerShell.SecretManagement and Microsoft.PowerShell.SecretStore powershell modules, which allows you to create local secret vaults in which you can store and pull secrets. But, this is just an educated guess, as, again, microsoft hasn't said a thing about this.

youngturk2 avatar Jun 20 '23 15:06 youngturk2

Hi @youngturk2, there's no need for aggressive comments, you can read the code of conduct we abide by and ask users to abide by as well here: code of conduct. We are currently working on documentation, you can look at the tests in this repository for examples of how to use the PSCredentialInfo object in the meanwhile: PSCredentialInfoTests The parameter also takes a hashtable, so it's not necessary to pass in the object itself.

alerickson avatar Jun 20 '23 18:06 alerickson

Hi @alerickson

It was very clear to me that a PsCredentialInfo instance was requested. What surprised me, is the fact that up until now, is that the -Credential has been used on so many different cmdlets, and it standardly asks for an object of type pscredential.

In this case, t_o me that actually felt like a bug_, as I was actually expecting the the parameter -credential to expect a pscredential NOT a PscredentialInfo

Just for completness, I add the extract to the article released on the powershell blog not so long ago:

Azure DevOps Feeds To get the uri for your feed go to dev.azure.com > Artifacts > select desired feed > click “Connect to Feed” > choose “NuGet.exe”. then runRegister-PSResourceRepository -Name "AdoFeedName" -Uri <My_ADO_Feed_Uri> If it is a public feed creds arent needed. If it is a private feed go to dev.azure.com > User Settings in top right corner > Personal Access Tokens > Create PAT token. In your PowerShell terminal, create credential with your username as your email account used for ADO, password will be PAT token from prior step. To use the credential persistence feature of PSResourceGet reference the docs. You can also use with the -Credential parameter.

to me, how it is written there, it sounds like you can either use the persistance feature OR use the (good old) -credential parameter.

In other terms, IF you don't wan't to use the credential persistence feautre, you don't have to. But in this case, it doesn't work I would say.

This would make sense, as it would follow the standard that has been in place since the beginning of powershell. It would become quite a mess and very confusing for the users if suddently we would have official cmdlets that would accept a PsCredential object, and others that would accept PsCredentialInfo.

I feel like the intention of -Credential was not to be able to pass a PsCredentialInfo, but that it was for (the good old) PsCredential type. (which would feel completley logic to me).

Stephanevg avatar Jun 21 '23 09:06 Stephanevg

may be the good choise will be renaming -Credential to -CredentialInfo to show that they are different types

MVKozlov avatar Jun 24 '23 12:06 MVKozlov

Yes, I agree that we should rename the -Credential parameter as it brings to much confusion. tagging @SydneyhSmith for visibility.

Stephanevg avatar Jun 27 '23 14:06 Stephanevg

I completely agree, -CredentialInfo makes more sense here

alerickson avatar Jun 27 '23 19:06 alerickson

I just took a closer look to address this issue, but Register-PSResourceRepository actually does not have a -Credential parameter, only a -CredentialInfo parameter. Somehow the parameter binding mapped it to CredentialInfo which caused a bit of confusion. So really the issue is that the blog post should have said -CredentialInfo. Sorry for the confusion about that, I should've caught that earlier. If there's any other issues with Credentials, comment here and I can reopen this issue, or feel free to open up a new issue.

alerickson avatar Jun 28 '23 00:06 alerickson

Hi, you are right @alerickson , my bad, I didn't see it as well.

I still think there is some confusing around the -CredentialInfo parameter. There seem to be no existing cmdlet that allows one to get the object of type CredentialInfo.

Look at this example:

In order to register a PsRessource registry, I need to pass a PsCredentialInfo, but neither of the cmdlets actually return me an object of that type.

Get-Secret returns a System.Management.Automation.PSCredential Get-SecretInfo returns a Microsoft.PowerShell.SecretManagement.SecretInformation

Maybe I missed it, but the only way I found to get a PsCredentialInfo is via the example below.

$PsCredentialInfo = [Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo]::new("SecretStore","mod_prd")
$url = "https://pkgs.dev.azure.com/MyLongURL"

Register-PSResourceRepository -Name "syn_mod_prd" -Uri $Url -Force -CredentialInfo $PsCredentialInfo -Trusted

I am surprised, as I was really thinking that Get-SecretInfo would give me the right type. (Or perhaps I am doing something wrong?)

I believe this is a bit confusing, as we have 3 different type of credentials now, and the one we actually need for the Register-PsSressourceRepository can only be created using this method above, which might not be very accessible to everyone.

Wouldn't it make sense to have a Get-CredentialInfo cmdlet?

Stephanevg avatar Jun 28 '23 06:06 Stephanevg

@alerickson could you please re-open the ticket? looks like i cant my self

Stephanevg avatar Jun 28 '23 06:06 Stephanevg

One thing to consider is that -CredentialInfo also takes a hash table like -CredentialInfo @{ VaultName = 'VaultName'; SecretName = 'SecretName' }... but agree that a cmdlet would be a good feature request!

SydneyhSmith avatar Jun 29 '23 18:06 SydneyhSmith

Sorry if this appears as just a "+1" comment, but I'd like to re-iterate how confusing the current setup and documentation is. (Found this GH issue searching for similar answers, even though I have the version of the module that at least has the correct parameter name. Somehow I ended up trying to use [Microsoft.PowerShell.PowerShellGet.UtilClasses.PSCredentialInfo] which of course doesn't exist.)

Thinking about this a bit, I think there's two main contributors:

Parameter/Object Type(Class?) name:

CredentialInfo/PSCredentialInfo are misleading names - there's nothing there that would lead me to think it was related to the SecretManagement modules. This is especially problematic because PSCredential is such a commonly used Type.

Why is creating and passing in a new type (that I've never encountered before) even required? (It's fine/preferred to keep supporting it, of course). I'd request/suggest a new parameter set for the PSResourceRepository commands that just takes the same two strings we currently use to create the credentialinfo object.

My personal preference/wish would be to rename PSCredentialInfo to something like PSSecretManagementInfo, or whatever Class is already used in SecretManagementInfo. (I realize that's a bigger lift.)

Documentation:

Having both PowershellGet and PSResourceGet under the same documentation area, combined with how the version selection works is confusing. It's weird, at best, to be at https://learn.microsoft.com/en-us/powershell/gallery/powershellget/how-to/credential-persistence?view=powershellget-2.x , reading about PSResourceGet. I've been working w/ Powershell for around 10 years now, and I was still getting confused - I can't imagine how it must be for someone coming in fresh.

I believe the documentation should better call out:

  • That you're just setting up a reference - that the vault/store will need to be unlocked per the usual rules when used in the future, or any other subtleties in how it works.
  • The object in the secretstore must be a PSCredential. (I know it's the same as using the -credential param, but it's still surprising because if you're using a PAT, the username is not used)

OranguTech avatar Nov 18 '24 21:11 OranguTech

Update to the above, just stumbled upon another PSCredentialInfo class https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.commands.automation.model.credentialinfo - different namespaces, but still.

OranguTech avatar Nov 19 '24 21:11 OranguTech

But why is it not possible to call Register-PSResourceRepository using a PSCredential instance? Why do you need to have this as Secret management objects?

It was mentioned somewhere that PSCredential was possible to pass in to the Install-PSResource cmdlet. But what should you then pass in the Repository parameter? According to documentation, if Repository is not specified, it will search all registered repositories. So would the Repository parameter then have to be the full web address for the repository to use?

Same thing goes for the Publish-PSResource. It takes a Repository parameter being a string, and the examnple uses the value TestRepository. But if this is not already registered, how does Publish-PSResource find out where it is? Or shold this also be a full web address for the repository?

Right now, I'm trying to publish a Powershell module to my organizations GitHub Packages repository. Earlier in 2024, I was able to call Register-PSResourceRepository passing in a PSCredential instance and then use my freindly name for the repository. However, I happended to unregister this repository, and now I'm not able to re-register the repository.

And what if you have a local file based repository? How to you call Register-PSResourceRepository to allow installing and publishing to a LocalNuget repository located for example in C:\LocalNuget. What should I pass in as PSCredentialInfo? Simply dummy values?

I really do not see this as user freindly.

bstordrup avatar Dec 23 '24 08:12 bstordrup