PoShFolderSize.psm1
function Get-FolderSize { <# .SYNOPSIS Gets amount of Folders & Files within a Folder and its total size in Byte .DESCRIPTION Uses Robocopy to get Total Size, Files and Folders within a given Folder recursiv. No 260 char Path limitation. Only works with GER and EN OS. .PARAMETER Path Path to the Folder that will be checked .PARAMETER Threads Number of Threads robocopy should use, using the /MT Parameter. Allowed Values 1-128. default = 8 .INPUTS System.String System.IO.DirectoryInfo .OUTPUTS System.Management.Automation.PSCustomObject .EXAMPLE Get-FolderSize -Path 'C:\Windows\temp' .EXAMPLE Get-ChildItem 'C:\LHG-IT' | Get-FolderSize #> [CmdLetBinding()] [OutputType([System.Object])] Param( [Parameter( Position=0, ValueFromPipeline, ValueFromPipelineByPropertyName) ] [Alias('FullName')] [string[]]$Path = (Get-Location).Path, [ValidateRange(1,128)] [ValidateNotNullOrEmpty()] [int]$Threads = 8, [switch]$IgnoreLanguage ) Begin { if($IgnoreLanguage) { Write-Warning "Parameter -IgnoreLanguage can cause inacurate results. Only use this Parameter as Last resort."} ### GET PARSER WHITCH IS USED TO PARSE THE ROBOCOPY OUTPUT ### ### BASED ON DETECTED ROBOCOPY LANGUAGE ### ### IF -IgnoreLanguage IS SET, NO ERROR IS THROWN AND ENGLISCH PARSER IS RETURN ### $parser = Get-RobocopyOutputParser -IgnoreLanguage:$IgnoreLanguage } Process { foreach ($p in $Path) { $p = (Resolve-Path $p).ProviderPath $inputItem = Get-Item $p -Force ### CHECK IF INPUT IS A FILE & SKIP IF APPLICABLE ### if(-Not $inputItem.PSIsContainer) { Write-Verbose "Input `"$p`" is a File. Skipping" continue } ### EXECUTING ROBOCOPY DOING THE HEAVY LIFTING ### $robocopyResult = @(robocopy.exe "$p" "." /L /E /BYTES /NFL /NDL /NJH /XJ /R:0 /W:0 /MT:$Threads) ### IF ROBOCOPY RESULT IS LESS THAN 11 LINES, SOMETHING HAS GONNE WRONG if($robocopyResult.Count -lt 11) { Write-Error "Error while checking Filezize of Folder '$p'.`n$robocopyResult" continue } $obj = [pscustomobject]@{ PSTypeName='Robocopy.Result' Path = $p Files = 0 Folders = 0 Size = 0 } ### PARSE ROBOCOPYRESULT LINE BY LINE USING PARSER FROM BEGIN BLOCK ### foreach ($line in $robocopyResult) { foreach ($prop in @("Folders","Files","Size")) { if($line -like $parser.$prop) { ### EXTRACT NUMBERS ONLY ### $obj.$prop = [Regex]::Match($line,"\d+").Value break } } } ### REDUCE FOLDER AMOUNT bY 1 SINCE IT IS ALWAYS OFF BY 1 ### $obj.Folders = [int]$obj.Folders -1 $obj | Add-Member -MemberType ScriptProperty -Name 'Size(GB)' -Value {[Math]::Round(($this.Size/1GB),2)} $obj | Write-Output } } } function Get-RobocopyOutputParser { [CmdLetBinding()] Param( [switch]$IgnoreLanguage ) ### EXECUTE ROBOCOPY TO DETERMAN THE ROBOCOPY LANGUAGE ### Try { $out = robocopy.exe -ErrorAction Stop } catch [System.Management.Automation.CommandNotFoundException] { throw "Failed to execute robocopy.exe - Command not found. Make sure robocopy.exe ist reachable from PATH" } catch { throw $_ } ### LOAD JSON CONTAINING A LANGUAGE MAPPING FROM MODULE FOLDER ### Try { $jsonPath = "$PSScriptRoot\languageMap.json" $languageMapping = Get-Content $jsonPath -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop } catch { throw "Couldn't load JSON `"$jsonPath`". Make sure File exists and is not corrupted" } ### CHECK EVERY LANGUAGEMAPPING IF HELPMSG MATCHES WITH ROBOCOPY OUTPUT ### foreach ($prop in $languageMapping.PSOBject.Properties.Name) { if(($out | Select-String -Pattern $languageMapping.$prop.HelpMsg)) { return $languageMapping.$prop } } ### LANGUAGE NOT SUPPORTED ### if($IgnoreLanguage) { return $languageMapping.EN } throw "Language of Robocopy CLI could not be detected and is not supported." } New-Alias -Name gfs -Value Get-FolderSize -Force |