"Fossies" - the Fresh Open Source Software Archive

Member "PowerShell-7.2.6/src/Microsoft.PowerShell.Security/security/AclCommands.cs" (11 Aug 2022, 58264 Bytes) of package /linux/misc/PowerShell-7.2.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C# source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AclCommands.cs" see the Fossies "Dox" file reference documentation.

    1 // Copyright (c) Microsoft Corporation.
    2 // Licensed under the MIT License.
    3 
    4 #pragma warning disable 1634, 1691
    5 #pragma warning disable 56506
    6 
    7 using System;
    8 using System.Collections.Generic;
    9 using System.Collections.ObjectModel;
   10 using System.ComponentModel;
   11 using System.Diagnostics.CodeAnalysis;
   12 using System.Globalization;
   13 using System.Management.Automation;
   14 using System.Management.Automation.Security;
   15 using System.Runtime.InteropServices;
   16 using System.Security.AccessControl;
   17 using System.Security.Principal;
   18 
   19 using Dbg = System.Management.Automation;
   20 
   21 namespace Microsoft.PowerShell.Commands
   22 {
   23     /// <summary>
   24     /// Defines the base class from which all Security Descriptor commands
   25     /// are derived.
   26     /// </summary>
   27     public abstract class SecurityDescriptorCommandsBase : PSCmdlet
   28     {
   29         /// <summary>
   30         /// Gets or sets the filter property.  The filter
   31         /// property allows for provider-specific filtering of results.
   32         /// </summary>
   33         [Parameter]
   34         public string Filter
   35         {
   36             get
   37             {
   38                 return _filter;
   39             }
   40 
   41             set
   42             {
   43                 _filter = value;
   44             }
   45         }
   46 
   47         /// <summary>
   48         /// Gets or sets the include property.  The include property
   49         /// specifies the items on which the command will act.
   50         /// </summary>
   51         [Parameter]
   52         public string[] Include
   53         {
   54             get
   55             {
   56                 return _include;
   57             }
   58 
   59             set
   60             {
   61                 _include = value;
   62             }
   63         }
   64 
   65         /// <summary>
   66         /// Gets or sets the exclude property.  The exclude property
   67         /// specifies the items on which the command will not act.
   68         /// </summary>
   69         [Parameter]
   70         public string[] Exclude
   71         {
   72             get
   73             {
   74                 return _exclude;
   75             }
   76 
   77             set
   78             {
   79                 _exclude = value;
   80             }
   81         }
   82 
   83         /// <summary>
   84         /// The context for the command that is passed to the core command providers.
   85         /// </summary>
   86         internal CmdletProviderContext CmdletProviderContext
   87         {
   88             get
   89             {
   90                 CmdletProviderContext coreCommandContext = new(this);
   91 
   92                 Collection<string> includeFilter =
   93                     SessionStateUtilities.ConvertArrayToCollection<string>(Include);
   94 
   95                 Collection<string> excludeFilter =
   96                     SessionStateUtilities.ConvertArrayToCollection<string>(Exclude);
   97 
   98                 coreCommandContext.SetFilters(includeFilter,
   99                                               excludeFilter,
  100                                               Filter);
  101 
  102                 return coreCommandContext;
  103             }
  104         }
  105 
  106         #region brokered properties
  107 
  108         /// <summary>
  109         /// Add brokered properties for easy access to important properties
  110         /// of security descriptor.
  111         /// </summary>
  112         internal static void AddBrokeredProperties(
  113             Collection<PSObject> results,
  114             bool audit,
  115             bool allCentralAccessPolicies)
  116         {
  117             foreach (PSObject result in results)
  118             {
  119                 if (audit)
  120                 {
  121                     // Audit
  122                     result.Properties.Add
  123                     (
  124                         new PSCodeProperty
  125                             (
  126                                 "Audit",
  127                                 typeof(SecurityDescriptorCommandsBase).GetMethod("GetAudit")
  128                             )
  129                     );
  130                 }
  131                 // CentralAccessPolicyId retrieval does not require elevation, so we always add this property.
  132                 result.Properties.Add
  133                 (
  134                     new PSCodeProperty
  135                         (
  136                             "CentralAccessPolicyId",
  137                             typeof(SecurityDescriptorCommandsBase).GetMethod("GetCentralAccessPolicyId")
  138                         )
  139                 );
  140 #if !CORECLR    // GetAllCentralAccessPolicies and GetCentralAccessPolicyName are not supported in OneCore powershell
  141                 // because function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.
  142                 if (allCentralAccessPolicies)
  143                 {
  144                     // AllCentralAccessPolicies
  145                     result.Properties.Add
  146                     (
  147                         new PSCodeProperty
  148                             (
  149                                 "AllCentralAccessPolicies",
  150                                 typeof(SecurityDescriptorCommandsBase).GetMethod("GetAllCentralAccessPolicies")
  151                             )
  152                     );
  153                 }
  154                 // CentralAccessPolicyName retrieval does not require elevation, so we always add this property.
  155                 result.Properties.Add
  156                 (
  157                     new PSCodeProperty
  158                         (
  159                             "CentralAccessPolicyName",
  160                             typeof(SecurityDescriptorCommandsBase).GetMethod("GetCentralAccessPolicyName")
  161                         )
  162                 );
  163 #endif
  164             }
  165         }
  166 
  167         /// <summary>
  168         /// Gets the Path of the provided PSObject.
  169         /// </summary>
  170         /// <param name="instance">
  171         /// The PSObject for which to obtain the path.
  172         /// </param>
  173         /// <returns>
  174         /// The path of the provided PSObject.
  175         /// </returns>
  176         public static string GetPath(PSObject instance)
  177         {
  178             if (instance == null)
  179             {
  180                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  181             }
  182             else
  183             {
  184                 // These are guaranteed to not be null, but even checking
  185                 // them for null causes a presharp warning
  186 #pragma warning disable 56506
  187 
  188                 // Get path
  189                 return instance.Properties["PSPath"].Value.ToString();
  190 #pragma warning restore 56506
  191             }
  192         }
  193 
  194         /// <summary>
  195         /// Gets the Owner of the provided PSObject.
  196         /// </summary>
  197         /// <param name="instance">
  198         /// The PSObject for which to obtain the Owner.
  199         /// </param>
  200         /// <returns>
  201         /// The Owner of the provided PSObject.
  202         /// </returns>
  203         public static string GetOwner(PSObject instance)
  204         {
  205             if (instance == null)
  206             {
  207                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  208             }
  209 
  210             if (!(instance.BaseObject is ObjectSecurity sd))
  211             {
  212                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  213             }
  214 
  215             // Get owner
  216             try
  217             {
  218                 IdentityReference ir = sd.GetOwner(typeof(NTAccount));
  219                 return ir.ToString();
  220             }
  221             catch (IdentityNotMappedException)
  222             {
  223                 // All Acl cmdlets returning SIDs will return a string
  224                 // representation of the SID in all cases where the SID
  225                 // cannot be mapped to a proper user or group name.
  226             }
  227 
  228             // We are here since we cannot get IdentityReference from sd..
  229             // So return sddl..
  230             return sd.GetSecurityDescriptorSddlForm(AccessControlSections.Owner);
  231         }
  232 
  233         /// <summary>
  234         /// Gets the Group of the provided PSObject.
  235         /// </summary>
  236         /// <param name="instance">
  237         /// The PSObject for which to obtain the Group.
  238         /// </param>
  239         /// <returns>
  240         /// The Group of the provided PSObject.
  241         /// </returns>
  242         public static string GetGroup(PSObject instance)
  243         {
  244             if (instance == null)
  245             {
  246                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  247             }
  248 
  249             if (!(instance.BaseObject is ObjectSecurity sd))
  250             {
  251                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  252             }
  253 
  254             // Get Group
  255             try
  256             {
  257                 IdentityReference ir = sd.GetGroup(typeof(NTAccount));
  258                 return ir.ToString();
  259             }
  260             catch (IdentityNotMappedException)
  261             {
  262                 // All Acl cmdlets returning SIDs will return a string
  263                 // representation of the SID in all cases where the SID
  264                 // cannot be mapped to a proper user or group name.
  265             }
  266 
  267             // We are here since we cannot get IdentityReference from sd..
  268             // So return sddl..
  269             return sd.GetSecurityDescriptorSddlForm(AccessControlSections.Group);
  270         }
  271         /// <summary>
  272         /// Gets the access rules of the provided PSObject.
  273         /// </summary>
  274         /// <param name="instance">
  275         /// The PSObject for which to obtain the access rules.
  276         /// </param>
  277         /// <returns>
  278         /// The access rules of the provided PSObject.
  279         /// </returns>
  280         public static AuthorizationRuleCollection GetAccess(PSObject instance)
  281         {
  282             if (instance == null)
  283             {
  284                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  285             }
  286 
  287             ObjectSecurity sd = instance.BaseObject as ObjectSecurity;
  288             if (sd == null)
  289             {
  290                 PSTraceSource.NewArgumentException(nameof(instance));
  291             }
  292 
  293             // Get DACL
  294             CommonObjectSecurity cos = sd as CommonObjectSecurity;
  295             if (cos != null)
  296             {
  297                 return cos.GetAccessRules(true, true, typeof(NTAccount));
  298             }
  299             else
  300             {
  301                 DirectoryObjectSecurity dos = sd as DirectoryObjectSecurity;
  302                 Dbg.Diagnostics.Assert(dos != null, "Acl should be of type CommonObjectSecurity or DirectoryObjectSecurity");
  303                 return dos.GetAccessRules(true, true, typeof(NTAccount));
  304             }
  305         }
  306 
  307         /// <summary>
  308         /// Gets the audit rules of the provided PSObject.
  309         /// </summary>
  310         /// <param name="instance">
  311         /// The PSObject for which to obtain the audit rules.
  312         /// </param>
  313         /// <returns>
  314         /// The audit rules of the provided PSObject.
  315         /// </returns>
  316         public static AuthorizationRuleCollection GetAudit(PSObject instance)
  317         {
  318             if (instance == null)
  319             {
  320                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  321             }
  322 
  323             ObjectSecurity sd = instance.BaseObject as ObjectSecurity;
  324             if (sd == null)
  325             {
  326                 PSTraceSource.NewArgumentException(nameof(instance));
  327             }
  328 
  329             CommonObjectSecurity cos = sd as CommonObjectSecurity;
  330             if (cos != null)
  331             {
  332                 return cos.GetAuditRules(true, true, typeof(NTAccount));
  333             }
  334             else
  335             {
  336                 DirectoryObjectSecurity dos = sd as DirectoryObjectSecurity;
  337                 Dbg.Diagnostics.Assert(dos != null, "Acl should be of type CommonObjectSecurity or DirectoryObjectSecurity");
  338                 return dos.GetAuditRules(true, true, typeof(NTAccount));
  339             }
  340         }
  341 
  342         /// <summary>
  343         /// Gets the central access policy ID of the provided PSObject.
  344         /// </summary>
  345         /// <param name="instance">
  346         /// The PSObject for which to obtain the central access policy ID.
  347         /// </param>
  348         /// <returns>
  349         /// The central access policy ID of the provided PSObject.
  350         /// </returns>
  351         public static SecurityIdentifier GetCentralAccessPolicyId(PSObject instance)
  352         {
  353             SessionState sessionState = new();
  354             string path = sessionState.Path.GetUnresolvedProviderPathFromPSPath(
  355                 GetPath(instance));
  356             IntPtr pSd = IntPtr.Zero;
  357 
  358             try
  359             {
  360                 // Get the file's SACL containing the CAPID ACE.
  361                 uint rs = NativeMethods.GetNamedSecurityInfo(
  362                     path,
  363                     NativeMethods.SeObjectType.SE_FILE_OBJECT,
  364                     NativeMethods.SecurityInformation.SCOPE_SECURITY_INFORMATION,
  365                     out IntPtr pOwner,
  366                     out IntPtr pGroup,
  367                     out IntPtr pDacl,
  368                     out IntPtr pSacl,
  369                     out pSd);
  370                 if (rs != NativeMethods.ERROR_SUCCESS)
  371                 {
  372                     throw new Win32Exception((int)rs);
  373                 }
  374 
  375                 if (pSacl == IntPtr.Zero)
  376                 {
  377                     return null;
  378                 }
  379 
  380                 NativeMethods.ACL sacl = Marshal.PtrToStructure<NativeMethods.ACL>(pSacl);
  381                 if (sacl.AceCount == 0)
  382                 {
  383                     return null;
  384                 }
  385 
  386                 // Extract the first CAPID from the SACL that does not have INHERIT_ONLY_ACE flag set.
  387                 IntPtr pAce = pSacl + Marshal.SizeOf(new NativeMethods.ACL());
  388                 for (ushort aceIdx = 0; aceIdx < sacl.AceCount; aceIdx++)
  389                 {
  390                     NativeMethods.ACE_HEADER ace = Marshal.PtrToStructure<NativeMethods.ACE_HEADER>(pAce);
  391                     Dbg.Diagnostics.Assert(ace.AceType ==
  392                         NativeMethods.SYSTEM_SCOPED_POLICY_ID_ACE_TYPE,
  393                         "Unexpected ACE type: " + ace.AceType.ToString(CultureInfo.CurrentCulture));
  394                     if ((ace.AceFlags & NativeMethods.INHERIT_ONLY_ACE) == 0)
  395                     {
  396                         break;
  397                     }
  398 
  399                     pAce += ace.AceSize;
  400                 }
  401 
  402                 IntPtr pSid = pAce + Marshal.SizeOf(new NativeMethods.SYSTEM_AUDIT_ACE()) -
  403                     Marshal.SizeOf(new uint());
  404                 bool ret = NativeMethods.IsValidSid(pSid);
  405                 if (!ret)
  406                 {
  407                     throw new Win32Exception(Marshal.GetLastWin32Error());
  408                 }
  409 
  410                 return new SecurityIdentifier(pSid);
  411             }
  412             finally
  413             {
  414                 NativeMethods.LocalFree(pSd);
  415             }
  416         }
  417 
  418 #if !CORECLR
  419         /// <summary>
  420         /// Gets the central access policy name of the provided PSObject.
  421         /// </summary>
  422         /// <remarks>
  423         /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.
  424         /// </remarks>
  425         /// <param name="instance">
  426         /// The PSObject for which to obtain the central access policy name.
  427         /// </param>
  428         /// <returns>
  429         /// The central access policy name of the provided PSObject.
  430         /// </returns>
  431         public static string GetCentralAccessPolicyName(PSObject instance)
  432         {
  433             SecurityIdentifier capId = GetCentralAccessPolicyId(instance);
  434             if (capId == null)
  435             {
  436                 return null; // file does not have the scope ace
  437             }
  438 
  439             int capIdSize = capId.BinaryLength;
  440             byte[] capIdArray = new byte[capIdSize];
  441             capId.GetBinaryForm(capIdArray, 0);
  442             IntPtr caps = IntPtr.Zero;
  443             IntPtr pCapId = Marshal.AllocHGlobal(capIdSize);
  444 
  445             try
  446             {
  447                 // Retrieve the CAP by CAPID.
  448                 Marshal.Copy(capIdArray, 0, pCapId, capIdSize);
  449                 IntPtr[] ppCapId = new IntPtr[1];
  450                 ppCapId[0] = pCapId;
  451                 uint rs = NativeMethods.LsaQueryCAPs(
  452                     ppCapId,
  453                     1,
  454                     out caps,
  455                     out uint capCount);
  456                 if (rs != NativeMethods.STATUS_SUCCESS)
  457                 {
  458                     throw new Win32Exception((int)rs);
  459                 }
  460 
  461                 if (capCount == 0 || caps == IntPtr.Zero)
  462                 {
  463                     return null;
  464                 }
  465 
  466                 // Get the CAP name.
  467                 NativeMethods.CENTRAL_ACCESS_POLICY cap = Marshal.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(caps);
  468                 // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes.
  469                 return Marshal.PtrToStringUni(cap.Name.Buffer, cap.Name.Length / 2);
  470             }
  471             finally
  472             {
  473                 Marshal.FreeHGlobal(pCapId);
  474                 uint rs = NativeMethods.LsaFreeMemory(caps);
  475                 Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS,
  476                     "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture));
  477             }
  478         }
  479 
  480         /// <summary>
  481         /// Gets the names and IDs of all central access policies available on the machine.
  482         /// </summary>
  483         /// <remarks>
  484         /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.
  485         /// </remarks>
  486         /// <param name="instance">
  487         /// The PSObject argument is ignored.
  488         /// </param>
  489         /// <returns>
  490         /// The names and IDs of all central access policies available on the machine.
  491         /// </returns>
  492         public static string[] GetAllCentralAccessPolicies(PSObject instance)
  493         {
  494             IntPtr caps = IntPtr.Zero;
  495 
  496             try
  497             {
  498                 // Retrieve all CAPs.
  499                 uint rs = NativeMethods.LsaQueryCAPs(
  500                     null,
  501                     0,
  502                     out caps,
  503                     out uint capCount);
  504                 if (rs != NativeMethods.STATUS_SUCCESS)
  505                 {
  506                     throw new Win32Exception((int)rs);
  507                 }
  508 
  509                 Dbg.Diagnostics.Assert(capCount < 0xFFFF,
  510                     "Too many central access policies");
  511                 if (capCount == 0 || caps == IntPtr.Zero)
  512                 {
  513                     return null;
  514                 }
  515 
  516                 // Add CAP names and IDs to a string array.
  517                 string[] policies = new string[capCount];
  518                 IntPtr capPtr = caps;
  519                 for (uint capIdx = 0; capIdx < capCount; capIdx++)
  520                 {
  521                     // Retrieve CAP name.
  522                     Dbg.Diagnostics.Assert(capPtr != IntPtr.Zero,
  523                         "Invalid central access policies array");
  524                     NativeMethods.CENTRAL_ACCESS_POLICY cap = Marshal.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(capPtr);
  525                     // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes.
  526                     policies[capIdx] = "\"" + Marshal.PtrToStringUni(
  527                         cap.Name.Buffer,
  528                         cap.Name.Length / 2) + "\"";
  529 
  530                     // Retrieve CAPID.
  531                     IntPtr pCapId = cap.CAPID;
  532                     Dbg.Diagnostics.Assert(pCapId != IntPtr.Zero,
  533                         "Invalid central access policies array");
  534                     bool ret = NativeMethods.IsValidSid(pCapId);
  535                     if (!ret)
  536                     {
  537                         throw new Win32Exception(Marshal.GetLastWin32Error());
  538                     }
  539 
  540                     SecurityIdentifier sid = new SecurityIdentifier(pCapId);
  541                     policies[capIdx] += " (" + sid.ToString() + ")";
  542 
  543                     capPtr += Marshal.SizeOf(cap);
  544                 }
  545 
  546                 return policies;
  547             }
  548             finally
  549             {
  550                 uint rs = NativeMethods.LsaFreeMemory(caps);
  551                 Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS,
  552                     "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture));
  553             }
  554         }
  555 #endif
  556 
  557         /// <summary>
  558         /// Gets the security descriptor (in SDDL form) of the
  559         /// provided PSObject.  SDDL form is the Security Descriptor
  560         /// Definition Language.
  561         /// </summary>
  562         /// <param name="instance">
  563         /// The PSObject for which to obtain the security descriptor.
  564         /// </param>
  565         /// <returns>
  566         /// The security descriptor of the provided PSObject, in SDDL form.
  567         /// </returns>
  568         public static string GetSddl(PSObject instance)
  569         {
  570             if (instance == null)
  571             {
  572                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  573             }
  574 
  575             if (!(instance.BaseObject is ObjectSecurity sd))
  576             {
  577                 throw PSTraceSource.NewArgumentNullException(nameof(instance));
  578             }
  579 
  580             string sddl = sd.GetSecurityDescriptorSddlForm(AccessControlSections.All);
  581             return sddl;
  582         }
  583 
  584         #endregion brokered properties
  585 
  586         /// <summary>
  587         /// The filter to be used to when globbing to get the item.
  588         /// </summary>
  589         private string _filter;
  590 
  591         /// <summary>
  592         /// The glob string used to determine which items are included.
  593         /// </summary>
  594         private string[] _include = Array.Empty<string>();
  595 
  596         /// <summary>
  597         /// The glob string used to determine which items are excluded.
  598         /// </summary>
  599         private string[] _exclude = Array.Empty<string>();
  600     }
  601 
  602 #if !UNIX
  603     /// <summary>
  604     /// Defines the implementation of the 'get-acl' cmdlet.
  605     /// This cmdlet gets the security descriptor of an item at the specified path.
  606     /// </summary>
  607     [Cmdlet(VerbsCommon.Get, "Acl", SupportsTransactions = true, DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096593")]
  608     public sealed class GetAclCommand : SecurityDescriptorCommandsBase
  609     {
  610         /// <summary>
  611         /// Initializes a new instance of the GetAclCommand
  612         /// class.  Sets the default path to the current location.
  613         /// </summary>
  614         public GetAclCommand()
  615         {
  616             // Default for path is the current location
  617             _path = new string[] { "." };
  618         }
  619         #region parameters
  620 
  621         private string[] _path;
  622 
  623         /// <summary>
  624         /// Gets or sets the path of the item for which to obtain the
  625         /// security descriptor.  Default is the current location.
  626         /// </summary>
  627         [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")]
  628         [ValidateNotNullOrEmpty()]
  629         public string[] Path
  630         {
  631             get
  632             {
  633                 return _path;
  634             }
  635 
  636             set
  637             {
  638                 _path = value;
  639             }
  640         }
  641 
  642         private PSObject _inputObject;
  643 
  644         /// <summary>
  645         /// InputObject Parameter
  646         /// Gets or sets the inputObject for which to obtain the security descriptor.
  647         /// </summary>
  648         [Parameter(Mandatory = true, ParameterSetName = "ByInputObject")]
  649         public PSObject InputObject
  650         {
  651             get
  652             {
  653                 return _inputObject;
  654             }
  655 
  656             set
  657             {
  658                 _inputObject = value;
  659             }
  660         }
  661 
  662         /// <summary>
  663         /// Gets or sets the literal path of the item for which to obtain the
  664         /// security descriptor.  Default is the current location.
  665         /// </summary>
  666         [Parameter(ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")]
  667         [Alias("PSPath")]
  668         [ValidateNotNullOrEmpty()]
  669         [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
  670         public string[] LiteralPath
  671         {
  672             get
  673             {
  674                 return _path;
  675             }
  676 
  677             set
  678             {
  679                 _path = value;
  680                 _isLiteralPath = true;
  681             }
  682         }
  683 
  684         private bool _isLiteralPath;
  685 
  686         /// <summary>
  687         /// Gets or sets the audit flag of the command.  This flag
  688         /// determines if audit rules should also be retrieved.
  689         /// </summary>
  690         [Parameter()]
  691         public SwitchParameter Audit
  692         {
  693             get
  694             {
  695                 return _audit;
  696             }
  697 
  698             set
  699             {
  700                 _audit = value;
  701             }
  702         }
  703 
  704         private SwitchParameter _audit;
  705 
  706 #if CORECLR
  707         /// <summary>
  708         /// Parameter '-AllCentralAccessPolicies' is not supported in OneCore powershell,
  709         /// because function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.
  710         /// </summary>
  711         private SwitchParameter AllCentralAccessPolicies
  712         {
  713             get; set;
  714         }
  715 #else
  716         /// <summary>
  717         /// Gets or sets the AllCentralAccessPolicies flag of the command. This flag
  718         /// determines whether the information about all central access policies
  719         /// available on the machine should be displayed.
  720         /// </summary>
  721         [Parameter()]
  722         public SwitchParameter AllCentralAccessPolicies
  723         {
  724             get
  725             {
  726                 return allCentralAccessPolicies;
  727             }
  728 
  729             set
  730             {
  731                 allCentralAccessPolicies = value;
  732             }
  733         }
  734 
  735         private SwitchParameter allCentralAccessPolicies;
  736 #endif
  737 
  738         #endregion
  739 
  740         /// <summary>
  741         /// Processes records from the input pipeline.
  742         /// For each input file, the command retrieves its
  743         /// corresponding security descriptor.
  744         /// </summary>
  745         protected override void ProcessRecord()
  746         {
  747             AccessControlSections sections =
  748                 AccessControlSections.Owner |
  749                 AccessControlSections.Group |
  750                 AccessControlSections.Access;
  751             if (_audit)
  752             {
  753                 sections |= AccessControlSections.Audit;
  754             }
  755 
  756             if (_inputObject != null)
  757             {
  758                 PSMethodInfo methodInfo = _inputObject.Methods["GetSecurityDescriptor"];
  759 
  760                 if (methodInfo != null)
  761                 {
  762                     object customDescriptor = null;
  763 
  764                     try
  765                     {
  766                         customDescriptor = PSObject.Base(methodInfo.Invoke());
  767 
  768                         if (customDescriptor is not FileSystemSecurity)
  769                         {
  770                             customDescriptor = new CommonSecurityDescriptor(false, false, customDescriptor.ToString());
  771                         }
  772                     }
  773                     catch (Exception)
  774                     {
  775                         // Calling user code, Catch-all OK
  776                         ErrorRecord er =
  777                         SecurityUtils.CreateNotSupportedErrorRecord(
  778                             UtilsStrings.MethodInvokeFail,
  779                             "GetAcl_OperationNotSupported"
  780                             );
  781 
  782                         WriteError(er);
  783                         return;
  784                     }
  785 
  786                     WriteObject(customDescriptor, true);
  787                 }
  788                 else
  789                 {
  790                     ErrorRecord er =
  791                         SecurityUtils.CreateNotSupportedErrorRecord(
  792                             UtilsStrings.GetMethodNotFound,
  793                             "GetAcl_OperationNotSupported"
  794                             );
  795 
  796                     WriteError(er);
  797                 }
  798             }
  799             else
  800             {
  801                 foreach (string p in Path)
  802                 {
  803                     List<string> pathsToProcess = new();
  804 
  805                     string currentPath = null;
  806                     try
  807                     {
  808                         if (_isLiteralPath)
  809                         {
  810                             pathsToProcess.Add(p);
  811                         }
  812                         else
  813                         {
  814                             Collection<PathInfo> resolvedPaths =
  815                                 SessionState.Path.GetResolvedPSPathFromPSPath(p, CmdletProviderContext);
  816                             foreach (PathInfo pi in resolvedPaths)
  817                             {
  818                                 pathsToProcess.Add(pi.Path);
  819                             }
  820                         }
  821 
  822                         foreach (string rp in pathsToProcess)
  823                         {
  824                             currentPath = rp;
  825 
  826                             CmdletProviderContext context = new(this.Context);
  827                             context.SuppressWildcardExpansion = true;
  828 
  829                             if (!InvokeProvider.Item.Exists(rp, false, _isLiteralPath))
  830                             {
  831                                 ErrorRecord er =
  832                                     SecurityUtils.CreatePathNotFoundErrorRecord(
  833                                                rp,
  834                                                "GetAcl_PathNotFound"
  835                                     );
  836 
  837                                 WriteError(er);
  838                                 continue;
  839                             }
  840 
  841                             InvokeProvider.SecurityDescriptor.Get(rp, sections, context);
  842 
  843                             Collection<PSObject> sd = context.GetAccumulatedObjects();
  844                             if (sd != null)
  845                             {
  846                                 AddBrokeredProperties(
  847                                     sd,
  848                                     _audit,
  849                                     AllCentralAccessPolicies);
  850                                 WriteObject(sd, true);
  851                             }
  852                         }
  853                     }
  854                     catch (NotSupportedException)
  855                     {
  856                         ErrorRecord er =
  857                             SecurityUtils.CreateNotSupportedErrorRecord(
  858                                 UtilsStrings.OperationNotSupportedOnPath,
  859                                 "GetAcl_OperationNotSupported",
  860                                 currentPath
  861                             );
  862 
  863                         WriteError(er);
  864                     }
  865                     catch (ItemNotFoundException)
  866                     {
  867                         ErrorRecord er =
  868                             SecurityUtils.CreatePathNotFoundErrorRecord(
  869                                 p,
  870                                 "GetAcl_PathNotFound_Exception"
  871                             );
  872 
  873                         WriteError(er);
  874                         continue;
  875                     }
  876                 }
  877             }
  878         }
  879     }
  880 
  881     /// <summary>
  882     /// Defines the implementation of the 'set-acl' cmdlet.
  883     /// This cmdlet sets the security descriptor of an item at the specified path.
  884     /// </summary>
  885     [Cmdlet(VerbsCommon.Set, "Acl", SupportsShouldProcess = true, SupportsTransactions = true, DefaultParameterSetName = "ByPath",
  886             HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096600")]
  887     public sealed class SetAclCommand : SecurityDescriptorCommandsBase
  888     {
  889         private string[] _path;
  890 
  891         /// <summary>
  892         /// Gets or sets the path of the item for which to set the
  893         /// security descriptor.
  894         /// </summary>
  895         [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")]
  896         public string[] Path
  897         {
  898             get
  899             {
  900                 return _path;
  901             }
  902 
  903             set
  904             {
  905                 _path = value;
  906             }
  907         }
  908 
  909         private PSObject _inputObject;
  910 
  911         /// <summary>
  912         /// InputObject Parameter
  913         /// Gets or sets the inputObject for which to set the security descriptor.
  914         /// </summary>
  915         [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByInputObject")]
  916         public PSObject InputObject
  917         {
  918             get
  919             {
  920                 return _inputObject;
  921             }
  922 
  923             set
  924             {
  925                 _inputObject = value;
  926             }
  927         }
  928 
  929         /// <summary>
  930         /// Gets or sets the literal path of the item for which to set the
  931         /// security descriptor.
  932         /// </summary>
  933         [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")]
  934         [Alias("PSPath")]
  935         [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
  936         public string[] LiteralPath
  937         {
  938             get
  939             {
  940                 return _path;
  941             }
  942 
  943             set
  944             {
  945                 _path = value;
  946                 _isLiteralPath = true;
  947             }
  948         }
  949 
  950         private bool _isLiteralPath;
  951 
  952         private object _securityDescriptor;
  953 
  954         /// <summary>
  955         /// Gets or sets the security descriptor object to be
  956         /// set on the target item(s).
  957         /// </summary>
  958         [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true, ParameterSetName = "ByPath")]
  959         [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true, ParameterSetName = "ByLiteralPath")]
  960         [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true, ParameterSetName = "ByInputObject")]
  961         public object AclObject
  962         {
  963             get
  964             {
  965                 return _securityDescriptor;
  966             }
  967 
  968             set
  969             {
  970                 _securityDescriptor = PSObject.Base(value);
  971             }
  972         }
  973 
  974 #if CORECLR
  975         /// <summary>
  976         /// Parameter '-CentralAccessPolicy' is not supported in OneCore powershell,
  977         /// because function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.
  978         /// </summary>
  979         private string CentralAccessPolicy { get; }
  980 #else
  981         private string centralAccessPolicy;
  982 
  983         /// <summary>
  984         /// Gets or sets the central access policy to be
  985         /// set on the target item(s).
  986         /// </summary>
  987         [Parameter(Position = 2, Mandatory = false, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")]
  988         [Parameter(Position = 2, Mandatory = false, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")]
  989         public string CentralAccessPolicy
  990         {
  991             get
  992             {
  993                 return centralAccessPolicy;
  994             }
  995 
  996             set
  997             {
  998                 centralAccessPolicy = value;
  999             }
 1000         }
 1001 #endif
 1002 
 1003         private SwitchParameter _clearCentralAccessPolicy;
 1004 
 1005         /// <summary>
 1006         /// Clears the central access policy applied on the target item(s).
 1007         /// </summary>
 1008         [Parameter(Mandatory = false, ParameterSetName = "ByPath")]
 1009         [Parameter(Mandatory = false, ParameterSetName = "ByLiteralPath")]
 1010         public SwitchParameter ClearCentralAccessPolicy
 1011         {
 1012             get
 1013             {
 1014                 return _clearCentralAccessPolicy;
 1015             }
 1016 
 1017             set
 1018             {
 1019                 _clearCentralAccessPolicy = value;
 1020             }
 1021         }
 1022 
 1023         private SwitchParameter _passthru;
 1024 
 1025         /// <summary>
 1026         /// Gets or sets the Passthru flag for the operation.
 1027         /// If true, the security descriptor is also passed
 1028         /// down the output pipeline.
 1029         /// </summary>
 1030         [Parameter()]
 1031         public SwitchParameter Passthru
 1032         {
 1033             get
 1034             {
 1035                 return _passthru;
 1036             }
 1037 
 1038             set
 1039             {
 1040                 _passthru = value;
 1041             }
 1042         }
 1043 
 1044         /// <summary>
 1045         /// Returns a newly allocated SACL with no ACEs in it.
 1046         /// Free the returned SACL by calling Marshal.FreeHGlobal.
 1047         /// </summary>
 1048         private static IntPtr GetEmptySacl()
 1049         {
 1050             IntPtr pSacl = IntPtr.Zero;
 1051             bool ret = true;
 1052 
 1053             try
 1054             {
 1055                 // Calculate the size of the empty SACL, align to DWORD.
 1056                 uint saclSize = (uint)(Marshal.SizeOf(new NativeMethods.ACL()) +
 1057                     Marshal.SizeOf(new uint()) - 1) & 0xFFFFFFFC;
 1058                 Dbg.Diagnostics.Assert(saclSize < 0xFFFF,
 1059                     "Acl size must be less than max SD size of 0xFFFF");
 1060 
 1061                 // Allocate and initialize the SACL.
 1062                 pSacl = Marshal.AllocHGlobal((int)saclSize);
 1063                 ret = NativeMethods.InitializeAcl(
 1064                     pSacl,
 1065                     saclSize,
 1066                     NativeMethods.ACL_REVISION);
 1067                 if (!ret)
 1068                 {
 1069                     throw new Win32Exception(Marshal.GetLastWin32Error());
 1070                 }
 1071             }
 1072             finally
 1073             {
 1074                 if (!ret)
 1075                 {
 1076                     Marshal.FreeHGlobal(pSacl);
 1077                     pSacl = IntPtr.Zero;
 1078                 }
 1079             }
 1080 
 1081             return pSacl;
 1082         }
 1083 
 1084         /// <summary>
 1085         /// Returns a newly allocated SACL with the supplied CAPID in it.
 1086         /// Free the returned SACL by calling Marshal.FreeHGlobal.
 1087         /// </summary>
 1088         /// <remarks>
 1089         /// Function 'LsaQueryCAPs' is not available in OneCoreUAP and NanoServer.
 1090         /// So the parameter "-CentralAccessPolicy" is not supported on OneCore powershell,
 1091         /// and thus this method won't be hit in OneCore powershell.
 1092         /// </remarks>
 1093         private IntPtr GetSaclWithCapId(string capStr)
 1094         {
 1095             IntPtr pCapId = IntPtr.Zero, pSacl = IntPtr.Zero;
 1096             IntPtr caps = IntPtr.Zero;
 1097             bool ret = true, freeCapId = true;
 1098             uint rs = NativeMethods.STATUS_SUCCESS;
 1099 
 1100             try
 1101             {
 1102                 // Convert the supplied SID from string to binary form.
 1103                 ret = NativeMethods.ConvertStringSidToSid(capStr, out pCapId);
 1104                 if (!ret)
 1105                 {
 1106                     // We may have got a CAP friendly name instead of CAPID.
 1107                     // Enumerate all CAPs on the system and try to find one with
 1108                     // a matching friendly name.
 1109                     // If we retrieve the CAPID from the LSA, the CAPID need not
 1110                     // be deallocated separately (but with the entire buffer
 1111                     // returned by LsaQueryCAPs).
 1112                     freeCapId = false;
 1113                     rs = NativeMethods.LsaQueryCAPs(
 1114                         null,
 1115                         0,
 1116                         out caps,
 1117                         out uint capCount);
 1118                     if (rs != NativeMethods.STATUS_SUCCESS)
 1119                     {
 1120                         throw new Win32Exception((int)rs);
 1121                     }
 1122 
 1123                     Dbg.Diagnostics.Assert(capCount < 0xFFFF,
 1124                         "Too many central access policies");
 1125                     if (capCount == 0 || caps == IntPtr.Zero)
 1126                     {
 1127                         return IntPtr.Zero;
 1128                     }
 1129 
 1130                     // Find the supplied string among available CAP names, use the corresponding CAPID.
 1131                     IntPtr capPtr = caps;
 1132                     for (uint capIdx = 0; capIdx < capCount; capIdx++)
 1133                     {
 1134                         Dbg.Diagnostics.Assert(capPtr != IntPtr.Zero,
 1135                             "Invalid central access policies array");
 1136                         NativeMethods.CENTRAL_ACCESS_POLICY cap = Marshal.PtrToStructure<NativeMethods.CENTRAL_ACCESS_POLICY>(capPtr);
 1137                         // LSA_UNICODE_STRING is composed of WCHARs, but its length is given in bytes.
 1138                         string capName = Marshal.PtrToStringUni(
 1139                             cap.Name.Buffer,
 1140                             cap.Name.Length / 2);
 1141                         if (capName.Equals(capStr, StringComparison.OrdinalIgnoreCase))
 1142                         {
 1143                             pCapId = cap.CAPID;
 1144                             break;
 1145                         }
 1146 
 1147                         capPtr += Marshal.SizeOf(cap);
 1148                     }
 1149                 }
 1150 
 1151                 if (pCapId == IntPtr.Zero)
 1152                 {
 1153                     Exception e = new ArgumentException(UtilsStrings.InvalidCentralAccessPolicyIdentifier);
 1154                     WriteError(new ErrorRecord(
 1155                         e,
 1156                         "SetAcl_CentralAccessPolicy",
 1157                         ErrorCategory.InvalidArgument,
 1158                         AclObject));
 1159                     return IntPtr.Zero;
 1160                 }
 1161 
 1162                 ret = NativeMethods.IsValidSid(pCapId);
 1163                 if (!ret)
 1164                 {
 1165                     throw new Win32Exception(Marshal.GetLastWin32Error());
 1166                 }
 1167 
 1168                 uint sidSize = NativeMethods.GetLengthSid(pCapId);
 1169 
 1170                 // Calculate the size of the SACL with one CAPID ACE, align to DWORD.
 1171                 uint saclSize = (uint)(Marshal.SizeOf(new NativeMethods.ACL()) +
 1172                     Marshal.SizeOf(new NativeMethods.SYSTEM_AUDIT_ACE()) +
 1173                     sidSize - 1) & 0xFFFFFFFC;
 1174                 Dbg.Diagnostics.Assert(saclSize < 0xFFFF,
 1175                     "Acl size must be less than max SD size of 0xFFFF");
 1176 
 1177                 // Allocate and initialize the SACL.
 1178                 pSacl = Marshal.AllocHGlobal((int)saclSize);
 1179                 ret = NativeMethods.InitializeAcl(
 1180                     pSacl,
 1181                     saclSize,
 1182                     NativeMethods.ACL_REVISION);
 1183                 if (!ret)
 1184                 {
 1185                     throw new Win32Exception(Marshal.GetLastWin32Error());
 1186                 }
 1187 
 1188                 // Add CAPID to the SACL.
 1189                 rs = NativeMethods.AddScopedPolicyIDAce(
 1190                     pSacl,
 1191                     NativeMethods.ACL_REVISION,
 1192                     NativeMethods.SUB_CONTAINERS_AND_OBJECTS_INHERIT,
 1193                     0,
 1194                     pCapId);
 1195                 if (rs != NativeMethods.STATUS_SUCCESS)
 1196                 {
 1197                     if (rs == NativeMethods.STATUS_INVALID_PARAMETER)
 1198                     {
 1199                         throw new ArgumentException(UtilsStrings.InvalidCentralAccessPolicyIdentifier);
 1200                     }
 1201                     else
 1202                     {
 1203                         throw new Win32Exception((int)rs);
 1204                     }
 1205                 }
 1206             }
 1207             finally
 1208             {
 1209                 if (!ret || rs != NativeMethods.STATUS_SUCCESS)
 1210                 {
 1211                     Marshal.FreeHGlobal(pSacl);
 1212                     pSacl = IntPtr.Zero;
 1213                 }
 1214 
 1215                 rs = NativeMethods.LsaFreeMemory(caps);
 1216                 Dbg.Diagnostics.Assert(rs == NativeMethods.STATUS_SUCCESS,
 1217                     "LsaFreeMemory failed: " + rs.ToString(CultureInfo.CurrentCulture));
 1218                 if (freeCapId)
 1219                 {
 1220                     NativeMethods.LocalFree(pCapId);
 1221                 }
 1222             }
 1223 
 1224             return pSacl;
 1225         }
 1226 
 1227         /// <summary>
 1228         /// Returns the current thread or process token with the specified privilege enabled
 1229         /// and the previous state of this privilege. Free the returned token
 1230         /// by calling NativeMethods.CloseHandle.
 1231         /// </summary>
 1232         private static IntPtr GetTokenWithEnabledPrivilege(
 1233             string privilege,
 1234             NativeMethods.TOKEN_PRIVILEGE previousState)
 1235         {
 1236             IntPtr pToken = IntPtr.Zero;
 1237             bool ret = true;
 1238 
 1239             try
 1240             {
 1241                 // First try to open the thread token for privilege adjustment.
 1242                 ret = NativeMethods.OpenThreadToken(
 1243                     NativeMethods.GetCurrentThread(),
 1244                     NativeMethods.TOKEN_QUERY | NativeMethods.TOKEN_ADJUST_PRIVILEGES,
 1245                     true,
 1246                     out pToken);
 1247 
 1248                 if (!ret)
 1249                 {
 1250                     if (Marshal.GetLastWin32Error() == NativeMethods.ERROR_NO_TOKEN)
 1251                     {
 1252                         // Client is not impersonating. Open the process token.
 1253                         ret = NativeMethods.OpenProcessToken(
 1254                             NativeMethods.GetCurrentProcess(),
 1255                             NativeMethods.TOKEN_QUERY | NativeMethods.TOKEN_ADJUST_PRIVILEGES,
 1256                             out pToken);
 1257                     }
 1258 
 1259                     if (!ret)
 1260                     {
 1261                         throw new Win32Exception(Marshal.GetLastWin32Error());
 1262                     }
 1263                 }
 1264 
 1265                 // Get the LUID of the specified privilege.
 1266                 NativeMethods.LUID luid = new();
 1267                 ret = NativeMethods.LookupPrivilegeValue(
 1268                     null,
 1269                     privilege,
 1270                     ref luid);
 1271                 if (!ret)
 1272                 {
 1273                     throw new Win32Exception(Marshal.GetLastWin32Error());
 1274                 }
 1275 
 1276                 // Enable the privilege.
 1277                 NativeMethods.TOKEN_PRIVILEGE newState = new();
 1278                 newState.PrivilegeCount = 1;
 1279                 newState.Privilege.Attributes = NativeMethods.SE_PRIVILEGE_ENABLED;
 1280                 newState.Privilege.Luid = luid;
 1281                 uint previousSize = 0;
 1282                 ret = NativeMethods.AdjustTokenPrivileges(
 1283                     pToken,
 1284                     false,
 1285                     ref newState,
 1286                     (uint)Marshal.SizeOf(previousState),
 1287                     ref previousState,
 1288                     ref previousSize);
 1289                 if (!ret)
 1290                 {
 1291                     throw new Win32Exception(Marshal.GetLastWin32Error());
 1292                 }
 1293             }
 1294             finally
 1295             {
 1296                 if (!ret)
 1297                 {
 1298                     NativeMethods.CloseHandle(pToken);
 1299                     pToken = IntPtr.Zero;
 1300                 }
 1301             }
 1302 
 1303             return pToken;
 1304         }
 1305 
 1306         /// Processes records from the input pipeline.
 1307         /// For each input file, the command sets its
 1308         /// security descriptor to the specified
 1309         /// Access Control List (ACL).
 1310         protected override void ProcessRecord()
 1311         {
 1312             ObjectSecurity aclObjectSecurity = _securityDescriptor as ObjectSecurity;
 1313 
 1314             if (_inputObject != null)
 1315             {
 1316                 PSMethodInfo methodInfo = _inputObject.Methods["SetSecurityDescriptor"];
 1317 
 1318                 if (methodInfo != null)
 1319                 {
 1320                     string sddl;
 1321 
 1322                     if (aclObjectSecurity != null)
 1323                     {
 1324                         sddl = aclObjectSecurity.GetSecurityDescriptorSddlForm(AccessControlSections.All);
 1325                     }
 1326                     else if (_securityDescriptor is CommonSecurityDescriptor aclCommonSD)
 1327                     {
 1328                         sddl = aclCommonSD.GetSddlForm(AccessControlSections.All);
 1329                     }
 1330                     else
 1331                     {
 1332                         Exception e = new ArgumentException("AclObject");
 1333                         WriteError(new ErrorRecord(
 1334                             e,
 1335                             "SetAcl_AclObject",
 1336                             ErrorCategory.InvalidArgument,
 1337                             AclObject));
 1338                         return;
 1339                     }
 1340 
 1341                     try
 1342                     {
 1343                         methodInfo.Invoke(sddl);
 1344                     }
 1345                     catch (Exception)
 1346                     {
 1347                         // Calling user code, Catch-all OK
 1348                         ErrorRecord er =
 1349                         SecurityUtils.CreateNotSupportedErrorRecord(
 1350                             UtilsStrings.MethodInvokeFail,
 1351                             "SetAcl_OperationNotSupported"
 1352                             );
 1353 
 1354                         WriteError(er);
 1355                         return;
 1356                     }
 1357                 }
 1358                 else
 1359                 {
 1360                     ErrorRecord er =
 1361                         SecurityUtils.CreateNotSupportedErrorRecord(
 1362                             UtilsStrings.SetMethodNotFound,
 1363                             "SetAcl_OperationNotSupported"
 1364                             );
 1365 
 1366                     WriteError(er);
 1367                 }
 1368             }
 1369             else
 1370             {
 1371                 if (Path == null)
 1372                 {
 1373                     Exception e = new ArgumentException("Path");
 1374                     WriteError(new ErrorRecord(
 1375                         e,
 1376                         "SetAcl_Path",
 1377                         ErrorCategory.InvalidArgument,
 1378                         AclObject));
 1379                     return;
 1380                 }
 1381 
 1382                 if (aclObjectSecurity == null)
 1383                 {
 1384                     Exception e = new ArgumentException("AclObject");
 1385                     WriteError(new ErrorRecord(
 1386                         e,
 1387                         "SetAcl_AclObject",
 1388                         ErrorCategory.InvalidArgument,
 1389                         AclObject));
 1390                     return;
 1391                 }
 1392 
 1393                 if (CentralAccessPolicy != null || ClearCentralAccessPolicy)
 1394                 {
 1395                     if (!DownLevelHelper.IsWin8AndAbove())
 1396                     {
 1397                         Exception e = new ParameterBindingException();
 1398                         WriteError(new ErrorRecord(
 1399                             e,
 1400                             "SetAcl_OperationNotSupported",
 1401                             ErrorCategory.InvalidArgument,
 1402                             null));
 1403                         return;
 1404                     }
 1405                 }
 1406 
 1407                 if (CentralAccessPolicy != null && ClearCentralAccessPolicy)
 1408                 {
 1409                     Exception e = new ArgumentException(UtilsStrings.InvalidCentralAccessPolicyParameters);
 1410                     ErrorRecord er =
 1411                     SecurityUtils.CreateInvalidArgumentErrorRecord(
 1412                         e,
 1413                         "SetAcl_OperationNotSupported"
 1414                         );
 1415 
 1416                     WriteError(er);
 1417                     return;
 1418                 }
 1419 
 1420                 IntPtr pSacl = IntPtr.Zero;
 1421                 NativeMethods.TOKEN_PRIVILEGE previousState = new();
 1422                 try
 1423                 {
 1424                     if (CentralAccessPolicy != null)
 1425                     {
 1426                         pSacl = GetSaclWithCapId(CentralAccessPolicy);
 1427                         if (pSacl == IntPtr.Zero)
 1428                         {
 1429                             SystemException e = new(UtilsStrings.GetSaclWithCapIdFail);
 1430                             WriteError(new ErrorRecord(e,
 1431                                                         "SetAcl_CentralAccessPolicy",
 1432                                                         ErrorCategory.InvalidResult,
 1433                                                         null));
 1434                             return;
 1435                         }
 1436                     }
 1437                     else if (ClearCentralAccessPolicy)
 1438                     {
 1439                         pSacl = GetEmptySacl();
 1440                         if (pSacl == IntPtr.Zero)
 1441                         {
 1442                             SystemException e = new(UtilsStrings.GetEmptySaclFail);
 1443                             WriteError(new ErrorRecord(e,
 1444                                                         "SetAcl_ClearCentralAccessPolicy",
 1445                                                         ErrorCategory.InvalidResult,
 1446                                                         null));
 1447                             return;
 1448                         }
 1449                     }
 1450 
 1451                     foreach (string p in Path)
 1452                     {
 1453                         Collection<PathInfo> pathsToProcess = new();
 1454 
 1455                         CmdletProviderContext context = this.CmdletProviderContext;
 1456                         context.PassThru = Passthru;
 1457                         if (_isLiteralPath)
 1458                         {
 1459                             string pathStr = SessionState.Path.GetUnresolvedProviderPathFromPSPath(
 1460                                 p, out ProviderInfo Provider, out PSDriveInfo Drive);
 1461                             pathsToProcess.Add(new PathInfo(Drive, Provider, pathStr, SessionState));
 1462                             context.SuppressWildcardExpansion = true;
 1463                         }
 1464                         else
 1465                         {
 1466                             pathsToProcess = SessionState.Path.GetResolvedPSPathFromPSPath(p, CmdletProviderContext);
 1467                         }
 1468 
 1469                         foreach (PathInfo pathInfo in pathsToProcess)
 1470                         {
 1471                             if (ShouldProcess(pathInfo.Path))
 1472                             {
 1473                                 try
 1474                                 {
 1475                                     InvokeProvider.SecurityDescriptor.Set(pathInfo.Path,
 1476                                                                           aclObjectSecurity,
 1477                                                                           context);
 1478 
 1479                                     if (CentralAccessPolicy != null || ClearCentralAccessPolicy)
 1480                                     {
 1481                                         if (!pathInfo.Provider.NameEquals(Context.ProviderNames.FileSystem))
 1482                                         {
 1483                                             Exception e = new ArgumentException("Path");
 1484                                             WriteError(new ErrorRecord(
 1485                                                 e,
 1486                                                 "SetAcl_Path",
 1487                                                 ErrorCategory.InvalidArgument,
 1488                                                 AclObject));
 1489                                             continue;
 1490                                         }
 1491 
 1492                                         // Enable the security privilege required to set SCOPE_SECURITY_INFORMATION.
 1493                                         IntPtr pToken = GetTokenWithEnabledPrivilege("SeSecurityPrivilege", previousState);
 1494                                         if (pToken == IntPtr.Zero)
 1495                                         {
 1496                                             SystemException e = new(UtilsStrings.GetTokenWithEnabledPrivilegeFail);
 1497                                             WriteError(new ErrorRecord(e,
 1498                                                                         "SetAcl_AdjustTokenPrivileges",
 1499                                                                         ErrorCategory.InvalidResult,
 1500                                                                         null));
 1501                                             return;
 1502                                         }
 1503 
 1504                                         // Set the file's CAPID.
 1505                                         uint rs = NativeMethods.SetNamedSecurityInfo(
 1506                                             pathInfo.ProviderPath,
 1507                                             NativeMethods.SeObjectType.SE_FILE_OBJECT,
 1508                                             NativeMethods.SecurityInformation.SCOPE_SECURITY_INFORMATION,
 1509                                             IntPtr.Zero,
 1510                                             IntPtr.Zero,
 1511                                             IntPtr.Zero,
 1512                                             pSacl);
 1513 
 1514                                         // Restore privileges to the previous state.
 1515                                         if (pToken != IntPtr.Zero)
 1516                                         {
 1517                                             NativeMethods.TOKEN_PRIVILEGE newState = new();
 1518                                             uint newSize = 0;
 1519                                             NativeMethods.AdjustTokenPrivileges(
 1520                                                 pToken,
 1521                                                 false,
 1522                                                 ref previousState,
 1523                                                 (uint)Marshal.SizeOf(newState),
 1524                                                 ref newState,
 1525                                                 ref newSize);
 1526 
 1527                                             NativeMethods.CloseHandle(pToken);
 1528                                             pToken = IntPtr.Zero;
 1529                                         }
 1530 
 1531                                         if (rs != NativeMethods.ERROR_SUCCESS)
 1532                                         {
 1533                                             Exception e = new Win32Exception(
 1534                                                 (int)rs,
 1535                                                 UtilsStrings.SetCentralAccessPolicyFail);
 1536                                             WriteError(new ErrorRecord(e,
 1537                                                                        "SetAcl_SetNamedSecurityInfo",
 1538                                                                        ErrorCategory.InvalidResult,
 1539                                                                        null));
 1540                                         }
 1541                                     }
 1542                                 }
 1543                                 catch (NotSupportedException)
 1544                                 {
 1545                                     ErrorRecord er =
 1546                                         SecurityUtils.CreateNotSupportedErrorRecord(
 1547                                             UtilsStrings.OperationNotSupportedOnPath,
 1548                                             "SetAcl_OperationNotSupported",
 1549                                             pathInfo.Path
 1550                                         );
 1551 
 1552                                     WriteError(er);
 1553                                 }
 1554                             }
 1555                         }
 1556                     }
 1557                 }
 1558                 finally
 1559                 {
 1560                     Marshal.FreeHGlobal(pSacl);
 1561                 }
 1562             }
 1563         }
 1564     }
 1565 #endif // !UNIX
 1566 }
 1567 
 1568 #pragma warning restore 56506