| Problém - máme file server a potřebujeme najít všechny adresáře, jejichž obsah se už dlouho nezměnil. Použijeme k tomu samozřejmě PowerShell. Vyhledat dlouho nezměněné soubory není vůbec problém, stačí porovnat jejich atribut LastWriteTime. Jenže tohle nechceme, bude toho obvykle (sto)(deseti)tisíce, prostě mnoho. Já chci vidět jen adresář, jehož celý obsah má poslední modifikaci starší, než například 410 dnů.
Takže zde je funkce, která prohledá celou adresářovou strukturu a vrátí jen adresáře, jejichž žádný soubor se nezměnil nedávno, než před nějakým počtem dnů.
function Get-FsAgeMap (
[Parameter(Position=0, Mandatory=$true)] [ValidateScript({ Test-Path $fsRoot })] [string] $fsRoot,
[Parameter(Position=1)] [ValidateScript({ $_ -ge 0 })] [int] $ageDaysAtLeast = 0,
[switch] $returnOnlyParent
)
{
if ($returnOnlyParent -and ($ageDaysAtLeast -eq 0)) {
throw 'You must specify some minimum days of age to use the -returnOnlyParent parameter'
}
$fsRoot = $fsRoot.TrimEnd('\')
[hashtable] $ageMap = @{}
[bool] $uncFsRoot = $fsRoot -like '\\?*\?*'
# Note: using -Force parameter in order to obtain System and Hidden files as well
dir $fsRoot -Recurse -Force | ? { -not $_.PsIsContainer } | % {
[IO.FileInfo] $oneFile = $_
[int] $ageDays = ([DateTime]::Now - $oneFile.LastWriteTime).TotalDays
[string] $onePath = $oneFile.FullName
while ($true) {
[string] $onePath = Split-Path -Parent $onePath
if ((-not ([string]::IsNullOrEmpty($onePath))) -and ($onePath.Length -ge $fsRoot.Length)) {
if ($ageMap.ContainsKey($onePath)) {
$ageMap[$onePath] = [Math]::Min($ageDays, $ageMap[$onePath])
} else {
[void] $ageMap.Add($onePath, $ageDays)
}
} else {
break
}
}
}
if ($ageDaysAtLeast -gt 0) {
[Collections.ArrayList] $ageMapKeys = $ageMap.Keys
foreach ($oneAgeMapKey in $ageMapKeys) {
if ($ageMap[$oneAgeMapKey] -lt $ageDaysAtLeast) {
[void] $ageMap.Remove($oneAgeMapKey)
}
}
if ($returnOnlyParent) {
[Collections.ArrayList] $ageMapKeys = $ageMap.Keys
$ageMapKeys.Sort()
[int] $i = 0
while ($i -lt $ageMapKeys.Count) {
[string] $oneAgeMapKey = $ageMapKeys[$i]
$i ++
while (($i -lt $ageMapKeys.Count) -and ($ageMapKeys[$i] -like (Join-Path $oneAgeMapKey '?*'))) {
[void] $ageMap.Remove($ageMapKeys[$i])
$i ++
}
}
}
}
return $ageMap
}
Zavoláte to jednoduše, buď s pomocí lokální cesty, nebo pomocí UNC síťové cesty, to je jedno. Parametr returnOnlyParent způsobí, že ve výsledku budou opravdu jen ty nejvrchnější adresáře. Pokud byste to tam nedali, tak by to vrátilo všechny adresáře, jejichž obsah je starší než zadaný počet dnů, takže by tam jedna podcesta byla zbytečně vícekrát. Například takto:
$ageMap = Get-FsAgeMap -fsRoot '\\fs1\profiles' -ageDaysAtLeast 210 -returnOnlyParent
|