How to create empty files in all empty folders using PowerShell? - powershell

I want to create empty text files in all the subfolders which are empty. The following piece of script will list all the empty subfolders.
$a = Get-ChildItem D:\test -recurse | Where-Object {$_.PSIsContainer -eq $True}
$a | Where-Object {$_.GetFiles().Count -eq 0} | Select-Object FullName
How can I iterate through the output of the above command and create empty text files in them?

There were a few too many loops in the answer you made for yourself. I offer this solution which will make an empty file in all directories that do not have files ( From your solution it is OK if they have folders so I'm keeping with that logic.)
Get-ChildItem -Recurse C:\temp |
Where-Object {$_.PSIsContainer -and ($_.GetFiles().Count -eq 0)} |
ForEach-Object{[void](New-Item -Path $_.FullName -Name "Touch.txt" -ItemType File)}
If $_.PSIsContainer is false then it won't bother with the other condition of checking for files. Also cast the output of New-Item to void to stop the output of successfully created all those new files.

The following piece of code worked for me.
$a = Get-ChildItem D:\test -recurse | Where-Object {$_.PSIsContainer -eq $True}
$path = $a | Where-Object {$_.GetFiles().Count -eq 0} | foreach {$_.FullName}
$a | Where-Object {$_.GetFiles().Count -eq 0} | foreach {$_.FullName}|ForEach-Object -Process {New-Item -Path $path -Name "testfile.txt" -Value "Test Value" -ItemType File }

How make sure.. this does not create the file in a directory, which has sub directory in it.
i.e. file should be created in a directory where there are no files and sub-directories

this worked for me .. it creates file only if the directory neither has sub-directories or files
$a = Get-ChildItem C:\tejasoft -recurse | Where-Object {$_.PSIsContainer -eq $True -and ($_.GetDirectories().Count -eq 0)}
$path = $a | Where-Object {$_.GetFiles().Count -eq 0} | foreach {$_.FullName}
$a | Where-Object {$_.GetFiles().Count -eq 0} | foreach {$_.FullName}|ForEach-Object -Process {New-Item -Path $path -Name ".keep" -Value "Test Value" -ItemType File }

Related

Powershell Find all empty folders and subfolders in a given Folder name

I´m trying to get a
a) list of all empty folders and subfolders if the folder is named "Archiv"
b) I´d like to delete all those empty folders. My current approch doesn´t check the subfolders.
It would be also great if the results would be exportet in a .csv =)
$TopDir = 'C:\Users\User\Test'
$DirToFind = 'Archiv'>$EmptyDirList = #(
Get-ChildItem -LiteralPath $TopDir -Directory -Recurse |
Where-Object {
#[System.IO.Directory]::GetFileSystemEntries($_.FullName).Count -eq 0
$_.GetFileSystemInfos().Count -eq 0 -and
$_.Name -match $DirToFind
}
).FullName
$EmptyDirList
Any ideas how to adjust the code? Thanks in advance
You need to reverse the order in which Get-ChildItem lists the items so you can remove using the deepest nested empty folder first.
$LogFile = 'C:\Users\User\RemovedEmptyFolders.log'
$TopDir = 'C:\Users\User\Test'
# first get a list of all folders below the $TopDir directory that are named 'Archiv' (FullNames only)
$archiveDirs = (Get-ChildItem -LiteralPath $TopDir -Filter 'Archiv' -Recurse -Directory -Force).FullName |
# sort on the FullName.Length property in Descending order to get 'deepest-nesting-first'
Sort-Object -Property Length -Descending
# next, remove all empty subfolders in each of the $archiveDirs
$removed = foreach ($dir in $archiveDirs) {
(Get-ChildItem -LiteralPath $dir -Directory -Force) |
# sort on the FullName.Length property in Descending order to get 'deepest-nesting-first'
Sort-Object #{Expression = {$_.FullName.Length}} -Descending |
ForEach-Object {
# if this folder is empty, remove it and output its FullName for the log
if (#($_.GetFileSystemInfos()).Count -eq 0) {
$_.FullName
Remove-Item -LiteralPath $_.FullName -Force
}
}
# next remove the 'Archiv' folder that is now possibly empty too
if (#(Get-ChildItem -LiteralPath $dir -Force).Count -eq 0) {
# output this folders fullname and delete
$dir
Remove-Item -LiteralPath $dir -Force
}
}
$removed | Set-Content -Path $LogFile -PassThru # write your log file. -PassThru also writes the output on screen
Not sure a CSV is needed, I think a simple text file will suffice as it's just a list.
Anyway, here's (although not the most elegant) a solution which will also delete "nested empty directories". Meaning if a directory only contains empty directorIS, it will also get deleted
$TopDir = "C:\Test" #Top level directory to scan
$EmptyDirListReport = "C:\EmptyDirList.txt" #Text file location to store a file with the list of deleted directorues
if (Test-Path -Path $EmptyDirListReport -PathType Leaf)
{
Remove-Item -Path $EmptyDirListReport -Force
}
$EmptyDirList = ""
Do
{
$EmptyDirList = Get-ChildItem -Path $TopDir -Recurse | Where-Object -FilterScript { $_.PSIsContainer } | Where-Object -FilterScript { ((Get-ChildItem -Path $_.FullName).Count -eq 0) } | Select-Object -ExpandProperty FullName
if ($EmptyDirList)
{
$EmptyDirList | Out-File -FilePath $EmptyDirListReport -Append
$EmptyDirList | Remove-Item -Force
}
} while ($EmptyDirList)
This should do the trick, should works with nested too.
$result=(Get-ChildItem -Filter "Archiv" -Recurse -Directory $topdir | Sort-Object #{Expression = {$_.FullName.Length}} -Descending | ForEach-Object {
if ((Get-ChildItem -Attributes d,h,a $_.fullname).count -eq 0){
$_
rmdir $_.FullName
}
})
$result | select Fullname |ConvertTo-Csv |Out-File $Logfile
You can do this with a one-liner:
> Get-ChildItem -Recurse dir -filter Archiv |
Where-Object {($_ | Get-ChildItem).count -eq 0} |
Remove-Item
Although, for some reason, if you have nested Archiv files like Archiv/Archiv, you need to run the line several times.

