Copy-Acl

Copy-Acl

Rate This
  • Comments 16

Today my wife told me about a problem on the family PC.  There were a bunch of PDF files in a directory that had the wrong permissions so my son couldn’t access them.  She modified the ACL on one of them using Explorer and verified that that was the fix.  (This is from a test I ran)

image

She then selected them all and tried to do it all at once but when she brought up the Properties, it didn’t have the Security Page anymore:

image

She wanted to know if there was some trick to set the ACLs all at once.  I told her that PowerShell could do that.  I showed her how to use Get-Acl and Set-Acl and she gave me a look like, “you expect me to remember that?” and asked, “why don’t you just have a COPY-ACL’ cmdlet.  I told her her how “to ship is to choose” but she wasn’t having any of it.  She clearly thought I was an idiot for not having shipped Copy-Acl.  You know what – I totally get it.  As a user – who cares how tough it is to ship software at Microsoft?  All that matters is that you have a need and we either meet it or we don’t.  Sadly that doesn’t change the reality of what it takes to ship things at Microsoft but it does provide some energy to write/share scripts.

As such, I spent a few minutes and wrote Copy-Acl.  I hope you enjoy it.  I’ve also attached it as a file to this blog. 

Enjoy!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

 

-------------------------------------------------------------------------------------------

 

<#
.SYNOPSIS
Copy the ACL from one file to other files

.DESCRIPTION
Takes a file and copies its ACL to one or more other files.

.PARAMETER FromPath
Path of the File to get the ACL from.

.PARAMETER Destination
Path to one or more files to copy the ACL to.

.PARAMETER Passthru
Returns an object representing the security descriptor.  By default, this cmdlet does not generate any output.

.INPUTS
You can Pipeline any object with a Property named "PSPath", "FullName" or "Destination".

.EXAMPLE
PS> Copy-Acl Referencefile.txt (dir c:\temp\*xml)

.EXAMPLE
PS> dir c:\files *.xml -recurse | Copy-Acl ReferenceFile.txt

.LINK
Get-Acl
Set-Acl

.NOTES
Author:  Jeffrey Snover

#>
#requires -Version 2.0
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(position=0,Mandatory=$true)]
[String]$FromPath,

