问题
如何可靠地判断给定的字符串是代表 aNTAccount
还是 a SecurityIdentifier
?
详细
给定一个字符串,我可以通过构造函数将其转换为 anNTAccount
或 a :SecurityIdentifier
[string]$myAccount = '...' # some value
$ntAccount = [System.Security.Principal.NTAccount]::new($myAccount)
$sid = [System.Security.Principal.SecurityPrincipal]::new($myAccount) // throws exception if not a valid SID
如果字符串不是 SID,SecurityIdentifier 构造函数将抛出异常。如果字符串是 SID,NTAccount 构造函数将接受它......但是,当我尝试将其转换为 SID 时,System.Security.Principal.IdentityNotMapped
将引发异常。
$sidFromNT = $ntAccount.Translate([System.Security.Principal.SecurityPrincipal]) # throw exception
$ntFromSid = $sid.Translate([System.Security.Principal.NTAccount]) # should work as if the SID were invalid we'd have already erred
如果我可以说我不知道使用共享基类的类型,那就太好了;但那是抽象的/没有公共构造函数;所以我不能这样做:
[string]$account = '...'
$idRef = [System.Security.Principal.IdentityReference]::new($account) # this is not valid code
$ntFromId = $idRef.Translate([System.Security.Principal.NTAccount])
$sidFromId = $idRef.Translate([System.Security.Principal.SecurityIdentifier])
因此,我能想到的唯一选择是:
- 使用抛出的错误*来确定类型;但这使错误成为我正常流程的一部分。
- 检查值是否开始
S-
;非常快,在大多数情况下应该可以工作;但这是一个黑客。
* 注意:我意识到无效值(即既不是 NT 帐户也不是 SID)也会出现异常;为了保持简短,我暂时忽略了这种情况。
--
C#版本
由于这是一个 .net 问题,而不是特定于 PowerShell 的问题,因此这里的代码用于说明 C# 中的相同问题(遗憾的是,我无法解决这个问题,因为各种 Fiddle 站点限制了所需的功能)。
public static void Main()
{
var ids = new string[] {"S-1-1-0", "Everyone"}; // a list of values which may be SIDs or NTAccounts
var pseudoRandomIndex = DateTime.Now.Millisecond % ids.Length; // saves initialising Random for a simple demo
var idString = ids[pseudoRandomIndex]; // pick one id at random; be it a SID or an NT Account
Debug.WriteLine($"Selected value is {idString}");
TryToProcessIdentityReference<NTAccount, SecurityIdentifier>(idString, (id) => new NTAccount(id));
TryToProcessIdentityReference<SecurityIdentifier, NTAccount>(idString, (id) => new SecurityIdentifier(id));
}
static void TryToProcessIdentityReference<T1, T2>(string idString, Func<string, T1> callConstructor)
where T1 : IdentityReference
where T2 : IdentityReference
{
var t1Type = typeof(T1);
var t2Type = typeof(T2);
Console.WriteLine($"Trying to process {idString} as a {t1Type.Name} ...");
try
{
var t1 = callConstructor(idString);
_ = t1.Translate(t2Type);
Debug.WriteLine($" - {idString} is a valid {t1Type.Name}!");
} catch (Exception e) when(e is ArgumentException || e is IdentityNotMappedException) {
Debug.WriteLine($" - Failed to process {idString} as {t1Type.Name}; error thrown when translating to {t2Type.Name}");
Debug.WriteLine($" - {e.ToString()}");
}
}