recursively count files in folder and output to file

I want to count files for every folder on an E-drive, and output the folder path and file count to a text file using PowerShell (version 2).
I have found this script, but it outputs to console. How do I change it to output to a text file?
Set-Location -Path E:\
Get-ChildItem -recurse | Where-Object{ $_.PSIsContainer } | ForEach-Object{ Write-Host $_.FullName (Get-ChildItem $_.FullName | Measure-Object).Count }
I think it would be best to get an array of resulting objects where you can store both the directory path and the number of files it contains. That way, you can afterwards show it in the console and also save it to a structured CSV file you can open in Excel.
This is for PowerShell 2:
# to keep the property order in PS version < 3.0, create an
# Ordered Dictionary to store the properties first
$dict = New-Object System.Collections.Specialized.OrderedDictionary
# now loop over the folders
$result = Get-ChildItem -Path 'E:\' -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.PSIsContainer } |
ForEach-Object {
# add the results in the temporary ordered dictionary
$dict.Add('Directory', $_.FullName)
$dict.Add('Files', #(Get-ChildItem -Path $_.FullName -Force -ErrorAction SilentlyContinue |
Where-Object { !$_.PSIsContainer }).Count)
# and output a PSObject to be collected in array '$result'
New-Object PSObject -Property $dict
$dict.Clear()
}
# output on screen
$result | Format-Table -AutoSize
#output to CSV file
$result | Export-Csv -Path 'D:\Test\FileCount.csv' -NoTypeInformation
The -Force switch makes sure you also count items that otherwise can't be accessed by the user, such as hidden or system files.
Get-ChildItem c:\tmp -recurse |
Where-Object{ $_.PSIsContainer } |
ForEach-Object {
"$($_.Fullname) $((Get-ChildItem $_.FullName | Where-Object{!$_.PSIsContainer}).count)"
} |
Out-File c:\tmp\out.txt
You can use the > operator for this:
Set-Location -Path E:\
(Get-ChildItem -recurse | Where-Object{ $_.PSIsContainer } | ForEach-Object{ Write-Host $_.FullName (Get-ChildItem $_.FullName | Measure-Object).Count }) >"OUTPUTFILEPATH.txt"

Compare files without extension and delete files from folder in Powershell

I compare files inside a folder. In this folder some files are existing in two file formats (filename1.jpg, filename1.bmp, ...) and some files are only existing in one format.
I try to find all files which are only existing in .bmp format and delete them.
The Code I got so far is:
$jpg = Get-ChildItem "C:\..\" -File -Filter *.jpg | ForEach-Object -Process {[System.IO.Path]::GetFileNameWithoutExtension($_)}
$bmp = Get-Childitem "C:\..\" -File -Filter *.bmp | ForEach-Object -Process {[System.IO.Path]::GetFileNameWithoutExtension($_)}
Compare-Object $jpg $bmp | where {$_.SideIndicator -eq "=>"}
This lists me the files I am looking for but I have trouble deleting them. I tried some things like:
Compare-Object $jpg $bmp | where {$_.SideIndicator -eq "=>"} | ForEach-Object {
Remove-Item "C:\..\($_.FullName)"
}
but without any success. Does anyone have a hint how I could solve this?
In your foreach your variable is not a file, it is the result from the compare.
Try this:
$a = Get-ChildItem "D:\a" -File -Filter *.jpg
$b = Get-Childitem "D:\b" -File -Filter *.bmp
Compare-Object $a.BaseName $b.BaseName | where {$_.SideIndicator -eq "=>"} | foreach {
$name = $_.InputObject
$File = $b.Where({$_.BaseName -eq $name})
if ($File.Count -gt 1) {
throw "Conflict, more than one file has the name $name"
} else {
Remove-Item -Path $File.FullName
}
}

