Export Folder Permissions - powershell

I want to Export folder Permissions for a subset of folders.
Each Folder in Department has two child's, Public and Internal.
For example, I want the permissions of the folder D:\Data\Department\Science\Public or D:\Data\Department\Sales\Public.
$FolderPath = dir -Directory -Path "D:\Data\Department" -Force
$Report = #()
Foreach ($Folder in $FolderPath)
{
$Folder2 = Join-Path -Path $Folder -ChildPath "Public"
$Acl = Get-Acl $Folder2.FullName
foreach ($Access in $acl.Access)
{
$Properties = [ordered]#{'FolderName'=$Folder2.FullName;'AD
Group or User'=$Access.IdentityReference;'Permissions'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
$Report += New-Object -TypeName PSObject -Property $Properties
}
}
$Report | Export-Csv -path "C:\Users\adminrw\FolderPermissions.csv"
Error:
Get-Acl : Cannot validate argument on parameter 'Path'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:7 char:16
+ $Acl = Get-Acl $Folder2.FullName
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-Acl], ParameterBindingValidationException

It looks like the Join-Path in your script is taking the Name of the folder and adding the childpath to it. This results in $Folder2 ending up like SomeFolder\Public
Try using
$Folder2 = Join-Path -Path $Folder.FullName -ChildPath "Public"
This will make $Folder2 : D:\Data\Department\SomeFolder\Public

I've corrected script. Please use below code:
$FolderPath = dir -Directory -Path "D:\Data\Department" -Force | Select *
$Report = #()
Foreach ($Folder in $FolderPath)
{
$Folder2 = Join-Path -Path $Folder.FullName -ChildPath "Public"
$Acl = Get-Acl $Folder2
foreach ($Access in $acl.Access)
{
$Properties = [ordered]#{'FolderName'=$Folder2.FullName;'AD
Group or User'=$Access.IdentityReference;'Permissions'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
$Report += New-Object -TypeName PSObject -Property $Properties
}
}
$Report | Export-Csv -path "C:\Users\adminrw\FolderPermissions.csv"

Related

Shared file area - how can I improve my PowerShell script?

I am trying to make a script that creates file areas for different groups in a company. All the members in the group need to have full access to the shared files, but any member from the other groups can not have access - not even see them. This is what I have. For the "Limit access" section you need to change up the name of the group, and repeat this for each group. Can I put this in a foreach loop?
I am new to Powershell and really want to learn how to improve my script. So how can I improve and automate this code?
# Creates file areas
$folders = ('C:\shares\it-drift','C:\shares\dev-team','C:\shares\regnskap','C:\shares\renhold','C:\shares\HR')
mkdir -path $folders
$folders | Where-Object {$_ -like "*shares*"} | ForEach-Object {$name = (Get-Item $_).name; $DfsPath = (‘\\sec.core\files\’ + $name); $targetPath = (‘\\dc1\’ + $name);New-DfsnFolderTarget -Path $dfsPath -TargetPath $targetPath}
# Limits access
$folder = ('C:\shares\dev-team')
$ACL = Get-Acl -path \\sec.core\files\dev-team
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("sec.core\g_dev_team","FullControl","Allow")
$ACL.SetAccessRule($AccessRule)
$ACL | Set-Acl -Path "\\sec.core\files\dev-team"
$ACL.SetAccessRuleProtection($true,$true)
$ACL = Get-Acl "\\sec.core\files\dev-team"
$ACL.Access | where {$_.IdentityReference -eq "BUILTIN\Users" } | foreach { $acl.RemoveAccessRuleSpecific($_) }
Set-Acl "\\sec.core\files\dev-team" $acl
(Get-ACL -Path "\\sec.core\files\dev-team").Access | Format-Table IdentityReference,FileSystemRights,AccessControlType,IsInherited,InheritanceFlags -AutoSize
Appreciate all tips:)
Here is how you can automate set of the same ACL for each shared folder:
# Creates file areas
$folders = #(
'C:\shares\it-drift'
'C:\shares\dev-team'
'C:\shares\regnskap'
'C:\shares\renhold'
'C:\shares\HR'
)
mkdir -path $folders
$folders | Where-Object {$_ -like "*shares*"} |
ForEach-Object {
$name = (Get-Item $_).name
$DfsPath = '\\sec.core\files\' + $name
$targetPath = '\\dc1\' + $name
New-DfsnFolderTarget -Path $dfsPath -TargetPath $targetPath
}
# Limits access
foreach($folder in $folders)
{
$leaf = Split-Path $folder -Leaf
$path="\\sec.core\files\$leaf"
$acl = Get-Acl -Path $path
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("sec.core\g_dev_team","FullControl","Allow")
$acl.SetAccessRule($AccessRule)
Set-Acl -Path $path -AclObject $acl
$acl.SetAccessRuleProtection($true,$true)
$acl = Get-Acl "\\sec.core\files\dev-team"
$acl.Access.where({$_.IdentityReference -eq "BUILTIN\Users"}).foreach({
$acl.RemoveAccessRuleSpecific($_)
})
Set-Acl -Path $path -AclObject $acl
(Get-ACL -Path $path).Access |
Format-Table IdentityReference,FileSystemRights,AccessControlType,IsInherited,InheritanceFlags -AutoSize
}
Try to use vertical coding instead of horizontal coding. People reading your code will be thankful.

