我在 Windows Server 2008 R2 上使用 PowerShell 2.0(因为 SP2010 是必需的)。我需要从 Windows 凭据管理器检索进程的凭据。我似乎无法让它发挥作用。
我得到了这段代码:
[Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
(new-object Windows.Security.Credentials.PasswordVault).RetrieveAll() | % { $_.RetrievePassword(); $_ }
两行代码都会抛出错误
Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime : Unable to find type [Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]: make sure that the assembly containing this type is loaded.
和
(new-object Windows.Security.Credentials.PasswordVault).RetrieveAll() | % {$_.RetrievePassword(); $_ }
分别。我一直在尝试以某种方式导入PasswordVault 类。到目前为止,谷歌让我失望了,我什至无法找出它驻留在哪个程序集中。我错过了什么?
在 powershell5 中输入:
Install-Module CredentialManager -force
然后
New-StoredCredential -Target $url -Username $ENV:Username -Pass ....
及以后
Get-StoredCredential -Target ....
该模块的源代码是https://github.com/davotronic5000/PowerShell_Credential_Manager
== 编辑 2023 ==
原件已存档,安装新的叉子:
Install-Module -Name TUN.CredentialManager
查看 Github 存储库了解更多详细信息。
您需要访问 Win32 API 才能与凭据管理器交互。
Technet 脚本库中的 CredMan.ps1 很好地演示了这一点。
对于更简单的使用模式,例如仅列出主体或添加新凭据,您还可以使用
cmdkey
,这是一个用于凭据管理的内置 Windows 命令行实用程序
为了在 PowerShell 中重用存储的凭据,这家伙似乎找到了一种方法,使用类似于 CredMan.ps1 的技术,从凭据存储中的通用凭据句柄构建
PSCredential
:Get-StoredCredential
如果有人只是想要一个代码片段,以便他们可以分发脚本而无需指导最终用户安装模块或包含 DLL 文件,这应该可以解决问题。
$code = @"
using System.Text;
using System;
using System.Runtime.InteropServices;
namespace CredManager {
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CredentialMem
{
public int flags;
public int type;
public string targetName;
public string comment;
public System.Runtime.InteropServices.ComTypes.FILETIME lastWritten;
public int credentialBlobSize;
public IntPtr credentialBlob;
public int persist;
public int attributeCount;
public IntPtr credAttribute;
public string targetAlias;
public string userName;
}
public class Credential {
public string target;
public string username;
public string password;
public Credential(string target, string username, string password) {
this.target = target;
this.username = username;
this.password = password;
}
}
public class Util
{
[DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CredRead(string target, int type, int reservedFlag, out IntPtr credentialPtr);
public static Credential GetUserCredential(string target)
{
CredentialMem credMem;
IntPtr credPtr;
if (CredRead(target, 1, 0, out credPtr))
{
credMem = Marshal.PtrToStructure<CredentialMem>(credPtr);
byte[] passwordBytes = new byte[credMem.credentialBlobSize];
Marshal.Copy(credMem.credentialBlob, passwordBytes, 0, credMem.credentialBlobSize);
Credential cred = new Credential(credMem.targetName, credMem.userName, Encoding.Unicode.GetString(passwordBytes));
return cred;
} else {
throw new Exception("Failed to retrieve credentials");
}
}
[DllImport("Advapi32.dll", SetLastError = true, EntryPoint = "CredWriteW", CharSet = CharSet.Unicode)]
private static extern bool CredWrite([In] ref CredentialMem userCredential, [In] int flags);
public static void SetUserCredential(string target, string userName, string password)
{
CredentialMem userCredential = new CredentialMem();
userCredential.targetName = target;
userCredential.type = 1;
userCredential.userName = userName;
userCredential.attributeCount = 0;
userCredential.persist = 3;
byte[] bpassword = Encoding.Unicode.GetBytes(password);
userCredential.credentialBlobSize = (int)bpassword.Length;
userCredential.credentialBlob = Marshal.StringToCoTaskMemUni(password);
if (!CredWrite(ref userCredential, 0))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
}
}
}
"@
Add-Type -TypeDefinition $code -Language CSharp
# How to store credentials
[CredManager.Util]::SetUserCredential("Application Name", "Username", "Password")
# How to retrieve credentials
[CredManager.Util]::GetUserCredential("Application Name")
# How to just get the password
[CredManager.Util]::GetUserCredential("Application Name").password
上述代码已在 PowerShell 7 和 PowerShell 5 上进行了测试,但如果您使用后者,则可能需要较新版本的 .Net 框架。
SecretManagement 和 SecretStore 似乎是官方解决方案。它们于 2021 年 3 月 25 日正式发布。这个秘密可以是凭证。
Install-Module Microsoft.PowerShell.SecretManagement
Install-Module SecretManagement.JustinGrote.CredMan # windows credential manager
Register-SecretVault SecretManagement.JustinGrote.CredMan
Set-Secret -Name TestSecret -Secret "TestSecret"
Get-Secret -Name TestSecret -AsPlainText
TestSecret
根据文档,Windows Server 2008 R2 不支持PasswordVault 类。
支持的最低服务器 Windows Server 2012
https://msdn.microsoft.com/library/windows/apps/windows.security.credentials.passwordvault.aspx
我发现了一篇非常好的帖子,这段代码将打印所有用户名、资源和密码
[Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
$vault = New-Object Windows.Security.Credentials.PasswordVault
$vault.RetrieveAll() | % { $_.RetrievePassword();$_ }
归功于托德的帖子
适用于 Windows PowerShell v5.1(以及可能早期版本)以及 PowerShell (Core) 7+:
BetterCredentials
模块,在PowerShell库中可用提供对CredMan(Windows凭据管理器)的编程访问。
您可以安装,例如:
Install-Module BetterCredentials -AllowClobber
-AllowClobber
是必要的,因为模块的 Get-Credential
命令旨在覆盖 内置命令:它与内置命令语法兼容,同时通过附加参数提供附加功能。[1]
值得注意的是,
-Store
开关可用于将返回的凭据存储在CredMan中。
要更多地控制条目的存储方式,请使用
Set-Credential
。
Get-Credential
自动返回已存储的凭据(如果可用),并且如果最初仅指定了用户名,也足以进行检索。
以下命令与 CredMan 库显式交互,需要完整条目 目标名称,如
.Target
返回的装饰 [pscredential]
实例的 Find-Credential
属性值所示。
Get-Credential -Store -UserName Foo
存储的凭证,.Target
属性值为 LegacyGeneric:target=MicrosoftPowerShell:user=foo
Find-Credential
默认列出所有存储的凭据;虽然它确实有一个 -Filter
参数,但它受到严重限制,并且根据我的经验,它不能可靠地工作(从模块版本 4.5 开始) - 最好将 post-filtering 与 Where-Object
一起使用,如 this 答案所示.
要删除存储的凭据,请使用
Remove-Credential
。
要测试 CredMan 保管库中是否已存在具有给定目标名称的凭证,请使用
Test-Credential
。
[1] 您不太可能需要这样做,但您仍然可以调用重写的 cmdlet,即通过
Microsoft.PowerShell.Security\Get-Credential