【问题标题】:Is there another way to ask for credentials in Powershell but Get-Credential?除了 Get-Credential,还有其他方法可以在 Powershell 中请求凭据吗?
【发布时间】:2021-07-03 22:58:43
【问题描述】:

我的 Powershell 脚本使用以下语法要求提供凭据,并且可以正常工作:

$credentials = (Get-Credential -Message "Enter Password")

但问题是弹出的输入用户名和密码的窗口空间很小,用户输入大用户名(大服务器名反斜杠大用户名)不舒服,而且windows没有允许调整大小。

我想让我的用户能够在另一个更大的窗口中输入用户名和密码。 有什么想法吗?

【问题讨论】:

  • 可能您必须自己设计一个自定义表单。做起来并不难。
  • 看看使用Read-Host 获取安全字符串。这会让你在整个控制台中工作...... [grin]
  • 查看 PowerShell v7.xx 中 cmdlet 的输出!它不会打开图形弹出窗口。

标签: powershell credentials


【解决方案1】:

我有类似的东西,所以我想为什么不分享它。试试看,虽然没有Get-Credential漂亮,但是可以调整大小。

它将返回一个PSCredential 对象,与Get-Credential 相同。
如果 UsernamePassword 有文字,OK 按钮才会变为 Enabled

Add-Type -AssemblyName System.Windows.Forms

$refAssemblies = @(
    'System.Drawing'
)
if($PSVersionTable.PSVersion.Major -ge 6)
{
    $refAssemblies += 'System.Drawing.Common'
}

Add-Type -ReferencedAssemblies $refAssemblies -IgnoreWarnings -WarningAction Ignore -TypeDefinition @'
using System; 
using System.Runtime.InteropServices;
using System.Drawing;

public class DPI
{  
    [DllImport("gdi32.dll")]
    static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

    public enum DeviceCap
    {
        VERTRES = 10,
        DESKTOPVERTRES = 117
    } 

    public static float scaling()
    {
        Graphics g = Graphics.FromHwnd(IntPtr.Zero);
        IntPtr desktop = g.GetHdc();
        int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
        int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);

        return (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
    }
}
'@

[void][System.Windows.Forms.Application]::EnableVisualStyles()
$DPI = [math]::round([dpi]::scaling(),2) * 100
$bounds = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea
$bounds.Width = ($bounds.Width / 100) * $DPI
$bounds.Height = ($bounds.Height / 100) * $DPI

$mainForm = [System.Windows.Forms.Form]::new()
$mainForm.StartPosition = 'CenterScreen'
$mainForm.FormBorderStyle = 'Sizable'
$mainForm.Text = 'Custom Get Credential'
$mainForm.WindowState = 'Normal'
$mainForm.KeyPreview = $True
$mainForm.Font = [System.Drawing.Font]::new('Calibri',12,[System.Drawing.FontStyle]::Regular)
$mainForm.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon((Get-Process -Id $PID).Path)
$mainForm.MinimumSize = [System.Drawing.Size]::new(($bounds.Width/4.5),($bounds.Height/4.5))
$mainForm.MaximumSize = [System.Drawing.Size]::new($bounds.Width,($bounds.Height/4.5))
$mainForm.MaximizeBox = $false
$mainForm.Size = $mainForm.MinimumSize

$credentialMsg = [System.Windows.Forms.Label]::new()
$credentialMsg.Location = [System.Drawing.Size]::new(10,10)
$credentialMsg.Size = [System.Drawing.Size]::new(($mainForm.Width-30),30)
$credentialMsg.Text = 'Supply values for the following parameters:'
$mainForm.Controls.Add($credentialMsg)

$userLbl = [System.Windows.Forms.Label]::new()
$userLbl.Location = [System.Drawing.Size]::new(10,50)
$userLbl.Size = [System.Drawing.Size]::new(80,30)
$userLbl.Text = 'Username'
$mainForm.Controls.Add($userLbl)

$userTxtBox = [System.Windows.Forms.TextBox]::new()
$userTxtBox.Location = [System.Drawing.Size]::new(($userLbl.Width+10),50)
$userTxtBox.Size = [System.Drawing.Size]::new(($mainForm.Width-120),60)
$mainForm.Controls.Add($userTxtBox)

$passwordLbl = [System.Windows.Forms.Label]::new()
$passwordLbl.Location = [System.Drawing.Size]::new(10,($userLbl.Location.Y+40))
$passwordLbl.Size = [System.Drawing.Size]::new(80,30)
$passwordLbl.Text = 'Password'
$mainForm.Controls.Add($passwordLbl)