Exporting & Import Folder Structure and rigts with CSV file using PS Script

I'm BRAND new to ps scripting and am looking for some advice please.
We replace a data share server every couple of years, and creating the complete folder structure and permissions by hand is very tedious, so I'm trying to automate it with a powershell script. Since I'm new I've been googling for some examples and snippets and have been compiling what I need from it.
My export script reads the folder structure and rites it to a text file, and my import script creates it once I move the folder over to new server, no problem.
The problem comes with the access rights.
It reads the rights and writes it to a CSV, but once I try to import it I get an error:
new-object : Cannot convert argument "2", with value: "TRUE", for
"FileSystemAccessRule" to type
"System.Security.AccessControl.AccessControlType": "Cannot convert
value "TRUE" to type
"System.Security.AccessControl.AccessControlType". Error: "Unable to
match the identifier name TRUE to a valid enumerator name. Specify one
of the following enumerator names and try again: Allow, Deny"" At
line:1 char:23
... ccessRule = new-object System.Security.AccessControl.FileSystemAccess ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (:) [New-Object], MethodException
FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
As I understand it it's looking for a Allow/Deny and not a True/False, but the export gives a True/False. So I'm guessing there's something wrong with my export...
Here is my code if anyone could point me in the correct direction I would greatly appreciate it!!
(Let me know if I should post ALL the code, I just don't want to clutter any more than I already do :D)
Export:
$FolderPath = dir -Directory -Path $DriveLetter -Force
$Report = #()
Foreach ($Folder in $FolderPath)
{
if ($Folder.Name -notlike '*$RECYCLE.BIN*')
{
if ($Folder.Name -notlike '*System Volume Information*')
{
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access)
{
$Properties = [ordered]#{'FolderName'=$Folder.Name;'IDRef'=$Access.IdentityReference;'FSRights'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
$Report += New-Object -TypeName PSObject -Property $Properties
}
}
}
}
$Report | Export-Csv -path $ExportACL -NoTypeInformation
Import:
foreach ( $LItem in $ACL_Imp )
{
$path_full = $Drivepath.ToString() + $LItem.FolderName
$ACL_Set = Get-Acl $path_full
$permission = $LItem.IDRef, $LItem.FSRights, $LItem.Inherited
$accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission <<<--- Error occurs here
$ACL_Set.SetAccessRule($accessRule)
$ACL_Set | Set-Acl $path_full
}
Example of one user in the export csv ( I remove the drive letter cause it isn't the same drive letter always.)
#TYPE System.Management.Automation.PSCustomObject;;; FolderName;IDRef;FSRights;Inherited
Data\UserA;Domain\UserA;FullControl;FALSE
Data\UserA;NT AUTHORITY\SYSTEM;FullControl;TRUE
Data\UserA;DOMAIN\UserB;FullControl;TRUE
Data\UserA;BUILTIN\Administrators;FullControl;TRUE
Data\UserA;DOMAIN\GRP_A;ReadAndExecute, Synchronize;TRUE
Data\UserA;Domain\GRP_A;ReadAndExecute, Synchronize;TRUE
Once again thanks in advance for any assistance!
And if you can't provide any, thanx for taking the time to check it out anycase!! :)
I've changed the number of variables I export and import, and that seemed to do the trick. (Exporting all variables, and only using 5)
I'm posting my Full Code in case someone else also wants to use this, or want to modify for their needs :)
Hope this will help someone in the future, and that my comments make sense..
Our Directory structure:
ImportExport <-- Location of scripts and output files (whole folder to be copied to new server)
Shared
Software
Users/UserA/
Users/UserB/
....
Users/UserZ/
Export:
#Variables
$drivepath = Get-Location #Get working drives' letter
$DriveLetter = Split-Path -qualifier $drivepath
$ExportACL = $DriveLetter.ToString() + "\ImportExport\export_acl.csv" #ACL Location
$ExportFolders = $DriveLetter.ToString() + "\ImportExport\export_folders.txt" #File with List of Folders
$UsersPath = $DriveLetter.ToString() + "\Users" #"Users" folders location on working drive located in Data folder
#Read user access levels on each folder on working drive and write to file.
cd.. #<-- add this if script is not run from within the PS environment.
$FolderPath = dir -Directory -Path $DriveLetter -Force
$Report = #()
Foreach ($Folder in $FolderPath)
{
if ($Folder.Name -notlike '*$RECYCLE.BIN*')
{
if ($Folder.Name -notlike '*ImportExport*')
{
if ($Folder.Name -notlike '*System Volume Information*')
{
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access)
{
$Properties = [ordered]#{'FolderName'=$Folder.Name;'FSRights'=$Access.FileSystemRights;'ACType'=$Access.AccessControlType;'IDRef'=$Access.IdentityReference;'Inherited'=$Access.IsInherited;'IFlags'=$Access.InheritanceFlags;'PFlags'=$Access.PropagationFlags}
$Report += New-Object -TypeName PSObject -Property $Properties
}
}
}
}
}
$Report | Export-Csv -path $ExportACL -NoTypeInformation
#Read user access levels on each child folder of Users folders on working drive and add to file.
$FolderPath = dir -Directory -Path $UsersPath -Force
$UserReport = #()
Foreach ($Folder in $FolderPath)
{
if ($Folder.Name -notlike '*$RECYCLE.BIN*')
{
if ($Folder.Name -notlike '*ImportExport*')
{
if ($Folder.Name -notlike '*System Volume Information*')
{
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access)
{
$StrFolderPath = $Folder.Parent.ToString() + "\" + $Folder.BaseName
$Properties = [ordered]#{'FolderName'=$StrFolderPath;'FSRights'=$Access.FileSystemRights;'ACType'=$Access.AccessControlType;'IDRef'=$Access.IdentityReference;'Inherited'=$Access.IsInherited;'IFlags'=$Access.InheritanceFlags;'PFlags'=$Access.PropagationFlags}
$UserReport += New-Object -TypeName PSObject -Property $Properties
}
}
}
}
}
$UserReport | Export-Csv -append $ExportACL
#Read Directory Structure and Export to File
$Dirs = Dir -Directory -Path $DriveLetter -Force
foreach($Dir in $Dirs)
{
if ($Dir.Name -notlike '*$RECYCLE.BIN*')
{
if ($Dir.Name -notlike '*ImportExport*')
{
if ($Dir.Name -notlike '*System Volume Information*')
{
$Dir.Name | out-file -Append $ExportFolders
}
}
}
}
$Dirs = Get-ChildItem -Path $UsersPath -Force
foreach($Dir in $Dirs)
{
$DirName = "Users\" + $Dir.Name
$DirName | out-file -Append $ExportFolders
}
Before import I open csv file in excel and make it different columns, so I use ";" as the delimiter, I'm struggling if I do not edit it. Variables with multiple values is split with a "," and that messes up the import.
Also, due to Admin rights needs to apply ACL, script needs to be run within elevated PS Environment, can't figure out how to do it outside. Can probably run a batch file to do a RunAs, but I had enough of this scripts for the time being. :p
Import:
#Variables
$drivepath = Get-Location #Get working drives' letter
$DriveLetter = Split-Path -qualifier $drivepath
$ImportACL = $DriveLetter.ToString() + "\ImportExport\export_acl.csv" #ACL Location
$ACL_Imp = Import-Csv $ImportACL -Delimiter ';' #Import ACL
$ImportFolders = $DriveLetter.ToString() + "\ImportExport\export_folders.txt" #File with List of Folders
$UsersPath = $DriveLetter.ToString() + "\Users" #Users' folder location on working drive
#Create Folders from text file.
Get-Content $ImportFolders | %{mkdir "$DriveLetter\$_"}
#Apply ACL to created Folder structure
foreach ( $LItem in $ACL_Imp )
{
$path_full = $Drivepath.ToString() + $LItem.FolderName
$ACL_Set = Get-Acl $path_full
$permission = $LItem.IDRef, $LItem.FSRights, $LItem.IFlags, $LItem.PFlags, $LItem.ACType
$accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission
$ACL_Set.SetAccessRule($accessRule)
$ACL_Set | Set-Acl $path_full
}

