简体   繁体   English

自定义PSHost,C#中的Get-Credential cmdlet

[英]Custom PSHost, Get-Credential cmdlet in C#

i am trying to implement a custom PSHost class for the purpose of crafting GUIs for Power Shell scripts. 我试图实现自定义PSHost类,以便为Power Shell脚本制作GUI。 I have taken the code here as a base and started adapting it for GUI Projects https://msdn.microsoft.com/en-us/library/ee706557%28v=vs.85%29.aspx 我已将此处的代码作为基础,并开始对其进行调整以适合GUI项目https://msdn.microsoft.com/en-us/library/ee706557%28v=vs.85%29.aspx

All was fine until i tried to run the Get-Credential cmdlet and got a error that the method is not implemented(ooouuuu)... The initial code was these two methods: 一切都很好,直到我尝试运行Get-Credential cmdlet并收到未实现该方法的错误(ooouuuu)...初始代码是这两种方法:

public override PSCredential PromptForCredential(
                                                 string caption, 
                                                 string message, 
                                                 string userName, 
                                                 string targetName)
{
  throw new NotImplementedException(
                       "The method or operation is not implemented.");
}

public override PSCredential PromptForCredential(
                                   string caption, 
                                   string message, 
                                   string userName, 
                                   string targetName, 
                                   PSCredentialTypes allowedCredentialTypes, 
                                   PSCredentialUIOptions options)
{
  throw new NotImplementedException(
                          "The method or operation is not implemented.");
}

So after some research i implemented the dialogue like this: 因此,经过一些研究,我实现了这样的对话:

    [DllImport("ole32.dll")]
    public static extern void CoTaskMemFree(IntPtr ptr);

    [DllImport("credui.dll", CharSet = CharSet.Auto)]
    private static extern int CredUIPromptForWindowsCredentials(ref CREDUI_INFO notUsedHere, int authError, ref uint authPackage, IntPtr InAuthBuffer, uint InAuthBufferSize, out IntPtr refOutAuthBuffer, out uint refOutAuthBufferSize, ref bool fSave, int flags);

    [DllImport("credui.dll", CharSet = CharSet.Auto)]
    private static extern bool CredUnPackAuthenticationBuffer(int dwFlags, IntPtr pAuthBuffer, uint cbAuthBuffer, StringBuilder pszUserName, ref int pcchMaxUserName, StringBuilder pszDomainName, ref int pcchMaxDomainame, StringBuilder pszPassword, ref int pcchMaxPassword);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct CREDUI_INFO
    {
        public int cbSize;
        public IntPtr hwndParent;
        public string pszMessageText;
        public string pszCaptionText;
        public IntPtr hbmBanner;
    }

    private enum PromptForWindowsCredentialsFlags
    {
        ...
    }

    public override PSCredential PromptForCredential(
                                       string caption,
                                       string message,
                                       string userName,
                                       string targetName,
                                       PSCredentialTypes allowedCredentialTypes,
                                       PSCredentialUIOptions options)
    {
        CREDUI_INFO credui = new CREDUI_INFO();
        credui.pszCaptionText = "Please enter the credentails";
        credui.pszMessageText = "DisplayedMessage";
        credui.cbSize = Marshal.SizeOf(credui);
        uint authPackage = 0;
        IntPtr outCredBuffer = new IntPtr();
        uint outCredSize;
        bool save = false;
        int result = CredUIPromptForWindowsCredentials(ref credui, 0, ref authPackage, IntPtr.Zero, 0, out outCredBuffer, out outCredSize, ref save, 1 /* Generic */);

        var usernameBuf = new StringBuilder(100);
        var passwordBuf = new StringBuilder(100);
        var domainBuf = new StringBuilder(100);

        int maxUserName = 100;
        int maxDomain = 100;
        int maxPassword = 100;
        if (result == 0)
        {
            if (CredUnPackAuthenticationBuffer(0, outCredBuffer, outCredSize, usernameBuf, ref maxUserName, domainBuf, ref maxDomain, passwordBuf, ref maxPassword))
            {
                //clear the memory allocated by CredUIPromptForWindowsCredentials
                CoTaskMemFree(outCredBuffer);
                SecureString secureString = new SecureString();
                foreach (char c in passwordBuf.ToString())
                {
                    secureString.AppendChar(c);
                }
                return new PSCredential(usernameBuf.ToString(), secureString);
            }
        }
        return null;
    }

This works fine but there is one snag, when running the Get-Credential cmdlet it prompts for a value for the Credential parameter, regardless of any input after hitting return the dialogue pops up and everything works as expected. 这可以正常工作,但存在一个障碍,运行Get-Credential cmdlet时,它将提示输入Credential参数的值,无论在按回车键后输入任何内容,都会弹出对话框,并且一切都按预期进行。 Doing the same in ISE the dialogue pops up directly without any prompt. 在ISE中执行相同操作,对话框将直接弹出,而没有任何提示。 I thought it was due to the arguments of the method but making them optional by defining a default value did not make a difference. 我认为这是由于该方法的参数所致,但是通过定义默认值使它们成为可选参数并没有什么不同。 It might be due to how the cmdlet is defined in the PS environment so my question is: How can i make it so that running the cmdlet will jump straight to the dialogue? 这可能是由于在PS环境中如何定义cmdlet,所以我的问题是:我该如何做到这一点,以便运行cmdlet可以直接跳至对话? Is it possible to define a default value for the Credential parameter to bind to? 是否可以为要绑定到的Credential参数定义默认值? I'm guessing this is how ISE gets around this or am i missing something? 我猜这是ISE如何解决这个问题或我缺少什么吗?

我花了一些时间进行试验,但是我发现,强制参数绑定由PSHostUserInterface接口中的public override Dictionary<string, PSObject> Prompt(string caption, string message, Collection<FieldDescription> descriptions)方法处理,然后PromptForCredential调用PromptForCredential

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM