在不需要提示输入密码的情况下使用PowerShell凭据

164

我想重新启动属于某个域的远程计算机。我有一个管理员账户,但不知道如何在powershell中使用它。

我知道有一个Restart-Computer cmdlet,而且可以传递凭证,但如果我的域是例如mydomain,我的用户名是myuser,密码是mypassword,正确的语法是什么?

我需要安排重启以便无需输入密码。


你应该阅读这个链接 - jams
get-credential domain01\admin01 是什么意思?下一个命令是 restart-computer -computername $s -force -throttlelimit 10 -credential $c。这是否意味着 get-credential 可以获取密码而无需询问? - all eyez on me
http://technet.microsoft.com/en-us/library/dd315327.aspx - jams
12个回答

214

Get-Credential 的问题在于它会一直提示输入密码。然而有一种方法可以解决这个问题,但它需要将密码作为安全字符串存储在文件系统中。

以下文章解释了如何实现:

不弹出提示使用 PSCredentials

简单来说,您需要创建一个文件来存储您的密码(以加密字符串形式)。下面这行代码将提示输入并将其作为加密字符串保存在 c:\mysecurestring.txt 中。您只需要执行一次即可:

read-host -assecurestring | convertfrom-securestring | out-file C:\mysecurestring.txt

无论在PowerShell命令中看到哪个-Credential参数,它都意味着您可以传递一个PSCredential。所以在您的情况下:

$username = "domain01\admin01"
$password = Get-Content 'C:\mysecurestring.txt' | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential `
         -argumentlist $username, $password

$serverNameOrIp = "192.168.1.1"
Restart-Computer -ComputerName $serverNameOrIp `
                 -Authentication default `
                 -Credential $cred
                 <any other parameters relevant to you>

由于我不知道您的环境,您可能需要一个不同的 -Authentication 开关值。


27
жӮЁиҝҳеҸҜд»ҘдҪҝз”Ёе‘Ҫд»ӨConvertTo-SecureString "password" -AsPlainText -ForceиҝӣиЎҢж“ҚдҪңгҖӮ - x0n
18
为了明确起见,$password = ConvertTo-SecureString "password" -AsPlainText -Force 的意思是将字符串 "password" 转换为安全字符串,并强制将其视为纯文本格式。 - Akira Yamamoto
在Read-Host参数中,需要使用-Credential [用户名],否则PowerShell会一直挂起。将-Credential传递给read-host后,您将直接在PowerShell控制台中收到提示,并且密码将被正确存储。谢谢! - sephirot
我正在尝试弄清楚如何在使用PowerShell中的Send-MailMessage函数时使其工作。我想要存储我的电子邮件用户和密码的凭据,以便我不必一直输入它。有什么想法吗? - KangarooRIOT
@user3681591 - 我建议您提出一个新问题,而不是在评论中进行。谢谢。 - Kev
使用-Authentication Basic时需要注意:我发现-Authentication Default可以正常工作,用户名为“计算机或域\用户名”,但如果您使用用户名“计算机名\用户名”,则会出现访问被拒绝的错误。这可以通过仅在提供给cmdlet(在我的情况下是Invoke-Command/New-PSSession)的PSCredential中指定用户名来解决。 - Johan Andersson

73

还有一种方法,但是......

如果您不想将密码存储在脚本文件中,请勿使用此方法。 (在脚本中存储密码并不是一个好主意,但我们中的一些人只是想知道如何做。)

好的,那就是警告,下面是代码:

$username = "John Doe"
$password = "ABCDEF"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr

$cred将拥有John Doe的凭据和密码"ABCDEF"。

获取密码以备使用的替代方法:

$password = convertto-securestring -String "notverysecretpassword" -AsPlainText -Force

谢谢。这非常有帮助。在我的情况下,我正在创建一个自定义的PowerShell cmdlet,它接受用户名和密码(作为secureString)。在内部,该cmdlet调用了几个其他cmdlet,其中一些只需要用户和密码,但其中一个需要凭据,因此我实际上不需要在我的脚本中硬编码密码。 - BenR
21
简化版:$password = convertto-securestring -String "notverysecretpassword" -AsPlainText -Force该命令用于将字符串“notverysecretpassword”转换为安全的密码对象,并将其存储在变量$password中。该命令使用了PowerShell语言中的convertto-securestring命令,其中-AsPlainText参数指定输入字符串是明文格式,-Force参数表示强制执行转换操作。 - Sam
我正在尝试弄清楚如何在使用PowerShell中的Send-MailMessage函数时使其工作。我想要存储我的电子邮件用户和密码的凭据,以便我不必一直输入它。有什么办法可以做到这一点吗? - KangarooRIOT
@user3681591 这将是Send-MailMessage -Credential $cred(其中$cred如本帖所示创建) - Jeroen Landheer
@JeroenLandheer 我尝试了你的答案(感谢帮助!),但是它并没有起作用。我的错误信息是: -Credential : 术语“-Credential”不被认为是命令、函数、脚本文件或可操作程序的名称。 - KangarooRIOT
@BenR的例子讲得非常好,我认为需要注意的是,如果您将未加密的密码存储在文件中,则此示例仅不安全/即不良想法。如果您是通过参数(内存中)传递密码或以不同方式访问加密密码,则这是一个完美的解决方案(并且完全不会不安全)。 - David Rogers

30

关于存储凭据,我使用两个函数(通常在从我的配置文件加载的模块中):

#=====================================================================
# Get-MyCredential
#=====================================================================
function Get-MyCredential
{
param(
$CredPath,
[switch]$Help
)
$HelpText = @"

    Get-MyCredential
    Usage:
    Get-MyCredential -CredPath `$CredPath

    If a credential is stored in $CredPath, it will be used.
    If no credential is found, Export-Credential will start and offer to
    Store a credential at the location specified.