NTFS Permission for single user only by using powershell

I am trying to create the user folder for each AD Users. For each folder, I want the folder only accessed by that AD users only.
The finally result I want:
FolderName: "UserAFolder"
Goal: only UserA in "UserAFolder"
But the result is
FolderName: "UserAFolder"
UserA, UserB, UserC ... are all in "UserAFolder"
$folderpath = "\\san\Shares\UserFolders\"
$ulist =import-csv -Path C:\aduserlist.csv
foreach($list in $ulist)
{
$users = $list.username
$newpath = $folderpath+$users
New-Item -ItemType Directory -Path $folderpath -Name $users
$rights = "Modify"
$inheritanceFlag = "ContainerInherit,ObjectInherit"
$propagationFlag = "None"
$type = "Allow"
$objACL = Get-Acl $newpath
$entries = $users, $rights,$inheritanceFlag,$propagationFlag,$type
$rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $entries
$objACL.SetAccessRule($rule)
$objACL | Set-Acl -Path $newpath
}
The original Code of ACL is work. Just Parent Folder inheritance issue.
The NTFS Security
$folderpath = "\\san\Shares\UserFolders\"
$ulist =import-csv -Path C:\aduserlist.csv
foreach($list in $ulist){
$users = $list.username
$newpath = $folderpath+$users
New-Item -ItemType Directory -Path $folderpath -Name $users
$users = $list.username
$ADUser = $list.email
$newpath = $folderpath+$users
Add-NTFSAccess $newpath -Account $ADUser -AccessRights Modify -PassThru
}