Finding Files in a directory equal to 0 Powershell

I was wondering how I can display a list of empty files in a directory
$test = gci "C:\Users\Freedom\Documents" -Recurse
$test | Where-Object {$_.PsISContainer} | Select-Object FullName | Where-Object {$_.GetFiles() -eq 0}
I Don't understand because when I do get-childitem | get-member I get a list of properties and methods I can use and in the list is getfiles() why can't I use this method why's it giving me an error message?
Method invocation failed because [System.IO.FileInfo] does not contain a method named 'GetFiles'.
I think you want this:
Get-ChildItem | Where-Object { (-not $_.PSIsContainer) -and ($_.Length -eq 0) }
If you have PowerShell 3.0 or later you can use this:
Get-ChildItem -File | Where-Object { $_.Length -eq 0 }
Of course you can add whatever other parameters for Get-ChildItem that you want (-Recurse, etc.).
Wow I had what I wanted mixed up! And I had to add the .count to the getfiles() method
$test | Where-Object {$_.PsISContainer} | Where-Object {$_.GetFiles().Count -eq 0} | Select-Object FullName
try this
Get-ChildItem "c:\temp" -File -Recurse | where Length -eq 0
Use Get-ChildItem and the File flag, -Recurse is needed to get every file in the folder and in the folder below. Then get all the files were Get-Content returns null.
Get-ChildItem $YourPath -Recurse -File | Where-Object {!(Get-Content $_.Fullname)}

Detect missing filenames in folder

Every day we receive a zipfile from a number of clients. The filename consists of the following:
data_clientname_timestamp.zip
Where "data" is always the same text, "clientname" could be anything and "timestamp" is the file creation date.
The files are always in the same directory. The clientnames are always known in advance, so I know what files should be received.
The script should do the following:
List all files received (created) today
If a file from one or more clients is missing, write "file from client.. missing" to a file
I would like to list the clients in a variable, so those can easily be changed.
What I have so far:
$folder='C:\data'
Get-ChildItem $folder -recurse -include #("*.zip") |
Where-Object {($_.CreationTime -gt (Get-Date).Date )} | select name | out-file $folder\result.txt
But how to check the file for missing files?
Edit:
Testdata:
$Timestamp = (Get-Date).tostring(“yyyyMMddhhmmss”)
New-Item c:\Data -type Directory
New-Item c:\Data\Data_client1_$Timestamp.zip -type file
New-Item c:\Data\Data_client2_$Timestamp.zip -type file
New-Item c:\Data\Data_client3_$Timestamp.zip -type file
New-Item c:\Data\Data_client5_$Timestamp.zip -type file
New-Item c:\Data\Data_client6_$Timestamp.zip -type file
New-Item c:\Data\Data_client7_$Timestamp.zip -type file
exit
Script:
$folder='C:\Data'
$clients = #("client1", "client2", "client3", "client4", "client5", "client6", "client7")
$files = Get-ChildItem $folder -recurse -include #("*.zip") |
Where-Object {($_.CreationTime -gt (Get-Date).Date )}
$files | Select-Object Name | Out-File $folder\result.txt
$files | Where-Object { ($_.Name -replace '.+?_([^_]+).*', '$1') -notin $clients} | Out-File $folder\result2.txt
Start with defining a list of clients you would expect like:
$clients = #("client1", "client2")
Then retrieve all zip files and save it to a variable:
$files = Get-ChildItem $folder -recurse -include #("*.zip") |
Where-Object {($_.CreationTime -gt (Get-Date).Date )}
Export the existing files to your result.txt:
$files | Select-Object Name | Out-File $folder\result.txt
Now you can determine each missing client using the Where-Object cmdlet with a regex that grabs the clientname:
$fileClients = $files | ForEach-Object { ($_.Name -replace '.+?_([^_]+).*', '$1') }
Compare-Object $clients $fileClients | select -ExpandProperty InputObject | Out-File $folder\result2.txt
You need to have a list of your clients somewhere (such as in a CSV file named clients.csv) then you could loop through that list to check if a file is found for each client. For example:
$folder='C:\data'
$Clients = Import-CSV Clients.csv
$Files = Get-ChildItem $folder -recurse -include #("*.zip") | Where-Object {($_.CreationTime -gt (Get-Date).Date )} | select name
$Clients | ForEach-Object {
$Client = $_
$ClientCheck = $Files | Where-Object {$_ -like $Client}
If (-not $ClientCheck) {
Write-Warning "$Client is missing!"
}Else{
Write-Output $ClientCheck
}
} | out-file $folder\result.txt