"@
    if($Help -or (!($CredPath))){write-host $Helptext; Break}
    if (!(Test-Path -Path $CredPath -PathType Leaf)) {
        Export-Credential (Get-Credential) $CredPath
    }
    $cred = Import-Clixml $CredPath
    $cred.Password = $cred.Password | ConvertTo-SecureString
    $Credential = New-Object System.Management.Automation.PsCredential($cred.UserName, $cred.Password)
    Return $Credential
}

还有这个:

#=====================================================================
# Export-Credential
# Usage: Export-Credential $CredentialObject $FileToSaveTo
#=====================================================================
function Export-Credential($cred, $path) {
      $cred = $cred | Select-Object *
      $cred.password = $cred.Password | ConvertFrom-SecureString
      $cred | Export-Clixml $path
}

使用方法如下:

$Credentials = Get-MyCredential (join-path ($PsScriptRoot) Syncred.xml)
如果凭证文件不存在,第一次运行时会提示输入凭证,并将凭证以加密字符串的形式存储在一个XML文件中。第二次运行该行代码时,XML文件已存在并将自动打开。

10

我需要从一个需要不同凭据的远程服务器上运行SCOM 2012功能。为避免明文密码,我通过将密码解密函数的输出作为ConvertTo-SecureString的输入来传递密码。出于清晰起见,此处未显示。

我喜欢对我的声明进行强制类型化。$strPass的类型声明运作正常。

[object] $objCred = $null
[string] $strUser = 'domain\userID'
[System.Security.SecureString] $strPass = '' 

$strPass = ConvertTo-SecureString -String "password" -AsPlainText -Force
$objCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($strUser, $strPass)

4

如果您要安排重新启动任务,有两种方法可以实现。

首先,您可以使用具有连接和重启其他计算机所需权限的凭据在一台计算机上创建一个任务。这样,调度程序负责安全地存储凭据。重新启动命令(我是 Powershell 专家,但此方法更加简洁)如下:

SHUTDOWN /r /f /m \\计算机名

在本地计算机上创建一个定期重新启动远程计算机的命令行为:

SCHTASKS /Create /TN "重启服务器" /TR "shutdown.exe /r /f /m \\计算机名" /SC ONCE /ST 00:00 /SD "12/24/2012" /RU "域\用户名" /RP "密码"

我更喜欢第二种方式,它使用当前凭据在远程计算机上创建以系统帐户身份运行的定期任务。

SCHTASKS /Create /TN "重启服务器" /TR "shutdown.exe /r /f" /SC ONCE /ST 00:00 /SD "12/24/2012" /RU SYSTEM /S 计算机名

这也可以通过 GUI 实现,只需将用户名输入 SYSTEM,将密码字段留空即可。


3

