I am working on a Windows Server File Security project, and need the explicit ACL permissions for our " O:" and all of the subfolders. I am wanting to export it to an CSV for easy formatting. I am looking for a Powershell script that can list the folder name and the Security Group or User that has access to that folder.
$rootpath = "O:\ADSMO"
$outfile = "ExplicitACLs.txt"
New-Variable acl
$Report = #"
Explicit permissions on folders under parent $rootpath.
"#
$Report | out-file -Encoding ASCII -FilePath $outfile
Get-ChildItem -Recurse $rootpath -Exclude "*.*" | Where-Object {$_.PSisContainer } | ForEach-Object {
$acl = Get-Acl -Path $_.FullName
$access = $acl.access
if ( $access | Where-Object { $_.IsInherited -eq $False }) {
Add-Content -Path $outfile $_
$access | Where-Object { $_.IsInherited -eq $False } | ForEach-Object {
$i = $_.IdentityReference
$t = "`t"
$r = $_.FileSystemRights
$c = "$i"+"$t"+"$t"+"$t"+"$r"
Add-Content -Path $outfile $c
}
Add-Content -Path $outfile ""
}
Clear-Variable acl
Clear-Variable access
}
Add-Content -Path $outfile ""
Seems like you're trying to build a CSV manually, which is definitely not recommended. You can use Export-Csv to export your report to CSV. From what I'm seeing, your code could be simplified to this:
Get-ChildItem O:\ADSMO -Directory -Recurse | ForEach-Object {
foreach($access in (Get-Acl $_.FullName).Access) {
# if `IsInherited = $true` go to next iteration
if($access.IsInherited) { continue }
[pscustomobject]#{
FolderName = $_.Name
FolderPath = $_.FullName
IdentityReference = $access.IdentityReference
FileSystemRights = $access.FileSystemRights
}
}
} | Export-Csv 'C:\path\to\acls.csv' -NoTypeInformation
Related
I am trying to create a PowerShell script to fetch the root folder's name where in their subdirectories files with error names are present with today's date. Below is the sample code I have tried so far to pick the folder names.
Root Log folder - C:\Errorlogs, contains many other application log level folders.
$targetDir="C:\Errorlogs"
Get-ChildItem $targetDir -Recurse -ErrorAction SilentlyContinue -Force -Filter "*Error*"|
where {([datetime]::now.Date -eq $_.lastwritetime.Date)} |
select FullName
I have tried the above code; however, it's giving me the whole path as result, whereas I only need the folder name.
Result - C:\Errorlogs\AsyncCreateUsersAPIProcessor\202302\04\Error.txt
Required - AsyncCreateUsersAPIProcessor
Use string LastIndexOf and SubString
$rootPath = "C:\Temp\Errorlogs"
$date = [DateTime]::Now.ToString("yyyyMM\\\\dd")
$pattern = '\\(?<folder>\w+)\\' + $date + '\\Error.*$'
$files = Get-ChildItem -Path $rootPath -Recurse | Select-Object -Property Fullname | Where-Object {$_.Fullname -Match $pattern}
foreach($file in $files)
{
$file.Fullname -match $pattern
Write-Host "folder = " $Matches.folder
}
Looks like you can do it just with splitting the path using \ as delimiter then picking the 3rd token (2nd index of an array):
$targetDir = "C:\Errorlogs"
Get-ChildItem $targetDir -Recurse -ErrorAction SilentlyContinue -Force -Filter "*Error*" |
Where-Object { [datetime]::Now.Date -eq $_.LastWriteTime.Date } |
Select-Object #{ N='Name'; E={ $_.FullName.Split('\')[2] }}
Another option if you want 2 levels up in the folder hierarchy is to query the .Directory property of the file then the .Parent property of the parent folder (2 times or as many times as needed):
$targetDir = "C:\Errorlogs"
Get-ChildItem $targetDir -Recurse -ErrorAction SilentlyContinue -Force -Filter "*Error*" |
Where-Object { [datetime]::Now.Date -eq $_.LastWriteTime.Date } |
Select-Object #{ N='Name'; E={ $_.Directory.Parent.Parent.Name }}
As long as the subfolders inside the folder you are after all have numeric-only names, you can loop backwards to get at the first non-numeric foldername and output that.
$targetDir = "C:\Errorlogs"
Get-ChildItem -Path $targetDir -File -Filter "*Error*" -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { [datetime]::Now.Date -eq $_.LastWriteTime.Date } | ForEach-Object {
$parentDir = $_.Directory
while ($parentDir.Name -match '^\d+$') { $parentDir = $parentDir.Parent }
$parentDir.Name
}
That way, even a path C:\Errorlogs\AsyncCreateUsersAPIProcessor\202302\02\04\1234\567\Error.txt would produce folder name AsyncCreateUsersAPIProcessor
Here is my current code but sadly it deletes excluded folder contents. I want to keep folder contents that are inside an excluded folder.
I've been trying for days but can't find a solution. Maybe this is a PowerShell limitation?
$path = "C:\Users\bob\Desktop\testfolder"
$exclude = #('FOLDERNAME', 'filename.txt')
$lastWrite = (Get-Date).AddDays(-30)
Get-ChildItem -Path $path -Recurse -Exclude $exclude | Where-Object {$_.LastWriteTime -le $lastWrite} | Remove-Item
Method 2 (doesn't function) :
$results = Get-ChildItem -Path $path -Recurse | Where-Object {$_.LastWriteTime -le $lastWrite}
$path = "C:\Users\louisp\Desktop\testfolder"
$exclude = #('oldkeep', 'oldkeep2', 'important')
$lastWrite = (Get-Date).AddDays(-30)
foreach ($item in $results) {
$noExeption = $true
foreach($exeption in $exclude){
if($item.name -eq $exeption){
$noExeption = $false
break
}
}
if($noExeption) {
remove-item $item
}
}
There is the code I use. maybe a little rustic, but it works.
$age = (Get-Date).AddDays(-30)
Get-ChildItem C:\Folder -Exclude Z*, FolderName | foreach{
if ($_.LastWriteTime -le $age){
Remove-Item $_.fullname -Recurse -Force -Confirm:$false
}
}
I suggest to following workaround art two:
$results= Get-ChildItem -Path $path -Recurse | Where-Object {$_.LastWriteTime -le $lastWrite}
foreach ($item in $results){
$notExeption=$true
foreach($exeption in $exclude){
if($item.name -eq $exeption){
$noExeption=$false
break
}
}
if($noexeption){
remove-item -LiteralPath $item.name
}
}
I have problems when running a powershell script in Scheduled Tasks. It gets stuck in Running, even though the Transcript has logged out the last row "Done!" and it also looks like it has done exactly what i want it to. What am I missing?
When running it from Run in Windows it also seems fine: powershell -file "D:\_temp\copy_bat\copy_one_reprint_folder.ps1"
Seetings in Task Scheduler is:
Run with full priviliges
Run weither user is logged on or not
Action, start program powershell.exe
-file "D:\_temp\copy_bat\copy_one_reprint_folder.ps1"
Please see code below if needed.
# PowerShell RePRINT copy first folder, sorted on lastModified
function timestamp
{
$ts = Get-Date -format s
return $ts
}
$fromDirectory = "D:\_temp\copy_bat"
$toDirectory = "D:\_temp\in_dummy"
$extractGUIDdir = ""
$docTypeDir = ""
# Logging
#########
$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -path $fromDirectory\copy_one_reprint_folder.log.txt -append
###########
Write-Host ""
Write-Host (timestamp) "Copy RePRINT extract started"
Write-Host (timestamp) "============================"
Get-ChildItem -path $fromDirectory | ?{ $_.PSIsContainer } | Sort-Object CreationTime | `
Where-Object {$_.name -ne "_copied"} | `
Select-Object -first 1 | `
Foreach-Object{
Write-Host (timestamp) $_.name
$extractGUIDdir = $_.FullName
Get-ChildItem -path $extractGUIDdir | ?{ $_.PSIsContainer } | Where-Object {$_.Name -match "Purchase Order \(-999999997\)" -or $_.Name -match "Logistics documents \(-1000000000\)" -or $_.Name -match "Specifications \(-999999998\)"} | `
Foreach-Object{
Write-Host (timestamp) " " $_.Name
}
Write-Host ""
Write-Host "These folders (document types), were also found but will not be included"
Get-ChildItem -path $extractGUIDdir -Exclude "Logistics documents (-1000000000)", "Purchase Order (-999999997)", "Specifications (-999999998)" | ?{ $_.PSIsContainer } | `
Foreach-Object{
Write-Host (timestamp) " - " $_.name
}
Write-Host ""
Get-ChildItem -path $extractGUIDdir | ?{ $_.PSIsContainer } | Where-Object {$_.Name -match "Purchase Order \(-999999997\)" -or $_.Name -match "Logistics documents \(-1000000000\)" -or $_.Name -match "Specifications \(-999999998\)"} | `
Foreach-Object{
$temp_name = $_.FullName
Write-Host (timestamp) "copying files from " $_.FullName
Write-Host (timestamp) " to " $toDirectory
#Copy-Item ($_.FullName)\*.* $toDirectory
Write-Host (timestamp) " copying meta-files..."
Copy-Item $temp_name\*.meta $toDirectory -Filter *.meta
Write-Host (timestamp) " copying pdf-files..."
Copy-Item $temp_name\*.pdf $toDirectory -Filter *.pdf
if(Test-Path $temp_name\*.* -Exclude *.meta, *.pdf)
{
Write-Host (timestamp) " WARNING/ERROR not all documents have been moved. Only PDFs was moved!"
Write-Host (timestamp) " Check folder for other document-types."
}
}
Move-Item $extractGUIDdir $fromDirectory\_copied
}
Write-Host (timestamp) " DONE!"
# Stop logging
Stop-Transcript
It is solved.
It works, stupid me did not press F5(update) in task scheduler to update the status of the task in the gui.
Actually I was quite certain I did this, but apparently not.
I'm working on a script that checks folders in specific directory. For example, I run the script for first time, it generates me a txt file containing folders in the directory.
I need the script to add any new directories that are found to the previously created txt file when the script is run again.
Does anyone have any suggestions how to make that happen?
Here is my code so far:
$LogFolders = Get-ChildItem -Directory mydirectory ;
If (-Not (Test-Path -path "txtfilelocated"))
{
Add-Content txtfilelocated -Value $LogFolders
break;
}else{
$File = Get-Content "txtfilelocatedt"
$File | ForEach-Object {
$_ -match $LogFolders
}
}
$File
something like this?
You can specify what directory to check adding path to get-childitem cmdlet in first line
$a = get-childitem | ? { $_.psiscontainer } | select -expand fullname #for V2.0 and above
$a = get-childitem -Directory | select -expand fullname #for V3.0 and above
if ( test-path .\list.txt )
{
compare-object (gc list.txt) ($a) -PassThru | Add-Content .\list.txt
}
else
{
$a | set-content .\list.txt
}
With PowerShell (although other suggestions are welcome), how does one recursively loop a directory/folder and
replace text A with B in all files,
rename all files so that A is replaced by B, and last
rename all folders also so that A is replaced by B?
With a few requirements refinements, I ended up with this script:
$match = "MyAssembly"
$replacement = Read-Host "Please enter a solution name"
$files = Get-ChildItem $(get-location) -filter *MyAssembly* -Recurse
$files |
Sort-Object -Descending -Property { $_.FullName } |
Rename-Item -newname { $_.name -replace $match, $replacement } -force
$files = Get-ChildItem $(get-location) -include *.cs, *.csproj, *.sln -Recurse
foreach($file in $files)
{
((Get-Content $file.fullname) -creplace $match, $replacement) | set-content $file.fullname
}
read-host -prompt "Done! Press any key to close."
I would go with something like this:
Get-ChildItem $directory -Recurse |
Sort-Object -Descending -Property { $_.FullName } |
ForEach-Object {
if (!$_.PsIsContainer) {
($_|Get-Content) -replace 'A', 'B' | Set-Content $_.FullName
}
$_
} |
Rename-Item { $_.name -replace 'A', 'B' }
The Sort-Object is there to ensure that first children (subdirs, files) are listed and then directories after them. (12345)
Untested, but should give you a starting point:
$a = 'A';
$b = 'B';
$all = ls -recurse;
$files = = $all | where{ !$_.PSIsContainer );
$files | %{
$c = ( $_ | get-itemcontent -replace $a,$b );
$c | out-file $_;
}
$all | rename-item -newname ( $_.Name -replace $a,$b );
Untested, may be I'm more lucky ;-)
$hello = 'hello'
$world = 'world'
$files = ls -recurse | ? {-not $_.PSIsContainer}
foearch ($file in $files) {
gc -path $file | % {$_ -replace $hello, $world} | Set-Content $file
ri -newname ($file.name -replace $hello, $world)
}
ls -recurse | ? {$_.PSIsContainer} | ri -newname ($_.name -replace $hello, $world)
To use the same recursion:
$hello = 'hello'
$world = 'world'
$everything = ls -recurse
foearch ($thing in $everything) {
if ($thing.PSIsContainer -ne $true) {
gc -path $thing | % {$_ -replace $hello, $world} | Set-Content $thing
}
ri -newname ($thing.name -replace $hello, $world)
}
I needed this for myself and below slightly better version of the script.
I added followings:
Support for verbose parameter so you can actually see what changes script has made.
Ability to specify folders so you can limit changes.
Adding bower.json, txt and md in to include extensions.
Search and replace content first, do rename later.
Do not replace content if search string is not found (this avoids unnecessary change in modified date).
[CmdletBinding(SupportsShouldProcess=$true)]
Param()
$match = "MyProject"
$replacement = Read-Host "Please enter project name"
$searchFolders = #("MyProject.JS", "MyProject.WebApi", ".")
$extensions = #("*.cs", "*.csproj", "*.sln", "bower.json", "*.txt", "*.md")
foreach($searchFolderRelative in $searchFolders)
{
$searchFolder = join-path (get-location) $searchFolderRelative
Write-Verbose "Folder: $searchFolder"
$recurse = $searchFolderRelative -ne "."
if (test-path $searchFolder)
{
$files = Get-ChildItem (join-path $searchFolder "*") -file -include $extensions -Recurse:$recurse |
Where-Object {Select-String -Path $_.FullName $match -SimpleMatch -Quiet}
foreach($file in $files)
{
Write-Verbose "Replaced $match in $file"
((Get-Content $file.fullname) -creplace $match, $replacement) | set-content $file.fullname
}
$files = Get-ChildItem $searchFolder -filter *$match* -Recurse:$recurse
$files |
Sort-Object -Descending -Property { $_.FullName } |
% {
Write-Verbose "Renamed $_"
$newName = $_.name -replace $match, $replacement
Rename-Item $_.FullName -newname $newName -force
}
}
else
{
Write-Warning "Path not found: $searchFolder"
}
}
Note that one change from the answer is that above recurses folder only in specified folders, not in root. If you don't want that then just set $recurse = true.