powershell permissions - powershell

I am currently using this to get a list of all permissions for specific folders.
`$InputFile = "C:\temp\Folders.txt"
$OutputFile = "C:\temp\FolderPermissions.txt"
$FolderList = Get-Content $InputFile
ForEach ($Folder in $FolderList)
{
Get-Acl $folder | Format-list >>$OutputFile
}
`
What i would like is for it to then remove all access apart from administrator from each of the specified folders.
I have looked at using SetAccessControl but can only manage to get it to remove all.
Could someone please point me in the right direction.
Thanks

The following code will remove any user execpt users matching 'administrator'
If you want to add more accounts add it to the Where-Object filter, for example:
Where-Object {$_.IdentityReference -match 'Administrator' -or $_.IdentityReference -eq 'NT AUTHORITY\SYSTEM'}
$InputFile = "C:\temp\Folders.txt"
$OutputFile = "C:\temp\FolderPermissions.txt"
$FolderList = Get-Content $InputFile
ForEach ($Folder in $FolderList)
{
Get-Acl $folder | Format-list >>$OutputFile
### Remove all ACL Rules exepet 'Administrator(s)'
$ACL = Get-ACL -Path $Folder
$Rules = $ACL.Access | Where-Object {$_.IdentityReference -notmatch 'Administrator'}
Foreach ($Rule in $Rules)
{
[Void]$ACL.RemoveAccessRule($Rule)
}
Set-Acl -Path $folder -AclObject $acl
}

Related

Powershell get-acl add user first and last name

I have the following code that returns the ntfs permissions for a particular folder path.
$folders = Get-ChildItem -path d:\test" -recurse -force | ?{ $_.psiscontainer }
$output = #()
foreach($folder in $folders)
{
$rights = Get-Acl -path $folder.fullname
foreach($right in $rights.Access)
{
$properties = [ordered]#{'foldername'=$folder.fullname;'username'=$right.identityreference;'permissions'=$right.filesystemrights}
$output += New-Object -TypeName psobject -Property $properties
}
}
$output | export-csv d:\output\folders_temp1.csv -NoTypeInformation -Encoding UTF8
Though it displays the username along with its respective permissions, I would like to display the first and last name associated to that user from the active directory.
Any ideas on how can that be achieved?
Thank you for your help.
Here is how I would approach this, using Group-Object so that you're not querying Active Directory for the same user over and over for each Access Control List.
It's important to note that #() and += is inefficient and that PSCustomObject can be casted which is also, more efficient than using an ordered hashtable and then converting it to a New-Object.
Another efficiency improvement, thanks to Mathias R. Jessen for his helpful feedback, is to implement a hash table ($map) to have a reference of the IdentityReference already queried, by doing so we would only be querying Active Directory only once per unique user.
# $_.PSIsContainer => Can be replaced with -Directory
$folders = Get-ChildItem -Path "D:\test" -Recurse -Force -Directory
$map = #{}
$output = foreach($folder in $folders)
{
$rights = Get-Acl -Path $folder.fullname
$groups = $rights.Access | Group-Object IdentityReference
foreach($group in $groups)
{
if(-not $map.ContainsKey($group.Name))
{
$ref = Split-Path $group.Name -Leaf
$user = Get-ADUser -LDAPFilter "(name=$ref)"
$map[$group.Name] = $user
}
$aduser = $map[$group.Name]
foreach($acl in $group.Group)
{
[pscustomobject]#{
GivenName = $aduser.GivenName
Surname = $aduser.Surname
Foldername = $folder.Fullname
UserName = $acl.IdentityReference
Permissions = $acl.FilesystemRights
}
}
}
}
$output | Export-Csv D:\output\folders_temp1.csv -NoTypeInformation -Encoding UTF8

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.

Add NTFS access to files with subfolders from CSV file

