We are running the script mentioned below to change a heap of ACL permissions which needs to be down to the file level as we are migrating from one environment to another.
The script below is working for folders/subfolders but appears to fail when it comes to the actual files themselves.
$items = get-childitem \\file.location.com.au\project\people\user1 -recurse | select-object -property fullname
Foreach ($item in $items) {
# Get the ACL for an existing folder
$existingAcl = Get-Acl -Path '$item'
# Set the permissions that you want to apply to the folder
$permissions = 'SERVER\USER1', 'Read,Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow'
# Create a new FileSystemAccessRule object
$rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permissions
# Modify the existing ACL to include the new rule
$existingAcl.SetAccessRule($rule)
# Apply the modified access rule to the folder
$existingAcl | Set-Acl -Path '$ITEM'
}
As you can see we are getting the below error and im unsure why. Is someone able to see what im missing?
I have spent a lot of time with no progress on rectifying this issue.
At line:14 char:1
+ $existingAcl.SetAccessRule($rule)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Get-Acl : Cannot find path '$item' because it does not exist.
At line:5 char:16
+ $existingAcl = Get-Acl -Path '$item'
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-Acl], ItemNotFoundException
+ FullyQualifiedErrorId : GetAcl_PathNotFound_Exception,Microsoft.PowerShell.Commands.GetAcl
Command
You cannot call a method on a null-valued expression.
This should put you on the right track:
$items = get-childitem \\file.location.com.au\project\people\user1 -recurse | select-object -property fullname
# Set the permissions that you want to apply to the folder
$permissions = 'SERVER\User1', 'Read,Modify', 'Allow'
# Create a new FileSystemAccessRule object
$newaccessrule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permissions
Foreach ($item in $items) {
# Get the ACL for an existing folder
$existingAcl = Get-Acl -Path $item.FullName
# Modify the existing ACL to include the new rule
$existingAcl.SetAccessRule($newaccessrule)
$existingAcl.SetAccessRuleProtection($false,$true)
# Apply the modified access rule to the folder
Set-Acl -Path $item.FullName -AclObject $existingAcl
}
Related
I am trying to get a script working to audit folder permissions on a Windows server, among other data, and export this data to a CSV file for analysis after a ransomware attack.
I ripped the script from a forum, but it did not run correctly as is. Below is a slightly modified version during my troubleshooting.
I am well versed in batch scripting, and have a decent understanding of loops and pipelining, but this Powershell script has me scratching my head.
It seems like the array is not making it to the nested loop.
I am testing in Windows 10 Pro 21H1, using Powershell version 5.1.19041.1320, build 10.0.19041.1320
##The script:
$ErrorActionPreference = "Continue"
$strComputer = $env:ComputerName
$colDrives = Get-PSDrive -PSProvider Filesystem
ForEach ($DriveLetter in $colDrives) {
$StartPath = "$DriveLetter`:\"
Get-ChildItem -LiteralPath $StartPath -Recurse | ?{ $_.PSIsContainer } |
ForEach ($FullPath = Get-Item -LiteralPath{Get-Item -LiteralPath $_.PSPath}{Get-Item -
LiteralPath $FullPath}.Directoryinfo.GetAccessControl())}
Select #{N='Server Name';E={$strComputer}}
#{N='Full Path';E={$FullPath}}
#{N='Type';E={If($FullPath.PSIsContainer -eq $True) {'D'} Else {'F'}}}
#{N='Owner';E={$_.Owner}}
#{N='Trustee';E={$_.IdentityReference}}
#{N='Inherited';E={$_.IsInherited}}
#{N='Inheritance Flags';E={$_.InheritanceFlags}}
#{N='Ace Flags';E={$_.PropagationFlags}}
#{N='Ace Type';E={$_.AccessControlType}}
#{N='Access Masks';E={$_.FileSystemRights}}
Export-CSV -NoTypeInformation -Delimiter "|" -Path "$strComputer`_$DriveLetter.csv"
##The error I am getting:
You cannot call a method on a null-valued expression.
At C:\Users\user\Documents\fileaudit2.ps1:8 char:13
ForEach ($FullPath = Get-Item -LiteralPath{Get-Item -LiteralPath $ ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (:) [], RuntimeException
FullyQualifiedErrorId : InvokeMethodOnNull
##when I modify the nested loop as follows:
ForEach ($FullPath = Get-Item -LiteralPath{Get-Item -LiteralPath $_.PSPath}{Get-Item -LiteralPath $FullPath}).Directoryinfo.GetAccessControl()}
##I get the error:
Get-Item : Cannot evaluate parameter 'LiteralPath' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without
input.
At C:\Users\user\Documents\fileaudit2.ps1:8 char:46
... Path = Get-Item -LiteralPath{Get-Item -LiteralPath $_.PSPath}{Get-Ite ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : MetadataError: (:) [Get-Item], ParameterBindingException
FullyQualifiedErrorId : ScriptBlockArgumentNoInput,Microsoft.PowerShell.Commands.GetItemCommand
##I'm just wholly struggling to understand what is not working in this loop.
You are mixing a lot of unneeded Get-Item calls in there.
I also would not use Get-PSDrive for this because I assume you don't want to get results for CD drives, USB devices etc in the report.
Try:
# this returns drives WITH a trailing backslash like C:\
$colDrives = ([System.IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' }).Name
# or use:
# this returns drives WITHOUT trailing backslash like C:
# $colDrives = (Get-CimInstance -ClassName win32_logicaldisk | Where-Object { $_.DriveType -eq 3 }).DeviceID
$result = foreach ($drive in $colDrives) {
Get-ChildItem -LiteralPath $drive -Directory -Recurse -ErrorAction SilentlyContinue |
ForEach-Object {
$path = $_.FullName
$acl = Get-Acl -Path $path
foreach ($access in $acl.Access) {
[PsCustomObject]#{
Server = $env:COMPUTERNAME
Drive = $drive[0] # just the first character of the drive
Directory = $path
Owner = $acl.Owner
Trustee = $access.IdentityReference
Inherited = $access.IsInherited
InheritanceFlags = $access.InheritanceFlags -join ', '
'Ace Flags' = $access.PropagationFlags -join ', '
'Ace Type' = $access.AccessControlType
'Access Masks' = $access.FileSystemRights -join ', '
}
}
}
}
# now you can save your result as CSV file for instance you can double-click to open in Excel:
$result | Export-Csv -Path 'X:\WhereEver\audit.csv' -NoTypeInformation -UseCulture
To do this on several remote machines, wrap it inside Invoke-Command
# set the credentials for admin access on the servers
$cred = Get-Credential 'Please enter your admin credentials'
# create an array of the servers you need to probe
$servers = 'Server01', 'Server02'
$result = Invoke-Command -ComputerName $servers -Credential $cred -ScriptBlock {
$colDrives = ([System.IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' }).Name
foreach ($drive in $colDrives) {
# code inside this loop unchanged as above
}
}
# remove the extra properties PowerShell added
$result = $result | Select-Object * -ExcludeProperty PS*, RunspaceId
# output to csv file
$result | Export-Csv -Path 'X:\WhereEver\audit.csv' -NoTypeInformation -UseCulture
So I'm running a script that creates folders from a list of usernames in a CSV and in those folders it creates a folder called "Documents" and I'm then trying to give "modify" access rights to the "Documents" folder for the user concerned - eg a folder is created for john.smith, inside that folder is a "Documents" folder, and the user john.smith gets modify access rights to that "Documents" folder.
Creating the folders works without a hitch, it's the access rights part that is giving me a headache - it returns an Invalid Argument error for the last line of the code below and I can't figure out why - any help would be appreciated.
$Location = "C:\Scripts"
Set-Location $Location
$Folders = Import-Csv "C:\Scripts\UserFolderList.csv"
ForEach ($Folder in $Folders)
{
#Create A Folder From The "Name" Column In The CSV Then Create A Subfolder Called Documents
New-Item $Folder.Name -ItemType Directory
$Docs = "Documents"
$DocsPath = Join-Path $Folder.Name $Docs
New-Item -Path $DocsPath -ItemType Directory
#Assign The Modify Permission For The Username To The Documents Folder
$Domain = "tly"
$DomainUser = $Domain + $Folder.Name
$FullDocsPath = "$Location" + $Folder.Name + "$Docs"
$Acl = Get-Acl $FullDocsPath
$ArgumentList="$DomainUser","Modify","ContainerInherit,ObjectInherit","None","Allow"
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule ($ArgumentList)
$Acl.SetAccessRule($AccessRule)
Set-Acl -path $FullDocsPath -aclObject $AccessRule
}
The resulting error is:
Set-Acl : AclObject
At line:22 char:1
Set-Acl -path $FullDocsPath -aclObject $AccessRule
CategoryInfo : InvalidArgument: (System.Security...ystemAccessRule:FileSystemAccessRule) [Set-Acl], ArgumentException
FullyQualifiedErrorId : SetAcl_AclObject,Microsoft.PowerShell.Commands.SetAclCommand
Im trying to write a script where a part of it take ACL from file and adding specific user ntfs permission to modify:
$identity = "$domain\$adname" #In this example $domain='muzi.local $adname='puzi'
$rights = 'Modify'
$inheritance = 'ContainerInherit, ObjectInherit'
$propagation = 'None'
$type = 'Allow'
$Acl = Get-Acl -Path "$bucketdir\$_" #for this example c:\bla.txt
$Acl.AddAccessRule($ACE) #this is where the error output.
Set-Acl -Path "$bucketdir\$_" -AclObject $Acl #code would not get here
Error output:
Exception calling "AddAccessRule" with "1" argument(s): "No flags can be set.
Parameter name: inheritanceFlags"
At C:\Step2.ps1:26 char:3
$Acl.AddAccessRule($ACE)
~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : ArgumentException
Looks like the arguments aren't passing to the function, but if I output them one by one it looks fine
I think you simply forgot to create the new access rule, but also, since you're changing the ACL of a File, not a Directory, you should use the constructor for the new rule which has only 3 parameters, since a file does not have child objects to propagate or inherit access rights:
$identity = "$domain\$adname" #In this example $domain='muzi.local $adname='puzi'
$rights = 'Modify'
$type = 'Allow'
# these do not apply for a File (it has no child objects)
# $inheritance = 'ContainerInherit, ObjectInherit'
# $propagation = 'None'
$file = "$bucketdir\$_" #for this example c:\bla.txt
# create the new AccessRule
$rule = [System.Security.AccessControl.FileSystemAccessRule]::new($identity, $rights, $type)
$Acl = Get-Acl -Path $file
$Acl.AddAccessRule($rule)
Set-Acl -Path $file -ACLObject $Acl
Since you can only view the C:\$RECYCLE.BIN Folder when you uncheck (Hide protected Operating System Files) you can't change the date modified through the usual way with PowerShell:
$file = Get-Item C:\Path\TO\File.txt
$file.LastWriteTime = (Get-Date)
or
$folder = Get-Item C:\folder1
$folder.LastWriteTime = (Get-Date)
When calling Get-Item C:\$RECYCLE.BIN, I get the following error:
Get-Item : Cannot find path 'C:\.bin' because it does not exist.
At line:1 char:9
+ $file = Get-Item C:\$Recycle.bin
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\.bin:String) [Get-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
How would I go about changing the date modified of it?
As C:\$RECYCLE.BIN contains $, PowerShell tries to evaluate the variable $RECYCLE, which is empty. Thus, the resulting path C:\.bin cannot be found. Quote your path with single quotes (') to prevent PowerShell from evaluating your string and also add the -Force parameter as it is a system directory:
Get-Item -Path 'C:\$RECYCLE.BIN' -Force
You can then access your files and change the LastWriteTime as you already tried in your question:
$fileObject = Get-Item -Path 'C:\$RECYCLE.BIN\S-1-5-21-3323847664-626704455-790384891-1001\$RT8USDF.txt' -Force
$fileObject.LastWriteTime = Get-Date
I have Windows Server 2016 Datacenter (64 bit) as a File Server (contains several Shared folder & subfolders).
I want to make a list OR export user Folder Structure along with permissions ( Read, Modify, Full .. etc..)
I tried with below PS script but I am getting an error message with I have mentioned after the script.
Powershell
$FolderPath = dir -Directory -Path "E:\Project Folders\#Folder_Name" -Recurse -Force
$Report = #()
Foreach ($Folder in $FolderPath) {
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access)
{
$Properties = [ordered]#{'FolderName'=$Folder.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:\Folder Permissions\Folder Name.csv"
Error:
dir : Access to the path 'E:\Project Folders**Folder Path**\New folder' is denied. At C:\Users\Administrator\Documents\PS Script**File Name**.ps1:1 char:15 + ... olderPath = dir -Directory -Path "E:\Project Folders**Folder Name**" -Re ...+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (E:\Project Fold...ngar\New folder:String) [Get-Child Item], UnauthorizedAccessException + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
Please help me out!
Thanks in Advance
As noted by the other comments.
This is not a PowerShell error/issue, it is a permissions one. The same thing can/will happen if you say you did this use case on the Windows folder tree.
Since you know this will happen, either fix the permissions on the tree you are working on or do this.
Get-ChildItem -Directory -Path 'C:\Windows\System32' -Recurse -ErrorAction SilentlyContinue
or if you want to just stop when a path fails.
# Treat non-terminating erros as terminating
$RootFolderUnc = 'C:\Windows\System32'
Try {Get-ChildItem -Directory -Path $RootFolderUnc -Recurse -ErrorAction Stop}
Catch [System.UnauthorizedAccessException]
{
Write-Warning -Message "$env:USERNAME. You do not have permissions to view this path."
$_.Exception.Message
}