我正在尝试实现一个自定义 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 解决这个问题的方式,还是我错过了什么?