I try to add NTFS access to the shortcuts.
I have the csv file that contains:
Name,AD
Steps Recorder,Group_312312
Snipping Tool,Group_545345
$FolderPath = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\"
$file = "C:\Users\adm\Desktop\Group.csv"
$groups = Get-Content $file | ConvertFrom-Csv
foreach ($group in $groups){
Add-NTFSAccess -Path (Join-Path -Path $FolderPath -ChildPath ($group.Name+".lnk")) `
-Account $group.AD `
-AccessRights ReadAndExecute `
}
I have a lot of subfolders with *.lnk files in $FolderPath. But in this way, the scripts find only in $FolderPath without subfolders. How can I change the script to find all *.lnk files include subfolders?
For example:
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\My_programs\OneDrive.lnk
For this, I think you need a different approach, where you get a collection of *.lnk files recursively and filter to get only those which have a BaseName property that can be found in the CSV.
Next, use Group-Object to group (make sub-collections) of these FileInfo objects, based on their BaseName.
According to the docs, the Path parameter on the Add-NTFSAccess cmdlet can take an array of paths (FullName properties) and these can be piped through to it, so we can send each subcollection all at once:
$FolderPath = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories"
$file = "C:\Users\adm\Desktop\Group.csv"
$groups = Import-Csv -Path $file
# get a list of *.lnk FileIfo objects where the file's BaseName can be found in the
# CSV column 'Name'. Group these files on their BaseName properties
$linkfiles = Get-ChildItem -Path $FolderPath -Filter '*.lnk' -File -Recurse -Force |
Where-Object { $groups.Name -contains $_.BaseName } |
Group-Object BaseName
# iterate through the grouped *.lnk files
$linkfiles | ForEach-Object {
$baseName = $_.Name # the name of the Group is the BaseName of the files in it
$adGroup = ($groups | Where-Object { $_.Name -eq $baseName }).AD
# pipe all items in the group through to the Add-NTFSAccess cmdlet
# see parameter Path at https://ntfssecurity.readthedocs.io/en/latest/Cmdlets/Add-NTFSAccess/
$_.Group | Add-NTFSAccess -Account $adGroup -AccessRights ReadAndExecute
}
UPDATE
# this is where the output 'log' csv file goes
$outputFile = "C:\Users\adm\Desktop\GroupReport.csv"
# get a list of *.lnk FileIfo objects where the file's BaseName can be found in the
# CSV column 'Name'. Group these files on their BaseName properties
$linkfiles = Get-ChildItem -Path $FolderPath -Filter '*.lnk' -File -Recurse -Force |
Where-Object { $groups.Name -contains $_.BaseName } |
Group-Object BaseName
# iterate through the grouped *.lnk files and add the group permission
# capture the results in a variable $log to output as CSV
$linkfiles | ForEach-Object {
$baseName = $_.Name # the name of the Group is the BaseName of the files in it
$adGroup = ($groups | Where-Object { $_.Name -eq $baseName }).AD
# create a new access rule
# see: https://learn.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.filesystemaccessrule
$rule = [System.Security.AccessControl.FileSystemAccessRule]::new($adGroup, "ReadAndExecute", "Allow")
$_.Group | ForEach-Object {
# get the current ACL of the file
$acl = Get-Acl -Path $_.FullName
# add the new rule to the ACL
$acl.SetAccessRule($rule)
$acl | Set-Acl $_.FullName
# output for logging csv
[PsCustomObject]#{
'Group' = $adGroup
'File' = $_.FullName
}
}
} | Export-Csv -Path $outputFile -NoTypeInformation

Get user of directory (Get-ACL) in folder structure with PowerShell, is there an easier way?

this script works for finding a particular user who has any explicit permissions on a folder within a folder structure, which is good! However, is there an easier way to list the folder path and $_.Access.IdentityReference.Value without having to loop my way in? Or, is this actually okay?
$foldStruct = get-childitem "C:\temp" -recurse -Attributes D | get-acl
ForEach ($fold in $foldStruct) {
ForEach ($perm in $fold.Access.IdentityReference) {
ForEach ($user in $perm.Value) {
If ($user -like "Dom\A*" -or $user -like "Dom\B*") {
Write-Host $user
Write-Host $fold.Path
}
}
}
}
It's debatable if this IS easier.
A more PowerShell way is to have objects as output.
instead of two -like I'd use the RegEx based -match with an alternation
the nested ForEach could be replaced with a Where-Object and a Select-Object
the Path would include Microsoft.PowerShell.Core\FileSystem:: I'd remove that with a -split '::'.
## Q:\Test\2019\02\07\SO_54569198.ps1
$Base = "C:\temp"
# to use a -match instead of -like anchor at begin and escape the \ => \\
$Users = "^Dom\\A|^Dom\\B"
$folderACLs = Get-ChildItem $Base -Recurse -Directory | Get-Acl |
Where-Object {$_.Access.IdentityReference.Value -match $Users } |
Select-Object #{n='User';e={($_.Access.IdentityReference.Value|?{$_ -match $Users})}},
#{n='Path';e={($_.Path -split '::')[1] }}
The output could/would include multiple users in the column, so to seperate them:
ForEach($folderACL in $folderACLs){
ForEach($User in ($folderACL.User){
[PSCustomObject]#{
User = $User
Path = ($_.folderACL.Path -split '::')[1]
}
}
}
I was thinking somewhere around the same thing as LotPings, using a regex -match to filter the users instead of doing -like twice.
I came up with this:
$users = '^Dom\\[AB].*' # regex to find usernames beginning with 'A' or 'B'
$subfolders = Get-ChildItem -Path "C:\Temp" -Recurse -Directory
foreach ($folder in $subfolders) {
$folder | Get-Acl | ForEach-Object { $_.Access } |
Where-Object {$_.IdentityReference.Value -match $users} | ForEach-Object {
[PSCustomObject]#{
'Folder' = $folder.FullName
'User' = $_.IdentityReference
# add extra info about access type for this user if you like
# 'AccessControlType' = $_.AccessControlType
# 'IsInherited' = $_.IsInherited
# 'InheritanceFlags' = $_.InheritanceFlags
# 'PropagationFlags' = $_.PropagationFlags
}
}
}

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
}