PowerShell Removing Folder Permission for Deleted AD User Accounts

Once a User is removed in AD their name is changes to a S-X-XX-XXX
I have a script to pull all folders where the S-X-XX-XXX has permissions, what I am trying to do is take that list of Folders and remove all S-X-XX-XXX's.
Code
<# The S-* is to represent the User ID that I am wanting to remove their folder permissions #>
$TargetUser = "S-*"
$TargetPath = "C:\Depts"
$Paths = get-childitem -path $TargetPath -Recurse -Directory
$FolderList = $Paths.FullName
ForEach ($Folder in $FolderList) {
$ACL = Get-Acl -Path $Folder
$ACLlist = $ACL.Access | where {$_.IdentityReference -like "*mike*"}
$RemoveUser = $ACLlist.IdentityReference
if ($ACLlist.IdentityReference -like "$TargetUser") {
Write-Host $Folder
Write-Host $RemoveUser
$ACE = New-Object System.Security.Accesscontrol.FileSystemAccessRule($RemoveUser, "None", "ContainerInherit,ObjectInherit", "InheritOnly", "Deny")
$ACL.AddAccessRule($ACE)
Set-Acl -Path $Folder -AclObject $ACL
}
}
I have found code on how to set folder permission from another folders permissions, however this are users that were not added through inheritance.
I know I am missing something simple so any help would be great.
Folder Permissions
Big thanks to everyone that replied, I appreciate you guys taking the time to help.
You can check what type of user login in acl, you don't need template.And you must go for each access rule in each folder to check this,because removeaccesrule method take only one object at time.
$DebugPreference = 'Continue'
$TargetPath = "D:\testdir"
$Paths = get-childitem -path $TargetPath -Recurse -Directory
$FolderList = $Paths.FullName
ForEach ($Folder in $FolderList) {
$ACLs = Get-Acl -Path $Folder
foreach($acl in $ACLs.Access){
If (($acl.IdentityReference -is [System.Security.Principal.SecurityIdentifier]) -and (-not $acl.IsInherited)){
Write-Debug ("Removing ACl for {0}`r`n" -f $acl.IdentityReference.Value)
[Void]$ACLs.RemoveAccessRule($acl)
}
}
Write-Debug ("Setting ACL for {0}`r`n" -f $folder.FullName)
Set-Acl -path $folder -aclObject $ACLs
}
I have one more solution:
Use module ntfsSecurity(folder and files management manual)
Lists all permissions that can no longer be resolved. This normally happens if the account is no longer available so the permissions show up as a SID and not as an account name.
To remove all non-resolvable or orphaned permissions you can use the following line. But be very careful with that as maybe the account is not resolvable due to a network problem.
Install-Module -Name NTFSSecurity
dir -Recurse | Get-NTFSOrphanedAccess | Remove-NTFSAccess
The answer for the problem is below.
Clear
$TargetUser = Read-Host -Prompt "Enter the target account you are targeting [Full or Parital works]"
$RootPath = Read-Host -Prompt "Enter the root folder to start looking in and removing permissions"
$SubPaths = Get-ChildItem -Path $RootPath -Recurse -Directory
$SubFolderList = $SubPaths.FullName
$rootdone = $false
$FolderPurgeList = #()
if ($rootdone -eq $false) {
$ACL = Get-Acl -Path $RootPath
$ACLlist = $ACL.Access | where {$_.IdentityReference -like "*$TargetUser*"}
$RemoveUser = $ACLlist.IdentityReference
$count = $RemoveUser.count
ForEach ($UserName in $RemoveUser ) {
$UserID = New-Object System.Security.Principal.Ntaccount ($UserName)
$ACL.PurgeAccessRules($UserID)
$ACL | Set-Acl $RootPath
$itemHasPerm = New-Object –TypeName PSObject
$itemHasPerm | Add-Member –MemberType NoteProperty –Name "Target User" -Value $UserName
$itemHasPerm | Add-Member –MemberType NoteProperty –Name "Folder Path" -Value $RootPath
$FolderPurgeList += $itemHasPerm
$count -= 1
}
if ($count -eq 0 ) {
$rootdone = $true
}
}
if ($rootdone -eq $true) {
ForEach ($SubFolder in $SubFolderList) {
$ACL = Get-Acl -Path $SubFolder
$ACLlist = $ACL.Access | where {$_.IdentityReference -like "*$TargetUser*"}
$RemoveUser = $ACLlist.IdentityReference
ForEach ($UserName in $RemoveUser ) {
$UserID = New-Object System.Security.Principal.Ntaccount ($UserName)
$ACL.PurgeAccessRules($UserID)
$ACL | Set-Acl $SubFolder
$itemHasPerm = New-Object –TypeName PSObject
$itemHasPerm | Add-Member –MemberType NoteProperty –Name "Target User" -Value $UserName
$itemHasPerm | Add-Member –MemberType NoteProperty –Name "Folder Path" -Value $SubFolder
$FolderPurgeList += $itemHasPerm
}
}
}
$FolderPurgeList
$DateStamp = Get-Date -Format "dd-MMM-yyyy - hh-ss"
$FolderPurgeList | Export-CSV $env:USERProfile\Documents\Purged_Permission_List_$DateStamp.csv