$passwordTxtBox = [System.Windows.Forms.TextBox]::new()
$passwordTxtBox.Location = [System.Drawing.Size]::new(($passwordLbl.Width+10),($userTxtBox.Location.Y+40))
$passwordTxtBox.Size = [System.Drawing.Size]::new(($mainForm.Width-120),60)
$passwordTxtBox.UseSystemPasswordChar = $True
$passwordTxtBox.Anchor = 'top,left'
$mainForm.Controls.Add($passwordTxtBox)

$cancelBtn = [System.Windows.Forms.Button]::new()
$cancelBtn.Location = [System.Drawing.Size]::new(($mainForm.Width-110),($passwordTxtBox.Location.Y+40))
$cancelBtn.Size = [System.Drawing.Size]::new(80,35)
$cancelBtn.Text = '&Cancel'
$cancelBtn.Anchor = 'right,bottom'
$cancelBtn.Add_Click({
    $mainForm.DialogResult = 'Cancel'
})
$mainForm.Controls.Add($cancelBtn)

$okBtn = [System.Windows.Forms.Button]::new()
$okBtn.Location = [System.Drawing.Size]::new(($cancelBtn.Location.X-$cancelBtn.Width-5),$passwordTxtBox.Location.Y+40)
$okBtn.Size = $cancelBtn.Size
$okBtn.Text = '&OK'
$okBtn.Anchor = $cancelBtn.Anchor
$okBtn.Enabled = $false
$okBtn.Add_Click({
    $mainForm.DialogResult = 'OK'
})
$mainForm.Controls.Add($okBtn)

$okBtnEnableEvent = {
    if(
        [string]::IsNullOrWhiteSpace($userTxtBox.Text) -or 
        [string]::IsNullOrWhiteSpace($passwordTxtBox.Text)
    )
    {
        $okBtn.Enabled = $false
    }
    else
    {
        $okBtn.Enabled = $True
    }
}
$userTxtBox.Add_TextChanged($okBtnEnableEvent)
$passwordTxtBox.Add_Textchanged($okBtnEnableEvent)

$mainForm.Add_Resize({
    $userTxtBox.Size = [System.Drawing.Size]::new(($this.Width-120),60)
    $passwordTxtBox.Size = [System.Drawing.Size]::new(($this.Width-120),60)
})

$mainForm.AcceptButton = $okBtn
$mainForm.CancelButton = $cancelBtn
$mainForm.Add_Shown({ $this.Activate() })

function New-PSCredential {
param(
    [string]$Username,
    [string]$Password
)
    
    $passw = ConvertTo-SecureString $Password.Trim() -AsPlainText -Force
    [System.Management.Automation.PSCredential]::new($Username.Trim(),$passw)
}

if('OK' -eq $mainForm.ShowDialog())
{
    New-PSCredential -Username $userTxtBox.Text -Password $passwordTxtBox.Text
}

$mainForm.Dispose()

编辑:


【讨论】:

  • 非常感谢@SantiagoSquerzon 提供如此完整的代码。它不仅可以帮助我解决这个问题,还可以作为生成更多表单的模板。谢谢!!
  • 干得好;一些提示:System.Drawing 不需要单独加载,而不是[void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') 最好使用Add-Type -Assembly System.Windows.Forms。如果您还希望它在 PowerShell Core 中工作,请将 [System.Drawing.Icon]::ExtractAssociatedIcon("$PSHOME\PowerShell.exe") 替换为 [System.Drawing.Icon]::ExtractAssociatedIcon((Get-Process -Id $PID).Path)
  • 您可以不使用 OK/Cancel 按钮事件,如下所示:$okBtn.DialogResult = 'OK'$cancelBtn.DialogResult = 'Cancel',结合 $mainForm.AcceptButton = $okBtn$mainForm.CancelButton = $cancelBtn。这也隐式启用了 ESC / Enter 支持。
  • 感谢 DPI 代码;我从来不用处理它,但听起来在 v4.7+ 中现在可以使用 .NET 辅助方法 - 请参阅 High DPI support in Windows Forms。是的,您需要先创建按钮控件,然后将它们分配给表单的.AcceptButton.CancelButton 属性。我不会在 事件处理程序 中创建凭证对象,我会检查 .ShowDialog() 结果中的 'OK' 然后创建对象(请参阅下一条评论)。
  • if ('OK' -eq $mainForm.ShowDialog()) { # Construct and output a PSCredential instance. [System.Management.Automation.PSCredential]::new( $userTxtBox.Text.Trim(), (ConvertTo-SecureString $passwordTxtBox.Text.Trim() -AsPlainText -Force) ) } $mainForm.Dispose()
猜你喜欢
  • 2015-06-26
  • 1970-01-01
  • 2018-03-01
  • 1970-01-01
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-14
相关资源
最近更新 更多