Get total number of files and Sub folders in a folder - powershell

I have a task to carry out 3 times a day on a WS2012R2 to get the Disk size, total number of files and folders including subdirectories from a folder on a remote server.
Currently I get this information by RDP'ing to the target, navigating to the folder and right clicking the folder to copy the info:
I have already tried the PowerShell script :
Get-ChildItem E:\Data -Recurse -File | Measure-Object | %{$_.Count}
and other PowerShell scripts.
Which produced countless errors pertaining to not having permissions for some sub directories or simply gave results I didn't want such.
I have tried VBscript but VBscript simply cannot get this information.

You can just access the count property:
$items = Get-ChildItem E:\Data -Recurse -File
($items | Where { -not $_.PSIsContainer}).Count #files
($items | Where $_.PSIsContainer).Count #folders

To summarise the comments so far.
You can get the size of the C drive with:
$Drive = "C"
Get-PSDrive -Name $Drive | Select-Object #{N="Used Space on $Drive Drive (GB)"; E={[Math]::Round($_.Used/1GB)}}
But you cannot use something like the code below to count the files & folders for the whole C drive, but it works for simple filestructures and simple drives.
I use the code to calculate my other drives and for my homepath, just change $Path to e.g "$Env:Homepath".
There's the path length problem which is a .NET thing and won't be
fixed until everyone (and PowerShell) is using .NET 4.6.2. Then
there's that you're acting as you counting it, not the operating
system counting.
[Int]$NumFolders = 0
[Int]$NumFiles = 0
$Path = "C:\"
$Objects = Get-ChildItem $Path -Recurse
$Size = Get-ChildItem $Path -Recurse | Measure-Object -property length -sum
$NumFiles = ($Objects | Where { -not $_.PSIsContainer}).Count
$NumFolders = ($Objects | Where {$_.PSIsContainer}).Count
$Summary = New-Object PSCustomObject -Property #{"Path" = $Path ; "Files" = $NumFiles ; "Folders" = $NumFolders ; "Size in MB" = ([Math]::Round($Size.sum /1MB))}
$Summary | Format-list
To run this on remote computers, I would recommend using New-PsSession to the computer/computers, then Invoke-Command to run the code using the new sessions.

Related

Single Folder Tree Size Report

I am trying to create a very specific Powershell report script that I can input a server list via CSV or TXT, and have it check a specific folder who's path exists on every server. Then output that information to a formatted CSV file with the server name, and the total size of that single folder tree.
I've been looking at the following thread: (Powershell folder size of folders without listing Subdirectories, as it seems to have the closest code examples of what I need to accomplish, but none of them are setup for a server report input and output.
The script shouldn't need any credentials as it will be running with elevated privileges. I don't think a function will be necessary as I plan to change the defined path as different situations come up.
I'm usually pretty good at piecing together different scripts I find. However I'm a bit stumped trying to find something that matches this exact function, so I'm not even sure where to start. I'm new to powershell and not very good at writing complex scripts by hand yet.
servers.txt
server1
server2
there are two ways, one by smb, one using winRM
1 + Powershell folder size of folders without listing Subdirectories
$servers = Get-Content "$PSScriptRoot\servers.txt"
$path = "c$\Distr"
$result = #()
foreach ($server in $servers){
$fullpath = "\\" + $server + "\" + "$path"
$fullpath
$size = (Get-ChildItem -Recurse -Force $fullpath | Measure-Object -Property Length -Sum).sum
$array = "" | Select server, size
$array.server = $server
$array.size = $size
$result+=$array
}
$result |Export-Csv -Delimiter ";" -Encoding UTF8 -Path "$PSScriptRoot\result.csv"
if the network connection is slow enough, it's better to use WinRM, but I don't have an example at hand right now.
Thanks to rinat gadev for the starter code. Here's my final with adjustments that does exactly what I wanted.
$servers = Get-Content "$PSScriptRoot\servers.txt"
$path = "c$\Distr"
$result = #()
foreach ($server in $servers){
$fullpath = "\\" + $server + "\" + "$path"
$fullpath
$size = (Get-ChildItem -Recurse -Force $fullpath | Measure-Object -Property Length -Sum ).sum | ForEach-Object {[math]::Round($_/1GB,2)}
$array = "" | Select-Object Server, Size
$array.server = $server
$array.size = $size
$result+=$array
}
$result | Export-Csv -Path "$PSScriptRoot\result.csv"-NoTypeInformation -UseCulture

