diff --git a/PInvoke/Security/AdvApi32/PSID.cs b/PInvoke/Security/AdvApi32/PSID.cs
index 2b60092a..d0cdd0e5 100644
--- a/PInvoke/Security/AdvApi32/PSID.cs
+++ b/PInvoke/Security/AdvApi32/PSID.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Vanara.Extensions;
@@ -13,6 +14,7 @@ namespace Vanara.PInvoke
{
/// Class representation of the native SID structure.
///
+ [DebuggerDisplay("{DebugString}")]
public class SafePSID : SafeMemoryHandle, IEquatable, IEquatable, IEquatable, ICloneable, ISecurityObject
{
/// Equivalent to a NULL pointer to a SID.
@@ -67,6 +69,27 @@ namespace Vanara.PInvoke
/// The SID length, in bytes.
public int Length => IsValidSid ? GetLengthSid(this) : 0;
+ /// Gets the string used to display in the debugger.
+ internal string DebugString
+ {
+ get
+ {
+ if (IsInvalid || IsClosed) return "NULL";
+ if (!IsValidSid) return "Invalid";
+ var d = ToString("D");
+ var n = ToString("P");
+ return d == n ? $"({d})" : $"{n} ({d})";
+ }
+ }
+
+ /// Creates a SID for predefined capability.
+ ///
+ /// Member of the KnownSIDCapability enumeration that specifies which capability the SID will identify.
+ ///
+ /// A instance.
+ public static SafePSID CreateCapability(KnownSIDCapability capability) =>
+ Init(KnownSIDAuthority.SECURITY_APP_PACKAGE_AUTHORITY, KnownSIDRelativeID.SECURITY_CAPABILITY_BASE_RID, (int)capability);
+
/// Copies the specified SID from a memory pointer to a instance.
/// The SID pointer. This value remains the responsibility of the caller to release.
/// A instance.
@@ -191,9 +214,46 @@ namespace Vanara.PInvoke
/// Returns a that represents this instance.
/// A that represents this instance.
- public override string ToString()
+ public override string ToString() => ToString(null);
+
+ /// Converts the value of this security identifier (SID) to its equivalent string representation according to the provided format specifier.
+ ///
+ /// A single format specifier that indicates how to format the value of this security identifier (SID). The format parameter can be
+ /// "B", "D", "N", or "P". If format is null or an empty string (""), "D" is used.
+ ///
+ /// The value of this security identifier (SID), in the specified format.
+ /// SID value is not a valid SID. - pSid
+ /// The value of format is not null, an empty string (""), "B", "D", "N", or "P".
+ ///
+ /// The following table shows the accepted format specifiers for the format parameter.
+ ///
+ /// -
+ /// Specifier
+ /// Format of return value
+ ///
+ /// -
+ /// "B"
+ ///
+ /// Binary hex dump representation of the SID.
+ ///
+ ///
+ /// -
+ /// "D"
+ /// SDDL representation of the SID.
+ ///
+ /// -
+ /// "N"
+ /// The NT4 style name (domain\username) corresponding to the SID.
+ ///
+ /// -
+ /// "P"
+ /// The internet style name (UPN) corresponding to the SID.
+ ///
+ ///
+ ///
+ public string ToString(string format)
{
- try { return ConvertSidToStringSid(this); }
+ try { return ((PSID)handle).ToString(format); }
catch { return !IsInvalid && !IsClosed ? "Invalid" : "0"; }
}
@@ -295,4 +355,113 @@ namespace Vanara.PInvoke
}
}
}
+
+ /// Extension methods for PSID instances.
+ public static class PSIDExtensions
+ {
+ /// Determines equality of two PSID instances.
+ /// The first PSID.
+ /// The second PSID.
+ /// if the SID structures are equal; otherwise.
+ public static bool Equals(this PSID psid1, PSID psid2) => AdvApi32.EqualSid(psid1, psid2);
+
+ /// Gets the binary form of the SID structure.
+ /// The SID structure pointer.
+ /// The binary form (byte array) of the SID structure.
+ public static byte[] GetBinaryForm(this PSID pSid) => pSid.IsValidSid() ? ((IntPtr)pSid).ToArray(pSid.Length()) : (new byte[0]);
+
+ ///
+ /// Validates a security identifier (SID) by verifying that the revision number is within a known range, and that the number of
+ /// subauthorities is less than the maximum.
+ ///
+ /// A pointer to the SID structure to validate. This parameter cannot be NULL.
+ ///
+ /// If the SID structure is valid, the return value is . If the SID structure is not valid, the return value is .
+ ///
+ public static bool IsValidSid(this PSID pSid) => AdvApi32.IsValidSid(pSid);
+
+ /// Returns the length, in bytes, of a valid security identifier (SID).
+ /// A pointer to the SID structure whose length is returned. The structure is assumed to be valid.
+ ///
+ /// If the SID structure is valid, the return value is the length, in bytes, of the SID structure. If the SID structure is not valid,
+ /// the return value is 0.
+ ///
+ public static int Length(this PSID pSid) => AdvApi32.IsValidSid(pSid) ? AdvApi32.GetLengthSid(pSid) : 0;
+
+ /// Converts the value of a security identifier (SID) to its equivalent string representation according to the provided format specifier.
+ /// A pointer to a valid SID structure.
+ ///
+ /// A single format specifier that indicates how to format the value of this security identifier (SID). The format parameter can be
+ /// "B", "D", "N", or "P". If format is null or an empty string (""), "D" is used.
+ ///
+ /// The value of this security identifier (SID), in the specified format.
+ /// SID value is not a valid SID. - pSid
+ /// The value of format is not null, an empty string (""), "B", "D", "N", or "P".
+ ///
+ /// The following table shows the accepted format specifiers for the format parameter.
+ ///
+ /// -
+ /// Specifier
+ /// Format of return value
+ ///
+ /// -
+ /// "B"
+ ///
+ /// Binary hex dump representation of the SID.
+ ///
+ ///
+ /// -
+ /// "D"
+ /// SDDL representation of the SID.
+ ///
+ /// -
+ /// "N"
+ /// The NT4 style name (domain\username) corresponding to the SID.
+ ///
+ /// -
+ /// "P"
+ /// The internet style name (UPN) corresponding to the SID.
+ ///
+ ///
+ ///
+ public static string ToString(this PSID pSid, string format)
+ {
+ if (!pSid.IsValidSid())
+ throw new ArgumentException("SID value is not a valid SID.", nameof(pSid));
+ switch (format)
+ {
+ case "B":
+ var len = pSid.Length();
+ return pSid.GetBinaryForm().ToHexDumpString(len, len, 0).Trim(' ', '\r', '\n');
+
+ case "D":
+ case null:
+ case "":
+ return AdvApi32.ConvertSidToStringSid(pSid);
+
+ case "N":
+ case "P":
+ using (var hPol = AdvApi32.LsaOpenPolicy(AdvApi32.LsaPolicyRights.POLICY_ALL_ACCESS))
+ {
+ var flag = format == "P" ? AdvApi32.LsaLookupSidsFlags.LSA_LOOKUP_PREFER_INTERNET_NAMES : 0;
+ try
+ {
+ AdvApi32.LsaLookupSids2(hPol, flag, 1, new[] { pSid }, out var memDoms, out var memNames).ThrowIfFailed();
+ memDoms.Dispose();
+ using (memNames)
+ {
+ return memNames.ToStructure().Name;
+ }
+ }
+ catch (Exception)
+ {
+ goto case "D";
+ }
+ }
+
+ default:
+ throw new FormatException();
+ }
+ }
+ }
}
\ No newline at end of file