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
)
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.