I've got the following powershell line:
$items = Get-ChildItem -Path "C:\temp" -Filter "*ä*" -Recurse | Select FullName
I want to write those paths to a *.txt file:
foreach ($item in $items){
add-content -Path C:\temp\test.txt -Value $item -Force
}
Output in test.txt:
#{FullName=C:\temp\ä}
How can I only write the Value of FullName to the txt-file ?
For example:
echo $item
and Output in Console:
C:\temp\ä
Common gotcha with PowerShell. $items is not an array of FullNames but an object array with a fullname property. (Array assuming more that one item was returned.)
$items = Get-ChildItem -Path "C:\temp" -Filter "*ä*" -Recurse | Select -Expand FullName
or
# Requires PowerShell v3.0 or above
$items = (Get-ChildItem -Path "C:\temp" -Filter "*ä*" -Recurse).Fullname
You should be able to do this:
foreach ($item in $items){
add-content -Path C:\temp\test.txt -Value $item.FullName -Force
}
Here's a common way to find this bit of info:
Get-ChildItem | Get-Member
Or the same with shorthands:
dir | gm
This will list all properties, methods, etc for the objects returned from Get-ChildItem.
Related
I am using the following script to read a list of file names which are then deleted. Is there a way can get an output of the date and time each file is deleted?
$targetFolder = "D:\" $fileList = "C:\DeleteList.txt" Get-ChildItem
-Path "$targetFolder\*" -Recurse -Include #(Get-Content $fileList) | Remove-Item -Verbose
Thanks for any help.
You could keep track of the files that are deleted and the time of deletion by outputting an object with the file's fullname and current date.
This output can then be saved as structured CSV file
$targetFolder = "D:\"
$fileList = Get-Content -Path "C:\DeleteList.txt"
$deleted = Get-ChildItem -Path $targetFolder -Recurse -Include $fileList | ForEach-Object {
# output an object with the current date and the file FullName
$_ | Select-Object #{Name = 'DeletedOn'; Expression = {(Get-Date)}}, FullName
$_ | Remove-Item -WhatIf
}
# output on screen
$deleted | Format-Table -AutoSize
# output to csv file
$deleted | Export-Csv -Path 'C:\RemovedFiles.csv' -NoTypeInformation
Remove the -WhatIf safety-switch if you are satisfied with the results shown on screen.
Would this work?
$targetFolder = "D:"
$fileList = "C:\DeleteList.txt"
$Files = Get-ChildItem -Path "$targetFolder" -Recurse -Include #(Get-Content $fileList)
# Once you have the desires files stored in the $Files variable, then run a Foreach loop.
$Obj = #() # create an array called $Obj
Foreach ($File in $Files)
{
# store info in hash table
$hash = #{
DateTime = (get-date)
fileName = $File.name
fullpath = $File.fullname
}
Write-Host "deleting file $($file.name)" -for cyan
Remove-Item $File.fullname # *** BE VERY CAREFUL!!!***
# record information in an array called $Obj
$Obj += New-Object psobject -Property $hash
}
$Obj | select fileName, DateTime | Export-csv C:\...
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.
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"
How do I show AND count matching files using a single Get-ChildItem command in PowerShell? Currently I am using two Get-ChildItem commands, the first to count, the second to display the files - works fine but it is not very effective when scanning an entire disk ...
Command to count the matches:
$count = Get-ChildItem -Path $searchLocation -Filter $filename -Recurse -ErrorAction SilentlyContinue | Measure-Object | %{$_.Count}
Command to display the files:
Get-ChildItem -Path $searchLocation -Filter $filename -Recurse -ErrorAction SilentlyContinue | %{$_.FullName}
As Get-ChildItem is returning an array, its size is stored in .Length member and explicit measurement is not needed. Thus, store the file names in the same collection and then print length for number of entries and iterate the collection for file names. Swapping the variable name as $files to reflect this like so,
$files = Get-ChildItem -Path $searchLocation -Filter $filename `
-Recurse -ErrorAction SilentlyContinue
# ` can used to divide command into multiple lines (and work-around for markup stupidness)
# prints the number of items
$files.Length
# prints the full names
$files | %{$_.FullName}
An alternative method is to add a file number to each file as it processes.
$i = 1
$Files = Get-ChildItem -Path $searchLocation -Filter $filename -Recurse -ErrorAction SilentlyContinue
Foreach($Item in $Files) {
$Item | Add-Member -MemberType NoteProperty -Name FileNo -Value $i
$i++
}
$Files | Select-Object FileNo, Fullname
You can then see the order the files were processed, get the last file number by doing $File[-1].FileNo. And it will maintain all the additional file metadata suck as CreationTime, DirectoryName, VersionInfo etc.
Simply like this :
$AllFile=Get-ChildItem $searchLocation -File -Filter $filename -Recurse | select FullName
$AllFile.Count
$AllFile.FullName
Or you can ad a rank into your loop like this :
$Rang=0
Get-ChildItem "c:\temp" -File -Filter "*.txt" -Recurse | %{
$Rang++
Add-Member -InputObject $_ -Name "Rang" -MemberType NoteProperty -Value $rang
$_
} | select Rang, FullName
Currently , I can export the list to a text file and separate them by share name.
My question is : I want to be able to count the number of files in the directory as well as the number of folders into a separate text file.
I'd like to do in this format for text file , $hostname-$sharename-count.txt
For example:
My desired output:
1000 #Folder count
150 #File count
Here is what I have so far:
$outputDir = 'C:\Output'
$Shares = Get-WmiObject Win32_Share -Filter "not name like '%$'"
$re = ($Shares | ForEach-Object {[Regex]::Escape($_.Path)}) -join '|'
foreach ($Share in $Shares) {
$result = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName) -replace "^($re)\\"
# output the results per share in a text file
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}.txt' -f $env:COMPUTERNAME, $Share.Name)
$result | Out-File -FilePath $fileOut -Force
}
You can simply expand the code you have like below:
$outputDir = 'C:\Output'
$Shares = Get-WmiObject Win32_Share -Filter "not name like '%$'"
$re = ($Shares | ForEach-Object {[Regex]::Escape($_.Path)}) -join '|'
foreach ($Share in $Shares) {
$files = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName) -replace "^($re)\\"
# output the list of files per share in a text file
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}.txt' -f $env:COMPUTERNAME, $Share.Name)
$files | Out-File -FilePath $fileOut -Force
# output the count results for files and folders per share in a text file
$folders = Get-ChildItem -Path $Share.Path -Directory -Recurse
$content = 'Folders: {0}{1}Files: {2}' -f $folders.Count, [Environment]::NewLine, $files.Count
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}-count.txt' -f $env:COMPUTERNAME, $Share.Name)
$content | Out-File -FilePath $fileOut -Force
}
P.S. You can add switch -Force to the Get-ChildItem cmdlet to also get the hidden or system files listed if there are any such files inside the shares
If you just want to have a count, you could do something like this:
$resultForFiles = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName)
$resultForFolders = (Get-ChildItem -Path $Share.Path -Directory -Recurse | Select-Object -Expand FullName)
$resultForFiles.Count | Out-File "Path" -Append
$resultForFolders.Count | Out-File "Path" -Append
The -File switch for Get-ChildItem will only get files and the -Directory will only get folders
You can do this in just one line of code
Get-ChildItem | Measure-Object -Property Mode
The property Mode from Get-ChildItem tells you if you are getting folders, files or others.
You can also use get-help Measure-Object -Examples to check some useful examples on measuring files and folders