Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Set-Acl very slow?

1,235 views
Skip to first unread message

BBF

unread,
Jun 15, 2010, 11:14:09 AM6/15/10
to
I put together a script that uses the SET-ACL cmdlet to apply file system
permissions to directories listed in an input file. The script seems to
work fine, but is extremely slow if the directory contains large number of
folders\files.

I put together a batch script that utilizes XCACLS.vbs which runs a lot
faster. I'm wondering why the powershell script is running slower. Does
anyone have any ideas?

Xcacls script completed in 10 minutes.
Powershell script was still processing after 18 hours.

Both scripts were configured to modify the same directories.
Both scripts were configured to modify NTFS permissions on a remote system
using UNC based paths.
The folder that the powershell script hung on contained approx 14GB of data.
224,000 files and 4,475 folders.

Here's the scripts that I used.
=====================================
Powershell
=====================================
Function SetPerms{
Switch($_.Propagate.ToUpper()){
"NO"{
$inherit = [system.security.accesscontrol.InheritanceFlags]('None')
$propagation = [system.security.accesscontrol.PropagationFlags]('None')
Log "`tSuccess: Progagation - This folder only"
}
"YES"{
$inherit =
[system.security.accesscontrol.InheritanceFlags]('ContainerInherit,
ObjectInherit')
$propagation = [system.security.accesscontrol.PropagationFlags]('None')
Log "`tSuccess: Progagation - This folder, subfolders, and files"
}
Default{Log "No Propagate flag set.";Break}
}

$path = $_.Path
$acl = get-acl -path $path

$account = New-Object system.security.principal.ntaccount($_.Account)
try {
$sid = $account.translate([system.security.principal.securityidentifier])
}
Catch [System.Management.Automation.MethodInvocationException]{
Log "`tError: SID translation error - $Account"
do {

Try{
$prompt = new-object -comobject MSScriptControl.ScriptControl
$prompt.language = "vbscript"
$prompt.addcode("function getInput() getInput = inputbox(`"The following
account is not valid:`" & vbCrlf & vbCrlf & `"Account: $Account`" & vbCrlf
& `"Path: $Path`" & vbCrlf & vbCrlf & `"Please enter a valid account.`" &
vbCrlf & `"Format: Domain\UserName`",`"Resolve Account Error`") end function"
)
$account = New-Object
system.security.principal.ntaccount($prompt.eval("getInput"))
$sid = $account.translate([system.security.principal.securityidentifier])
}
Catch [System.Management.Automation.MethodInvocationException]{
Log "`tError: SID translation error - $Account"
}
Catch [System.Management.Automation.PSArgumentException]{
Log "`tError: SID unresolved. Setting ACL skipped"
Break
}
Catch {
Log "`tError: Unknown"
}
} until ($sid -is [object])
}
Catch{
Log "Error: Unknown - $Account"
}
If($sid -is [object]){
$accessrule = New-Object
system.security.AccessControl.FileSystemAccessRule($sid,$_.Permission,
$inherit, $propagation, 'Allow')
$acl.AddAccessRule($accessrule)

Try{
set-acl -aclobject $acl $path
}
Catch{
Log "`tError: setting ACLs - $Account ($($_.Permission))`r"
Break
}
Finally{
Log "`tSuccess: Permissions assigned - $Account ($($_.Permission))`r"
}
}
}

Function DisableInheritance{
$inherit =
[system.security.accesscontrol.InheritanceFlags]('ContainerInherit,
ObjectInherit')
$propagation = [system.security.accesscontrol.PropagationFlags]('None')

$acl = get-acl -path $_.Path

$account = New-Object system.security.principal.ntaccount('Administrators')
$sid = $account.translate([system.security.principal.securityidentifier])
$accessrule = New-Object
system.security.AccessControl.FileSystemAccessRule($sid, 'FullControl',
$inherit, $propagation, 'Allow')
$acl.AddAccessRule($accessrule)

$account = New-Object system.security.principal.ntaccount('System')
$sid = $account.translate([system.security.principal.securityidentifier])
$accessrule = New-Object
system.security.AccessControl.FileSystemAccessRule($sid, 'FullControl',
$inherit, $propagation, 'Allow')
$acl.AddAccessRule($accessrule)

$account = New-Object system.security.principal.ntaccount('Creator Owner')
$sid = $account.translate([system.security.principal.securityidentifier])
$accessrule = New-Object
system.security.AccessControl.FileSystemAccessRule($sid, 'FullControl',
$inherit, $propagation, 'Allow')
$acl.AddAccessRule($accessrule)
$acl.SetAccessRuleProtection($TRUE,$FALSE)
set-acl -aclobject $acl $_.Path
Log "`tSuccess: Inheritance Disabled"
}

Function Log($message){
Write-Host $message
Add-Content -Path $((Get-Location -PSProvider
FileSystem).ProviderPath+'\'+$scriptName+'.log') -Value $message
}

CLS
$startTime=Get-Date
$scriptName =
$myinvocation.mycommand.Name.substring(0,$myinvocation.mycommand.Name.lastindexofany('.'))
#$scriptName = "SetPerms"
$inputFile = $scriptName+".csv"
Log "Running $($myinvocation.mycommand.Name) : Starting at
$($startTime.ToLongTimeString())`r"
try {
$csv = Import-Csv $inputFile
#$error[0].exception.psobject.typenames #Identify the error type
}
catch [System.IO.FileNotFoundException] {
Clear-Host
Log "Error: $((Get-Location -PSProvider
FileSystem).ProviderPath)\$inputFile not found."
break
}
catch {
Clear-Host
$error[0].exception.psobject.typenames #Identify the error type
Log "Error: Undetermined"
break
}
$count=0
$csv | foreach {
$count++
IF($csv.count -gt 1){Log "$([Math]::Round((($count/$csv.Count) *
100),2))%`t[$count of $($csv.count)]`t$($_.path) : $($_.Account) :
$($(Get-Date).ToLongTimeString())"}
$dirExists = test-path $_.Path -PathType Container
Log "`t$($_.Path)"
if ( ! $dirExists ) {
Log "Error: Path doesn't exist"
}
Else{
Log "`tSuccess: Directory found."
DisableInheritance
SetPerms
}
}
Log "Script Run Time: $($(Get-Date).Subtract($startTime).minutes) minutes"
Log "Script completed at: $(get-Date -format g)"

==============================
Batch Script
==============================
REM echo off
@echo Set NTFS Permissions

for /f "skip=1 tokens=1,2,3,4 delims=," %%I in (SetPerms.csv) do (
@CSCRIPT XCACLS.VBS "%%I" /E /G "NT AUTHORITY\SYSTEM":F /I REMOVE
@CSCRIPT XCACLS.VBS "%%I" /E /G "BUILTIN\Administrators":F
@CSCRIPT XCACLS.VBS "%%I" /E /G "Creator Owner":F
@CSCRIPT XCACLS.VBS "%%I" /E /G "%%J":"%%K" /SPEC %%L
)

Bob Landau

unread,
Jun 15, 2010, 9:57:32 PM6/15/10
to
This is a know problem that has to do with .NET there's really nothing
powershell can do. In .NET 4.0 the situation has been improved.

http://msdn.microsoft.com/en-us/library/ms171868.aspx#core_new_features_and_improvements

File System Enumeration Improvements

Like you I was also unfortunate to bump into this. I'm not sure whether this
can easily within a script.

I don't know what trouble you can get into by loading .NET 4.0 assemblies
into Powershell 2.0.

My suggestion in this case is to keep with your VBScript solution.

0 new messages