我看到一个使用Import/Export-CLIXML的例子。

以下是我推荐解决你所遇到问题的命令,使用它们的最简单方式如下。

$passwordPath = './password.txt'
if (-not (test-path $passwordPath)) {
    $cred = Get-Credential -Username domain\username -message 'Please login.'
    Export-CliXML -InputObject $cred -Path $passwordPath
}
$cred = Import-CliXML -path $passwordPath

如果文件在本地不存在,则会提示输入凭据并将其存储。这将不会有任何问题地接受 [pscredential] 对象,并将凭据隐藏为安全字符串。

最后,像往常一样使用凭据即可。

Restart-Computer -ComputerName ... -Credentail $cred

安全注意事项:

在磁盘上安全存储凭据

阅读解决方案时,您可能会担心在磁盘上存储密码。虽然谨慎地避免在硬盘上散布敏感信息是自然而明智的,但Export-CliXml命令使用Windows标准数据保护API加密凭据对象。这确保只有您的用户帐户才能正确解密其内容。同样,ConvertFrom-SecureString命令还会加密您提供的密码。

编辑:重新阅读原始问题。如果您已将[pscredential]初始化到硬盘,则上述内容将起作用。也就是说,如果您将其放入脚本并运行一次该脚本,它将创建该文件,然后无人值守地运行该脚本将变得简单。


1
不错。你能修正一个打字错误吗, "Export-CliXML",缺少了 "xml"。 - Stefan Wilms

1

这是我使用的方法,对我很有效。

$User="Domain\Username"
$Password=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('VABlAHMAdABQAGEAcwBzAHcAbwByAGQA'))

$SecurePassword = New-Object -TypeName System.Security.SecureString
$Password.ToCharArray() | ForEach-Object {$SecurePassword.AppendChar($_)}

$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $SecurePassword

要获取VABlAHMAdABQAGEAcwBzAHcAbwByAGQA,我这样做:

编码$EString表示加密字符串,$DString表示解密字符串

$EString = Read-Host "Type Text to Encode" -AsSecureString
$BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($EString)
$DString=[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$Encoded=[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($DString))

$Encoded # VABlAHMAdABQAGEAcwBzAHcAbwByAGQA
$DString # TestPassword

那样我就可以在脚本上放置任何想要的密码而不会太麻烦。

1
解决方案
$userName = 'test-domain\test-login'
$password = 'test-password'

$pwdSecureString = ConvertTo-SecureString -Force -AsPlainText $password
$credential = New-Object -TypeName System.Management.Automation.PSCredential `
    -ArgumentList $userName, $pwdSecureString

针对构建机器
在先前的代码中,将用户名和密码的值替换为您的构建机器的秘密(“隐藏日志”)环境变量。

测试结果

'# Results'
$credential.GetNetworkCredential().Domain
$credential.GetNetworkCredential().UserName
$credential.GetNetworkCredential().Password

你会看到

# Results
test-domain
test-login
test-password

1
read-host -assecurestring | convertfrom-securestring | out-file C:\securestring.txt
$pass = cat C:\securestring.txt | convertto-securestring
$mycred = new-object -typename System.Management.Automation.PSCredential -argumentlist "test",$pass
$mycred.GetNetworkCredential().Password

非常小心地存储密码,这种方式并不像...那样安全。

0

不要将加密密码存储在文本文件中,可以将其存储在凭据保险库中。 在以下示例中,用户仅在第一次提示输入密码,之后密码将从凭据保险库中检索。

# Load the Windows Runtime Class
[Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
$Vault = New-Object Windows.Security.Credentials.PasswordVault

$RESOURCE = "myresource"
$USERNAME = "myuser"

try {
    $credentials = $Vault.Retrieve($RESOURCE,$USERNAME)
    $pwd = $credentials.Password | ConvertTo-SecureString -Key (1..16)
    }
catch {
    $pwd = Read-Host "please enter your password:" -AsSecureString
    $Encrypted = ConvertFrom-SecureString -SecureString $pwd -Key (1..16)
    $credentials = new-object -Type Windows.Security.Credentials.PasswordCredential -ArgumentList $RESOURCE,$USERNAME,$Encrypted
    $Vault.Add($credentials)
    }

$cred = New-Object System.Management.Automation.PsCredential($USERNAME,$pwd)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接