backup and restore permissions

I am currently using the following script to export the permissions, take ownership of a folder and then remove all permissions from that folder. The folder list is taken from a text file.
$InputFile = "C:\temp\Folders.txt"
$OutputFile = "C:\temp\FolderPermissions.txt"
$FolderList = Get-Content $InputFile
foreach ($Folder in $FolderList) {
Get-Acl $folder | Format-List >>$OutputFile
$acl = Get-ACL -Path $folder
$acl.SetAccessRuleProtection($True, $True)
Set-Acl -Path $folder -AclObject $acl
$ACL = Get-ACL -Path $Folder
$Rules = $ACL.Access | Where-Object {$_.IdentityReference -notmatch 'Admin'}
foreach ($Rule in $Rules) {
[void]$ACL.RemoveAccessRule($Rule)
}
Set-Acl -Path $folder -AclObject $acl
}
I really want to be able to reverse this, but cannot figure out how to reapply the permissions from the file that it exports.
List format is okay for human readers, but it's not really suitable for restoring data from a file. Save the full path and SDDL of each folder to a CSV:
foreach ($Folder in $FolderList) {
Get-Acl $folder | Select-Object #{n='Path';e={$Folder.FullName}}, Sddl |
Export-Csv $OutputFile -NoType -Append
...
}
That should allow you to restore the security information like this:
Import-Csv $OutputFile | ForEach-Object {
$acl = Get-Acl -Path $_.Path
$acl.SetSecurityDescriptorSddlForm($_.Sddl)
Set-Acl -Path $_.Path -AclObject $acl
}