I have the following snippet of code from a script, used in order to get the NTFS permissions on file shares.
if ($ComputerName -eq '.'){
$Path = $Folder
}
else {
$Path = "\\$ComputerName\$Folder"
}ls
if ($OutputFile){
Get-Childitem $Path -Recurse:$Recurse | ForEach-Object {Get-Acl $_.FullName} | Select-Object #{Name="Path";Expression={$_.PSPath.Substring($_.PSPath.IndexOf(":")+2) }},#{Name="Type";Expression={$_.GetType()}},Owner -ExpandProperty Access | Export-CSV $OutputFile -NoTypeInformation
}
else{
Get-Childitem $Path -Recurse:$Recurse | ForEach-Object {Get-Acl $_.FullName} | Select-Object #{Name="Path";Expression={$_.PSPath.Substring($_.PSPath.IndexOf(":")+2) }},#{Name="Type";Expression={$_.GetType()}},Owner -ExpandProperty Access | Format-Table -AutoSize
}
At the moment when I run this I am able to generate a report on the NTFS permissions, however I would like to make the code recurse one extra folder deeper in a file share. My problem however is I only know of methods to completely recurse through all folders or get the current folders in a path.
For example assume I had a folder called 'test' and inside of test there were two other folders called 'temp1' and 'temp2', with there being one more folder inside of temp2 called 'extra.' I'd want it to get the NTFS permissions for 'test' and then go one level farther and report permissions for 'temp1' and 'temp2,' but I would not want it to get 'extra.'
EDIT:
if ($OutputFile){
gci c:\|%{if($_.PSIsContainer){GCI $_.FullName|get-acl};$_|get-acl}|Select-Object #{Name="Path";Expression={$_.PSPath.Substring($_.PSPath.IndexOf(":")+2) }},#{Name="Type";Expression={$_.GetType()}},Owner -ExpandProperty Access | sort PSParentPath|Export-CSV $OutputFile -NoType
}
You can manually recurse 1 level easily enough. Try this on for size:
if ($ComputerName -eq '.'){
$Path = $Folder
}
else {
$Path = "\\$ComputerName\$Folder"
}ls
if ($OutputFile){
gci c:\|%{if($_.PSIsContainer){GCI $_.FullName|get-acl};$_|get-acl}|sort PSParentPath|Export-CSV $OutputFile -NoType
}
else{
gci c:\|%{if($_.PSIsContainer){GCI $_.FullName|get-acl};$_|get-acl}|sort PSParentPath|FT -Auto
}
Something like this will go down to a depth of one folder
Get-Childitem $path | %{get-childitem -path $_.fullname}
Related
Hopefully this is a quick and easy process.
I need to build a tree (using powershell) of our network folders for auditing perposes.
I am wanting to start at the top level, root folder and encompass everything that falls under it. I know it will take a long time but that is okay with me.
I have full permissions on the root drive and inherency is turned on so there should be no folder permission errors.
I would like to export the tree to a .csv to look like this
Folder Name Folder Path
Folder1 \root\path\folder1
Folder2 \root\path\folder2
Here is what I have so far:
$path = "root\path\folder"
$reportPath = "C:\scripts
Get-ChildItem $Path -Recurse -Directory | Select-object psPath,psChildName | Export-CSV -path $reportPath
This gives me the results I am looking for but I get the dreaded "Microsoft.PowerShell.Core\FileSystem::" in the PSPath.
Does anyone know what I need to add in to hide that precursor to the pathway?
FullName is probably the property you're after. And if you want to have the CSV properties say "Folder Name" and "Folder Path" you can either use calculated properties with Select-Object or create your own object in a foreach-object loop.
Get-ChildItem $Path -Recurse -Directory |
Select-object #{n='Folder Name';e='Name'},#{n='Folder Path';e='FullName'} |
Export-Csv -path $reportPath -NoTypeInformation
or
Get-ChildItem $Path -Recurse -Directory | ForEach-Object {
[PSCustomObject]#{
'Folder Name' = $_.Name
'Folder Path' = $_.FullName
}
} | Export-Csv -path $reportPath -NoTypeInformation
Could you please help me with a directory operation?
I have an employee directory and in that directory, there are about 200+ employees subdirectories named by their employee code. And within each employee's subdirectory, there are about 20 subfolders referring to various documents. For example, subfolder named 'Educational Documents'. This 'Educational Documents' subfolder exists in each of these 200+ employee's folders.
I want to output a text or csv file listing all such 'Educational Documents' subfolders out of those 200+ employees which are empty or in other words where scanned PDF files have not been copied as yet. By doing so, I will be able to use that output file as a task list for myself to populate all those empty folders by putting scanned PDF documents for the missing employee data.
I have tried to use DOS commands with /S switch but that does not precisely cater to my needs and therefore I am looking at some Powershell script which could get this done.
My code so far:
$Search = gci -Filter "Educational Documents" -Recurse -Path "D:\Employees" -Directory
Foreach ($path in $Search.fullname)
{
Write-Output $path | Out-File d:\Filelist.txt -append
$file = gci -path $path | select name
$file.name | Out-File d:\filelist.txt -append
Write-Output "------- Next Folder --------------" | Out-File d:\Filelist.txt -append
}
If I understand correctly, you want a file listing of all empty folders called 'Educational Documents'.
To do that, you could make use of the GetFileSystemInfos() method of the DirectoryInfo objects returned by Get-ChildItem like this:
$Search = Get-ChildItem -Path "D:\Employees" -Filter "Educational Documents" -Recurse -Directory |
Where-Object { $_.GetFileSystemInfos().Count -eq 0 } | Select-Object -ExpandProperty FullName
# add '-PassThru' to also output this list on screen
$Search | Set-Content -Path 'D:\Empty_EducationalDocuments_Folders.txt'
Hope that helps
As per your comment, you would like to list both empty folders and folders that do not have a file with the word Graduation in their name, you can edit the above to become
$Search = Get-ChildItem -Path "D:\Employees" -Filter "Educational Documents" -Recurse -Directory |
Where-Object { $_.GetFileSystemInfos().Count -eq 0 -or
$_.GetFiles("*Graduation*", "TopDirectoryOnly").Count -eq 0 } |
Select-Object -ExpandProperty FullName
# add '-PassThru' to also output this list on screen
$Search | Set-Content -Path 'D:\EducationalDocuments_Folders_without_Graduation_File.txt'
You can try this code:
$Search = Get-ChildItem -Recurse -Path "D:\Employees" -Directory
foreach ($path in $Search.fullname)
{
$directoryInfo = Get-ChildItem -Path $path | Measure-Object
if($directoryInfo.count -eq 0)
{
$path | Out-File "D:\Filelist.txt" -append
Write-Output "------- Next Folder --------------" | Out-File "D:\Filelist.txt" -append
}
}
I used some code from this question: Test if folder is empty
I am trying to use powershell to produce a list of folder names and how many files are in each folder.
I have this script
$dir = "C:\Users\folder"
Get-ChildItem $dir -Recurse -Directory | ForEach-Object{
[pscustomobject]#{
Folder = $_.FullName
Count = #(Get-ChildItem -Path $_.Fullname -File).Count
}
} | Select-Object Folder,Count
Which lists the file count, but it puts the full path (i.e. C:\Users\name\Desktop\1\2\-movi...). Is there any way to just display the last folder ("movies") as well as save the result to a .txt file?
Thank you
Instead of $_.FullName, use $_.Name to only get the directory name.
Your Select-Object call is redundant - it is effectively a no-op.
While it's easy to send the results to a .txt file with >, for instance, it's better to use a more structured format for later programmatic processing.
In the simplest form, that means outputting to a CSV file via Export-Csv; generally, however, the most faithful way of serializing objects to a file is to use Export-CliXml.
Using Export-Csv for serialization:
$dir = 'C:\Users\folder'
Get-ChildItem -LiteralPath $dir -Recurse -Directory | ForEach-Object {
[pscustomobject] #{
Folder = $_.Name
Count = #(Get-ChildItem -LiteralPath $_.Fullname -File).Count
}
} | Export-Csv -NoTypeInformation results.csv
Note that you could streamline your command by replacing the ForEach-Object call with a Select-Object call that uses a calculated property:
$dir = 'C:\Users\folder'
Get-ChildItem -LiteralPath $dir -Recurse -Directory |
Select-Object Name,
#{ n='Count'; e={#(Get-ChildItem -LiteralPath $_.Fullname -File).Count} } |
Export-Csv -NoTypeInformation results.csv
You mean something like this...
Clear-Host
Get-ChildItem -Path 'd:\temp' -Recurse -Directory |
Select-Object Name,FullName,
#{Name='FileCount';Expression = {(Get-ChildItem -Path $_.FullName -File -Recurse| Measure-Object).Count}} `
| Format-Table -AutoSize
# Results
Name FullName FileCount
---- -------- ---------
abcpath0 D:\temp\abcpath0 5
abcpath1 D:\temp\abcpath1 5
abcpath2 D:\temp\abcpath2 5
Duplicates D:\temp\Duplicates 12677
EmptyFolder D:\temp\EmptyFolder 0
NewFiles D:\temp\NewFiles 4
PngFiles D:\temp\PngFiles 4
results D:\temp\results 905
...
I have this PowerShell code that compares 2 directories and removes files if the files no longer exist in the source directory.
For example say I have Folder 1 & Folder 2. I want to compare Folder 1 with Folder 2, If a file doesn't exist anymore in Folder 1 it will remove it from Folder 2.
this code works ok but I have a problem where it also picks up file differences on the date/time. I only want it to pick up a difference if the file doesn't exist anymore in Folder 1.
Compare-Object $source $destination -Property Name -PassThru | Where-Object {$_.SideIndicator -eq "=>"} | % {
if(-not $_.FullName.PSIsContainer) {
UPDATE-LOG "File: $($_.FullName) has been removed from source"
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue
}
}
Is there an extra Where-Object {$file1 <> $file2} or something like that.?
I am not sure how you are getting the information for $source and $destination I am assuming you are using Get-ChildItem
What i would do to eliminate the issue with date/time would be to not capture it in these variables. For Example:
$source = Get-ChildItem C:\temp\Folder1 -Recurse | select -ExpandProperty FullName
$destination = Get-ChildItem C:\temp\Folder2 -Recurse | select -ExpandProperty FullName
By doing this you only get the FullName Property for each object that is a child item not the date/time.
You would need to change some of the script after doing this for it to still work.
If I am not getting it wrong, the issue is your code is deleting the file with different time-stamp as compared to source:
Did you try -ExcludeProperty?
$source = Get-ChildItem "E:\New folder" -Recurse | select -ExcludeProperty Date
The following script can serve your purpose
$Item1=Get-ChildItem 'SourcePath'
$Item2=Get-ChildItem 'DestinationPath'
$DifferenceItem=Compare-Object $Item1 $Item2
$ItemToBeDeleted=$DifferenceItem | where {$_.SideIndicator -eq "=>" }
foreach ($item in $ItemToBeDeleted)
{
$FullPath=$item.InputObject.FullName
Remove-Item $FullPath -Force
}
Try something like this
In PowerShell V5:
$yourdir1="c:\temp"
$yourdir2="c:\temp2"
$filesnamedir1=(gci $yourdir1 -file).Name
gci $yourdir2 -file | where Name -notin $filesnamedir1| remove-item
In old PowerShell:
$yourdir1="c:\temp"
$yourdir2="c:\temp2"
$filesnamedir1=(gci $yourdir1 | where {$_.psiscontainer -eq $false}).Name
gci $yourdir2 | where {$_.psiscontainer -eq $false -and $_.Name -notin $filesnamedir1} | remove-item
If you want to compare files in multiple dir, use the -recurse option for every gci command.
I'm looking for a way to list all access rights from a folder recursively.
Right now I have this Code:
$logfile = "C:\temp\test.txt"
$testpath = "H:\"
dir $testpath -Recurse | Get-Acl | Out-File $logfile
But this doesn't list all access rights.
Does anyone have a idea what wrong is?
EDIT:
At the moment it looks like this:
Boardmaker
HEALTH\infsst_sys
VORDEFINIERT\Administratoren Allow FullControl...
Get-Acl produces a complex data structure with owner and access information about an object. You need to expand the Access property of that object to get the information you want:
Get-ChildItem $testpath -Recurse | ForEach-Object {
$file = $_.FullName
Get-Acl -Path $file | Select-Object -Expand Access |
Select-Object #{n='File';e={$file}}, IdentityReference, FileSystemRights,
AccessControlType
} | Export-Csv $logfile -NoType