I am trying to check ACLs on UNC paths via the Get-Acl cmdlet.
The below works fine when browsing the local filesystem or on a UNC path without spaces.
$ou = 'OU=Security Groups,DC=mydomain,DC=local'
$basepath = '\\mydomain\dfsroot'
$filter = '*501*'
Get-ADGroup -SearchBase $ou -Filter { Name -like $filter } | % {
$principle = $_.samAccountName
Get-ChildItem -LiteralPath $basepath -Recurse | % {
$path = $_.FullName
($path | Get-Acl).Access.IdentityReference | % { if ( $_.Value -match $principle ) { Write-Host "$principle has rights to $path" }}
}
}
On UNC paths with spaces I get a "FileNotFoundException":
Get-Acl : \local501\dfsroot\docs\Accounting\Bankruptcy Files\NOTICE TO MEMBERSHIP RE-CHAPTER 11.pdf
At C:\Users\administrator.LOCAL501\Documents\IT Support Guys - (855) 4 IT GUYS\Files\find_paths_by_principle.ps1:11 char:18
+ ($path | Get-Acl).Access.IdentityReference | % { if ( $_.Valu ...
+ ~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Acl],FileNotFoundException
+ FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.GetAclCommand
Can somebody help me understand what's going on here?
Thanks!
Ignore this!
My DFS share is full of corruption!
Filenames just happened to be ones with spaces.
Good news!
So your code is a little needlessly complicated. Here's a script that's easier to understand the flow and shouldn't error out on spaces:
If (-not (Test-Path -Path DFS:\))
{ New-PSDrive -Name DFS -PSProvider FileSystem -Root \\mydomain\dfsroot }
$OU = 'OU=Security Groups,DC=mydomain,DC=local'
$Filter = '*501*'
$Principles = (Get-ADGroup -SearchBase $OU -Filter {Name -like $Filter}).samAccountName
$Collection = #()
ForEach ($Path in (Get-ChildItem -Path DFS:\ -Recurse -ErrorVariable +CustomERR))
{
## Using an array literal so items don't end up appended to one giant hashtable
$Collection += #(
#{ Path = $Path.FullName
Acl = (Get-Acl -Path $Path.FullName).Access.IdentityReference.Value
}
)
}
ForEach ($Principle in $Principles)
{
ForEach ($Item in $Collection)
{
If ($Item.Acl -contains $Principle)
{
Write-Host "'$Principle' has rights to '$($Item.Path)'"
}
}
}
Edit: made some optimizations
Related
I am trying to check for presence of a particular folder "appdata\Local\Packages\ActiveSync" in each of the profile folders that are returned for each of the computer by the below script.Searching through various forums I got the script below and need further assistance to eventually output it to a file with results of Test-Path against each computer name and corresponding profile path.
e.g. \\Computer1\C:\users\John\appdata\Local\packages\ActiveSync False
Invoke-Command -Computer (get-content c:\temp\servers.txt) -ScriptBlock {
Get-childItem 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' |
% {Get-ItemProperty $_.pspath }} | Select pscomputername,profileimagepath |
Where-Object { $_.ProfileImagePath -like "C:\users*" } | Out-File c:\temp\profiles.csv
For this, I think I would use a loop to go through all user path strings like below:
Invoke-Command -ComputerName (Get-Content -Path 'c:\temp\servers.txt') -ScriptBlock {
$regPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*'
Get-ItemPropertyValue -Path $regPath -Name 'ProfileImagePath' -ErrorAction SilentlyContinue |
Where-Object { $_ -like 'C:\Users*' } | ForEach-Object {
# combine the value with the rest of the path to form a LOCAL path
$path = Join-Path -Path $_ -ChildPath 'AppData\Local\Packages\ActiveSync'
[PsCustomObject]#{
ComputerName = $env:COMPUTERNAME
Path = '\\{0}\{1}' -f $env:COMPUTERNAME, ($path.Replace(":", "$")) # UNC format
Exists = Test-Path -Path $path -PathType Container
}
}
} | Export-Csv -Path 'c:\temp\profiles.csv' -NoTypeInformation
Please note that if the output should be a structured CSV file, you need to use Export-Csv on the resulting objects instead of Out-File.
Also you may need to append parameter -Credential to the Invoke-Command call where you can give it administrative credentials.
I am trying to match the samaccountname to the current folder patch, and it would worked fine if the folderpatch was "d:\profile\username" but instead of username its states username_S-1-5-21*....
I use the below code, but is it possible to filter everything behind the _S-1.... so it can match the username to the samaccountname ?
I use the below code, any help would be appreciated
[EDIT: added complete script]
Below is the complete script, so the issue is that i have several user folder with _S-1-5-21* behind the username in the folder of our FXLogic profile folder and need to match the samaccountname with the folder ( username - _S-1-5-21* )
I hope this explanation is more clear, and yes its a SID not a GUID always get them mixed up.
param(
[Parameter(Mandatory=$true)]
$FXLogicFolderPath,
$MoveFolderPath,
$SearchBase,
[string[]]$ExcludePath,
[switch]$FolderSize,
[switch]$MoveDisabled,
[switch]$DisplayAll,
[switch]$UseRobocopy,
[switch]$RegExExclude,
[switch]$CheckFXLogicDirectory)
Check if FXLogicFolderPath is found, exit with warning message if path is incorrect
if (!(Test-Path -LiteralPath $FXLogicFolderPath)){
Write-Warning "FXLogicFolderPath not found: $FXLogicFolderPath"
Check if MoveFolderPath is found, exit with warning message if path is incorrect
if ($MoveFolderPath) {
if (!(Test-Path -LiteralPath $MoveFolderPath)){
Write-Warning "MoveFolderPath not found: $MoveFolderPath"
exit
}}
exit
Main loop, for each folder found under FXLogic folder path AD is queried to find a matching samaccountname
$ListOfFolders = Get-ChildItem -LiteralPath "$FXLogicFolderPath" -Force | Where-Object {$_.PSIsContainer}
Exclude folders if the ExcludePath parameter is given
if ($ExcludePath) {
$ExcludePath | ForEach-Object {
$CurrentExcludePath = $_
if ($RegExExclude) {
$ListOfFolders = $ListOfFolders | Where-Object {$_.FullName -notmatch $CurrentExcludePath}
} else {
$ListOfFolders = $ListOfFolders | Where-Object {$_.FullName -ne $CurrentExcludePath}
}
}}
$ListOfFolders | ForEach-Object {
$CurrentPath = Split-Path -Path $_ -Leaf
Construct AD Searcher, add SearchRoot attribute if SearchBase parameter is specified
$ADSearcher = New-Object DirectoryServices.DirectorySearcher -Property #{
Filter = "(samaccountname=$CurrentPath)"
}
if ($SearchBase) {
$ADSearcher.SearchRoot = [adsi]$SearchBase
}
Use the FullName path to look for a FXLogicdirectory attribute and replace the backslash by the \5C LDAP escape character
if ($CheckFXLogicDirectory) {
$ADSearcher.Filter = "(FXLogicdirectory=$($_.FullName -replace '\\','\5C')*)"
}
Execute AD Query and store in $ADResult
$ADResult = $ADSearcher.Findone()
If no matching samaccountname is found this code is executed and displayed
if (!($ADResult)) {
$HashProps = #{
'Error' = 'Account does not exist and has a FXLogic folder'
'FullPath' = $_.FullName
}
if ($FolderSize) {
$HashProps.SizeinBytes = [long](Get-ChildItem -LiteralPath $_.Fullname -Recurse -Force -ErrorAction SilentlyContinue |
Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue | Select-Object -Exp Sum)
$HashProps.SizeinMegaBytes = "{0:n2}" -f ($HashProps.SizeinBytes/1MB)
}
if ($MoveFolderPath) {
$HashProps.DestinationFullPath = Join-Path -Path $MoveFolderPath -ChildPath (Split-Path -Path $_.FullName -Leaf)
if ($UseRobocopy) {
robocopy $($HashProps.FullPath) $($HashProps.DestinationFullPath) /E /MOVE /R:2 /W:1 /XJD /XJF | Out-Null
} else {
Move-Item -LiteralPath $HashProps.FullPath -Destination $HashProps.DestinationFullPath -Force
}
}
Output the object
New-Object -TypeName PSCustomObject -Property $HashProps
If samaccountname is found but the account is disabled this information is displayed
} elseif (([boolean]((-join $ADResult.Properties.useraccountcontrol) -band 2))) {
$HashProps = #{
'Error' = 'Account is disabled and has a FXLogic folder'
'FullPath' = $_.FullName
}
if ($FolderSize) {
$HashProps.SizeinBytes = [long](Get-ChildItem -LiteralPath $_.Fullname -Recurse -Force -ErrorAction SilentlyContinue |
Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue | Select-Object -Exp Sum)
$HashProps.SizeinMegaBytes = "{0:n2}" -f ($HashProps.SizeinBytes/1MB)
}
if ($MoveFolderPath -and $MoveDisabled) {
$HashProps.DestinationFullPath = Join-Path -Path $MoveFolderPath -ChildPath (Split-Path -Path $_.FullName -Leaf)
Move-Item -LiteralPath $HashProps.FullPath -Destination $HashProps.DestinationFullPath -Force
}
Output the object
New-Object -TypeName PSCustomObject -Property $HashProps
Folders that do have active user accounts are displayed if -DisplayAll switch is set
} elseif ($ADResult -and $DisplayAll) {
$HashProps = #{
'Error' = $null
'FullPath' = $_.FullName
}
if ($FolderSize) {
$HashProps.SizeinBytes = [long](Get-ChildItem -LiteralPath $_.Fullname -Recurse -Force -ErrorAction SilentlyContinue |
Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue | Select-Object -Exp Sum)
$HashProps.SizeinMegaBytes = "{0:n2}" -f ($HashProps.SizeinBytes/1MB)
}
Output the object
New-Object -TypeName PSCustomObject -Property $HashProps
}}
# Construct AD Searcher, add SearchRoot attribute if SearchBase parameter is specified
$ADSearcher = New-Object DirectoryServices.DirectorySearcher -Property #{
Filter = "(samaccountname=$CurrentPath)"
}
if ($SearchBase) {
$ADSearcher.SearchRoot = [adsi]$SearchBase
The S-1-5-21... part is not a GUID, it's a SID (the principal's Security Identifier).
You can use the -replace operator to remove that part of the folder name:
$folderName = 'username_S-1-5-21-2855571654-3033049851-1520320983-9328'
$userName = $folderName -replace '_S-1-5.*$'
After which you can construct the desired LDAP query filter:
$ADSearcher = New-Object DirectoryServices.DirectorySearcher -Property #{
Filter = "(samaccountname=$userName)"
}
Not sure where your username is being derived from but you could do something simple with a regex replace on the $CurrentPath
$currentPath = 'username_S-1-5-21-2855571654-3033049851-1520320983-9328'
$currentPath = $currentPath -replace '_.+'
# AD Searcher here
This will replace everything after the underscore but all usernames will have to be in a consistent format or you'll have to take into account all possible formats that could be encountered.
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
}
I am recursively getting a list of folders with their respective permissions in a powershell script, however when the recursive part happens my output string keeps printing the folder structure each time an example of this is:
I have a folder called C:\temp, within that folder are 2 empty folders C:\temp\folder1 and C:\temp\folder2. With my script the output would be:
I have left out the permissions for readability
C:\temp
C:\temp\folder1
C:\temp
C:\temp\folder2
I don't want this to happen I want a list of folders with their permissions and then if the permissions on a child folder are different then look at the get the child folders of that folder. This works apart from the string building which I think I need a fresh pair of eyes to look at it because I'm getting nowhere.
Appreciate the help in advance,
Sam
CODE:
Add-Type -AssemblyName System.Windows.Forms
Import-Module ActiveDirectory
$info = ""
$OutputString
$step = 0
function DisplayForm{
#Some GUI code
#$textBox takes in the base folder from the user
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$baseFolder = $textBox.Text
$ParentProperties = (Get-Acl $baseFolder).Access| Select-Object -ExpandProperty IdentityReference
$OutputString = $OutputString + $baseFolder + "`r`n" + $ParentProperties + "`r`n`r`n"
$ChildFolders = Get-ChildItem $baseFolder | where {$_.Attributes -eq 'Directory'}
FindPriorities($baseFolder)
$info = "SAVED TO FOLDER"
outputList
}
}
function FindPriorities{
param($fileName)
$ChildFolders = Get-ChildItem $fileName | where {$_.Attributes -eq 'Directory'}
$step = $step + 1
$TempString = ""
foreach ($folder in $ChildFolders){
$child = $fileName + "\\" + $folder.name
$ParentProperties = (Get-Acl $fileName).Access| Select-Object -ExpandProperty IdentityReference
$ChildProperties = (Get-Acl $child).Access| Select-Object -ExpandProperty IdentityReference
$parentString=""
foreach ($p in $ParentProperties){
$parentString= $parentString + $p
}
$childString=""
foreach ($c in $childProperties){
$childString = $childString + $c
}
if($childString -ne $parentString){
$OutputString = $OutputString + $child + "`r`n" + $ChildProperties + "`r`n`r`n"
FindPriorities ($child)
}else{
$OutputString = $OutputString + $child + "`r`n" + $ChildProperties + "`r`n`r`n"
}
}
}
function outputList{
$OutputString
}
DisplayForm
I think I understood what you want to do.
Please give this snippet a try:
function Get-IdentityReference($path) {
Get-Acl $path |
Select-Object -ExpandProperty Access |
Select-Object -ExpandProperty IdentityReference
}
function Extract-Permissions($baseFolder) {
$folders = Get-ChildItem $baseFolder | Where-Object { $_.PSisContainer }
$baseACL = Get-IdentityReference $baseFolder
"$baseFolder : $baseACL"
foreach($folder in $folders) {
$folderACL = Get-IdentityReference $folder.FullName
$childFolders = Get-ChildItem $folder.FullName | Where-Object { $_.PSisContainer }
"$($folder.FullName) : $folderACL"
foreach($childFolder in $childFolders) {
$childACL = Get-IdentityReference $childFolder.FullName
if(Compare-Object $childACL $folderACL) {
Extract-Permissions $childFolder.FullName
} else {
"$($childFolder.FullName) : $childACL"
}
}
}
}
$baseFolder = "$env:USERPROFILE\Desktop"
Extract-Permissions $baseFolder
I need to get a list of all the folders owners on a shared network drive. However, I want to limit the recursion to just 3 folders deep (some of our users will create folders several levels deep, despite us telling them not to). I've found the below script, and slightly modified it to just give folder owner (it originally returned a lot more information for ACLs), but it still goes down through every folder level. How can I modify this to only return 3 folder levels?
$OutFile = "C:\temp\FolderOwner.csv" # indicates where to input your logfile#
$Header = "Folder Path;Owner"
Add-Content -Value $Header -Path $OutFile
$RootPath = "G:\" # which directory/folder you would like to extract the acl permissions#
$Folders = dir $RootPath -recurse | where {$_.psiscontainer -eq $true}
foreach ($Folder in $Folders){
$Owner = (get-acl $Folder.fullname).owner
Foreach ($ACL in $Owner){
$OutInfo = $Folder.Fullname + ";" + $owner
Add-Content -Value $OutInfo -Path $OutFile
}
}
You should be able to add a '*' to your path for each level. For example, this should return items three levels deep under C:\Temp:
dir c:\temp\*\*\*
Here's a sample function you can use (it's written for PowerShell v3 or higher, but it can be modified to work for version 2):
function Get-FolderOwner {
param(
[string] $Path = "."
)
Get-ChildItem $Path -Directory | ForEach-Object {
# Get-Acl throws terminating errors, so we need to wrap it in
# a ForEach-Object block; included -ErrorAction Stop out of habit
try {
$Owner = $_ | Get-Acl -ErrorAction Stop | select -exp Owner
}
catch {
$Owner = "Error: {0}" -f $_.Exception.Message
}
[PSCustomObject] #{
Path = $_.FullName
Owner = $Owner
}
}
}
Then you could use it like this:
Get-FolderOwner c:\temp\*\*\* | Export-Csv C:\temp\FolderOwner.csv
If you're after all items up to and including 3 levels deep, you can modify the function like this:
function Get-FolderOwner {
param(
[string] $Path = ".",
[int] $RecurseDepth = 1
)
$RecurseDepth--
Get-ChildItem $Path -Directory | ForEach-Object {
# Get-Acl throws terminating errors, so we need to wrap it in
# a ForEach-Object block; included -ErrorAction Stop out of habit
try {
$Owner = $_ | Get-Acl -ErrorAction Stop | select -exp Owner
}
catch {
$Owner = "Error: {0}" -f $_.Exception.Message
}
[PSCustomObject] #{
Path = $_.FullName
Owner = $Owner
}
if ($RecurseDepth -gt 0) {
Get-FolderOwner -Path $_.FullName -RecurseDepth $RecurseDepth
}
}
}
And use it like this:
Get-FolderOwner c:\temp -RecurseDepth 3 | Export-Csv C:\temp\FolderOwner.csv
Any help?
resolve-path $RootPath\*\* |
where { (Get-Item $_).PSIsContainer } -PipelineVariable Path |
Get-Acl |
Select #{l='Folder';e={$Path}},Owner