0

我正在尝试实现一个自定义 PSHost 类,以便为 Power Shell 脚本制作 GUI。我已将此处的代码作为基础并开始将其改编为 GUI 项目 https://msdn.microsoft.com/en-us/library/ee706557%28v=vs.85%29.aspx

一切都很好,直到我尝试运行 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.");
}

所以经过一些研究,我实现了这样的对话:

    [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;
    }

这工作正常,但有一个障碍,当运行 Get-Credential cmdlet 时,它会提示输入 Credential 参数的值,无论点击返回后的任何输入,都会弹出对话框并且一切都按预期工作。在 ISE 中执行相同操作,直接弹出对话框,没有任何提示。我认为这是由于方法的参数,但通过定义默认值使它们成为可选并没有什么不同。这可能是由于 cmdlet 在 PS 环境中是如何定义的,所以我的问题是:我怎样才能使它运行 cmdlet 将直接跳转到对话框?是否可以为要绑定的 Credential 参数定义默认值?我猜这就是 ISE 解决这个问题的方式,还是我错过了什么?

4

1 回答 1

0

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

于 2015-06-10T11:01:06.953 回答