Delete all files and folder working very slow

I need to delete all the archived files and folder older than 15 days.
I have implemented the solution using PowerShell script but it taking more than a day to delete all files. Total size of the folder is less than 100 GB.
$StartFolder = "\\Guru\Archive\"
$deletefilesolderthan = "15"
#Get Foldernames for ForEach Loop
$SubFolders = Get-ChildItem -Path $StartFolder |
Where-Object {$_.PSIsContainer -eq "True"} |
Select-Object Name
#Loop through folders
foreach ($Subfolder in $SubFolders) {
Write-Host "Processing Folder:" $Subfolder
#For each folder recurse and delete files olders than specified number of days while the folder structure is left intact.
Get-ChildItem -Path $StartFolder$($Subfolder.name) -Include *.* -File -Recurse |
Where LastWriteTime -lt (Get-Date).AddDays(-$deletefilesolderthan) |
foreach {$_.Delete()}
#$dirs will be an array of empty directories returned after filtering and loop until until $dirs is empty while excluding "Inbound" and "Outbound" folders.
do {
$dirs = gci $StartFolder$($Subfolder.name) -Exclude Inbound,Outbound -Directory -Recurse |
Where {(gci $_.FullName).Count -eq 0} |
select -ExpandProperty FullName
$dirs | ForEach-Object {Remove-Item $_}
} while ($dirs.Count -gt 0)
}
Write-Host "Completed" -ForegroundColor Green
#Read-Host -Prompt "Press Enter to exit"
Please suggest some way to optimise the performance.
If you have many smaller files, the long delete time is not abnormal because it has to process each file descriptor. Some improvements can be made depending on your version; I'm going to assume you're on at least v4.
#requires -Version 4
param(
[string]
$start = '\\Guru\Archive',
[int]
$thresholdDays = 15
)
# getting the name wasn't useful. keep objects as objects
foreach ($folder in Get-ChildItem -Path $start -Directory) {
"Processing Folder: $folder"
# get all items once
$folders, $files = ($folder | Get-ChildItem -Recurse).
Where({ $_.PSIsContainer }, 'Split')
# process files
$files.Where{
$_.LastWriteTime -lt (Get-Date).AddDays(-$thresholdDays)
} | Remove-Item -Force
# process folders
$folders.Where{
$_.Name -notin 'Inbound', 'Outbound' -and
($_ | Get-ChildItem).Count -eq 0
} | Remove-Item -Force
}
"Complete!"
The reason why it takes so many time is that you are deleting files/folder over network which leads to need for additional network communication for every file and folder. You can easily check that fact using network analyzer. The best approach here is to use one of the method that allows to run code which executes file operations on remote machine, for example you can try to use:
WinRM
psexec (first copy code to remote machine and then execute it using psexec)
remote WMI (using CIM_Datafile)
or even adding needed task to the scheduler
I would prefer to use WinRM but psexec is also good decision (if you don't want to perform additional configuration of WinRM).

Get Count of a Zip folder + match size Powershell

Trying to get Count of a zip folder that has for example 30 CSV files
The test folder has 30 csv files
$directoryInfo = Get-ChildItem "$TEST\*.csv" | Measure-Object
$directoryInfo.count
All 30 csv files will be compressed into a zip folder = TESTZIP1.zip located inside of TEST folder.
If I try to run the following to measure how many files are inside of the compressed folder, I get 0 as answer
$backUP = Get-ChildItem "$zipfiletest\TESTZIP1.zip\*.csv" | Measure-Object
$backUP.count
Goal: able to Count() how many files are inside of zip folder, and if zip folder has the same amount of files as TEST folder, sends an email.
If you want to count the files inside your zip-file, you can do it like this:
$ZipFile = [System.IO.Compression.ZipFile]::Open("$zipfiletest\TESTZIP1.zip",[System.IO.Compression.ZipArchiveMode]::Read)
$ZipFile.Entries.count
$ZipFile.Dispose()
If you want to check anything else inside the zip file, you can easily explore the other parameters of the $ZipFile variable
$fileToCheck = Get-Item -Path (Join-Path -Path "C:\Users\" -ChildPath test.zip) - ErrorAction SilentlyContinue
$ZipFiles = Get-ChildItem -Path $fileToCheck -Recurse -Filter '*.zip'
$Shell = New-Object -ComObject Shell.Application
$Results = foreach( $fileToCheck in $ZipFiles ){
$DATCount = $Shell.NameSpace($fileToCheck.FullName).Items() |
Where-Object { $_.Name -match '\.dat$' } |
Measure-Object |
Select-Object -ExpandProperty count

Search a specified path for multiple .xml files within the same folder

I am seeking help creating a PowerShell script which will search a specified path for multiple .xml files within the same folder.
The script should provide the full path of the file(s) if found.
The script should also provide a date.
Here's my code:
$Dir = Get-ChildItem C:\windows\system32 -Recurse
#$Dir | Get-Member
$List = $Dir | where {$_.Extension -eq ".xml"}
$List | Format-Table Name
$folder = "C:\Windows\System32"
$results = Get-ChildItem -Path $folder -File -Include "*.xml" | Select Name, FullName, LastWriteTime
This will return all xml files only and display the file name, full path to the file and last time it was written to. The "-File" switch is only available in Powershell 4 and up. So if doing it off a Windows 7 or Windows 2008 R2 Server, you will have to make sure you updated your WMF to 4 or higher. Without file the second like will look like.
#Powershell 2.0
$results = Get-ChildItem -Path $folder -Include "*.xml" | Where {$_.PSIsContainer -eq $false} | Select Name, FullName, LastWriteTime
I like the Select method mentioned above for the simpler syntax, but if for some reason you just want the file names with their absolute path and without the column header that comes with piping to Select (perhaps because it will be used as input to another script, or piped to another function) you could do the following:
$folder = 'C:\path\to\folder'
Get-ChildItem -Path $folder -Filter *.xml -File -Name | ForEach-Object {
[System.IO.Path]::GetFullPath($_)
}
I'm not sure if Select lets you leave out the header.
You could also take a look at this answer to give you some more ideas or things to try if you need the results sorted, or the file extension removed:
https://stackoverflow.com/a/31049571/10193624
I was able to make a few changes exporting the results to a .txt file, but though it provides the results I only want to isolate the same .xml files.
$ParentFolder = "C:\software"
$FolderHash = #{}
$Subfolders = Get-ChildItem -Path $ParentFolder
foreach ($EventFolder in $Subfolders) {
$XMLFiles = Get-ChildItem -Path $EventFolder.fullname -Filter *.xml*
if ($XMLFiles.Count -gt 1) {
$FolderHash += #{$EventFolder.FullName = $EventFolder.LastWriteTime}
}
}
$FolderHash
Judging from your self-answer you want a list of directories that contain more than one XML file without recursively searching those directories. In that case your code could be simplified to something like this:
Get-ChildItem "${ParentFolder}\*\*.xml" |
Group-Object Directory |
Where-Object { $_.Count -ge 2 } |
Select-Object Name, #{n='LastWriteTime';e={(Get-Item $_.Name).LastWriteTime}}

Multiple counts from Powershell Get-ChildItem?

How would I use powershell to count the number of files and the number of folders under a folder, emulating the Windows "properties" of that folder?
The FAQ says cross-posting is OK, so the full question can be found at: https://superuser.com/questions/605911/multiple-counts-from-powershell-get-childitem
Basically you need to enumerate all files and folders for a given path and maintain a count of each object type:
$files=$folders=0
$path = "d:\temp"
dir $path -recurse | foreach { if($_.psiscontainer) {$folders+=1} else {$files+=1} }
"'$path' contains $files files, $folders folders"
Edit:
Edited to improve efficiency and stop loops...
This can also be done by using the Measure-Object cmdlet with Get-childItem cmdlet:
gci "C:\" -rec | Measure -property psiscontainer -max -sum | Select `
#{Name="Path"; Expression={$directory.FullName}},
#{Name="Files"; Expression={$_.Count - $_.Sum}},
#{Name="Folders"; Expression={$_.Sum}}
Output:
Path Files Folders
---- ----- -------
C:\Test 470 19