[Parameter(Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
[Alias("PSpath","fullname")]
[String[]]$Destination,

[Parameter(Mandatory=$false)]
[Switch]$PassThru
)
Begin
{
    if (! (Test-Path $FromPath))
    {
        $ErrorRecord = New-Object System.Management.Automation.ErrorRecord  (
            (New-Object Exception "FromPath ($fromPath) does not point to an existing object"),
            "Copy-Acl.TestPath",
            "ObjectNotFound",
            $FromPath
         )

        $PSCmdlet.ThrowTerminatingError($ErrorRecord)
    }
    $acl = Get-Acl $FromPath
}
Process
{
    foreach ($Dest in @($Destination))
    {
        if ($pscmdlet.ShouldProcess($Dest))
        {
            Set-Acl -Path $Dest -AclObject $acl -Passthru:$PassThru
        }
    }
}

Attachment: Copy-Acl.ps1
Leave a Comment
  • Please add 2 and 2 and type the answer here:
  • Post
  • Great

    now just need a copy-acl that works on OU's in AD. this might work, I'll test it later

  • PingBack from http://asp-net-hosting.simplynetdev.com/copy-acl/

  • This wouldn't work if files have different owners.

    Also, might be easier to automate this:

    get-acl file.ext | set-acl <...>

    effect will the same.

  • Interesting Finds: May 11, 2009

  • @ the earlier comment: this works sufficiently well against AD.

    @ Jeffrey: this is a fantastic feature and fills a feature-gap that's been too-long unplugged... but, what's still missing is the capability to take an existing file/object ACL and dump it into some interim format (XML perhaps) that allows it to become portable between disconnected systems.  Something like -

     get-acl c:\source.FILE | export-cliXML storeACL.tmp

    ... move storeACL.tmp to an appropriate location and -

     import-cmiXML storeACL.tmp | set-acl d:\target.FILE

  • FYI,

    'Set-AuthenticodeSignature .\Copy-Acl.ps1 $cert' fails with Status:UnknownError.

    Using Notepad, I changed the encoding from 'Unicode big endian' to Unicode, and the previous Set-AuthenticodeSignature command worked.

  • Awesome… now we can copy ACLs between files. Next we need to be able to get a “ADD-Acl” which I guess

  • Jeffrey,

    Wonderful stuff and interesting too - your wife see a glaring frailty in the Windows UI (Vista - W7); you take 2 minutes to cough up a cmdlet (nee script) and dismiss it as a user script! You know I think you need to get your wife into the PowerShell usability labs!

    So keeping on this subject - where is a usable version of xcacls.vbs; your team cannot be so naive (academically orientated not user orientated?) as to not know of its uses/benefits in the real world. Surely 2 minutes to cough up a copy-acl script or 1 hour for a PowerShell developer to create PS version of a fully functioning xcacls would be well worth it?

    Sometimes I see "to ship is to choose" is lame; just as your wife did - but maybe I have a more profound need than most - as your wife did in this case. Am i the only one in the computing world to have been pestering for this (decent acl support) for a long time? Anyway - for me, one reason not port one of my great vbs/hta scripts.

    I just understand your wife's infuriation in this case. Just think about a normal Windows UI user - you can't change multiple acl's in one go - in the "dark ages" of, what was it called, XP, this was all fine! Now us admin's, especially with the new fangled, bells and whistle PowerShell have all that don't we - no sorry; but "to ship..." you get my point!

    Anyway sorry for the diatribe here; I really empathize with your wife as it plucks a chord; how about msft singing her up for the labs?

    Anyway best whishes - and you (and your team) are doing a generally great job; BUT FIX/IMPROVE acl stuff!

    Jeff if it only took 2 minutes for this script - you must be able to get proper acl support into PowerShell before v2 ships?.

    Bye and lots of support,

    Pete Gomersall

  • Pete,

    I couldn't agree with you more on very eloquent written piece. Although Powershell is powerfull and a lot of hard work has been done I can't help but wanting this to be more a tool for SA community (the quick and dirty scripting to get the job done in a few say "minutes") not the developers we have to hire to do the job.

    Thanks,

    Jack

  • There is already command cacls which work on directories and child objects. What is the issue in using that ?

  • Jeffrey, great stuff.

    I already earlier commented on the ACL stuff in another post.

    Better ACL support would of cource be great, but just fixing the ACL which is already in V1 would also be better IMHO. Literal paths is still not supported by Get-ACL/Set-ACL in CTP3, which makes it impossible to Set/Get ACLs on files with reserved characters like square brackets "[]".

    Jeffrey, thanks for all the stuff you are doing, but please get this one fixed before V2 - I (we) need it a lot.

  • Excellent stuff Jeff, i am just getting started with power shell and so far loving it.

  • Is there a way in PowerShell to add commands to the desktop shell?

    Adding menu items "Copy ACL", "Paste ACL (Replace)" and "Paste ACL (Add)" to the file menu would perhaps be all that would be required to add this to the UI.

  • I tried using this to set up permissions for an alternate program files like so (on Win7 x64), but it did not work:

    PS C:\Users\Me\Documents> .\copy-acl.ps1

    cmdlet copy-acl.ps1 at command pipeline position 1

    Supply values for the following parameters:

    FromPath: c:\Program Files

    Destination[0]: d:\Program Files

    Destination[1]:

    Set-Acl : The security identifier is not allowed to be the owner of this object.

    At C:\Users\Me\Documents\copy-acl.ps1:68 char:20

    +             Set-Acl <<<<  -Path $Dest -AclObject $acl -Passthru:$PassThru

       + CategoryInfo          : InvalidOperation: (D:\Program Files:String) [Set-Acl], InvalidOperationException

       + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.SetAclCommand

    What am I missing?

  • I tried to run your script but got this error:

    PS C:\scripts> .\copy-Acl.ps1

    Set-Acl : Cannot convert 'System.Object[]' to the type 'System.Security.AccessControl.ObjectSecurity' required by parameter 'AclObject'

    . Specified method is not supported.

    At C:\scripts\Copy-Acl.ps1:68 char:43

    +             Set-Acl -Path $Dest -AclObject <<<<  $acl -Passthru:$PassThru

       + CategoryInfo          : InvalidArgument: (:) [Set-Acl], ParameterBindingException

       + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.SetAclCommand

    Set-Acl : Cannot convert 'System.Object[]' to the type 'System.Security.AccessControl.ObjectSecurity' required by parameter 'AclObject'

    . Specified method is not supported.

    At C:\scripts\Copy-Acl.ps1:68 char:43

    +             Set-Acl -Path $Dest -AclObject <<<<  $acl -Passthru:$PassThru

       + CategoryInfo          : InvalidArgument: (:) [Set-Acl], ParameterBindingException

       + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.SetAclCommand

Page 1 of 2 (16 items) 12