This code works well in Powershell 5+ but doesn't work in Powershell 4.0 and 2.0:
$DaysToDelete = 2
$targets = "profile/Default",
"profile/Profile 1",
"profile/Profile 2",
"profile/Profile 3",
"profile/Profile 4"
$special = @("chromium", "64")
$profiles = Get-ChildItem "C:\" -Directory -Force |
Where-Object Name -In $special |
Select-Object -ExpandProperty FullName
$chromeDir = "C:\Users\*\AppData\Local\Google\Chrome\User Data\Default"
$chromeSetDir = "C:\Users\*\Local Settings\Application Data\Google\Chrome\User Data\Default"
$Items = @("*Archived History*",
"*Cache*",
"*Cookies*",
"*History*",
"*Top Sites*",
"*Visited Links*",
"*Web Data*")
$profiles | ForEach-Object {
foreach($target in $targets) {
$profile = Join-Path $_ $target
$items | ForEach-Object {
$item = $_
Get-ChildItem $profile, $chromeDir, $chromeSetDir -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { ($_.CreationTime -lt $(Get-Date).AddDays(-$DaysToDelete)) -and $_.Directory -like $item} | ForEach-Object {
$path = Join-Path $_.DirectoryName $_
Remove-Item $path -force -Verbose -recurse -ErrorAction SilentlyContinue }
}
}
}
I revealed that the piece which breaks the execution is
-and $_.Directory -like $item
It works fine on PS 5+ (Windows 10) but finds nothing alike pattern on PS 4 (Windows 7). Chrome version and its directory hierarchy are the same on both machines: 59.0.3071.115 (Official Build) (64-bit).
Starting script on Win10 with version specification alike
powershell.exe -Version 4.0
gave nothing, it ran fine anything. I am not so fluent in Powershell version-specifics, so gurus are welcomed to propose any suggestions. How to make the script version-independent?
UPDATE: Here is the full code, but it gives nothing valuable. I verified all the places and exactly localized that problem line is the above.
Another interesting moment: I discovered that problem is not in the like
clause per se, but in the combination of like
and $_.CreationTime
check:
$_.CreationTime -lt $(Get-Date).AddDays(-$DaysToDelete) -and $_.Directory -like $item
If I put either of these conditions by itself, all is working fine, but if I combine them into single compound condition, nothing is returned, though there are folders that meet both conditions.
I cannot explain this in any way.
I mentioned this in the comments; am not sure if it was clear enough, and whether this is the whole issue.
As per your original question, this line will not work. This is not dependent on the PowerShell version.
$_.Directory -like $item
When Get-ChildItem
finds files, it will return a System.IO.FileInfo
class object.
Directory
is a property of the FileInfo
class, so files will have this property.Directory
is of the type DirectoryInfo
.When Get-ChildItem
finds folders/directories, it will return a System.IO.DirectoryInfo
class object.
DirectoryInfo
objects do not have a Directory
property.Parent
, which also returns a System.IO.DirectoryInfo
objectIn either case, you are dealing with an object and comparing it to a string. When really you probably want to compare the folder Name to a string.
Edit: True for Windows 8.1 running v5.1.14409.1005
; expect to be the same for older OSes.
False for Windows 10 running PS v5.1.143993.1480
; expect to be the same on Server 2016. Not sure how the Name
/FullName
property is being automagically evaluated...
Get-ChildItem -File | Where {$_.Directory -like "*test*"} # not ok: comparing object to string.
Get-ChildItem -Directory | Where {$_.Directory.Name -like "*test*"} # not ok: DirectoryInfo object does not have Directory property
Get-ChildItem -File | Where {$_.Directory.Name -like "*test*"} # ok
Get-ChildItem -Directory | Where {$_.Parent.Name -like "*test*"} # ok
How to make the script version-independent?
For me the best way how to make it version-independent is to use the lowest version you need to support, which in your case is 2.0.
The other option is to detect the PowerShell version and make your version independent from each other.
I went through your script and
I recommend using Test-Path -Path "$var"
facility to test validity of the findings before actually removing the item.
Now to actually work on your issue: I have had similar issue when using PowerShell and clearning user profiles.
Adjusting for your particular case (circumventing your issue with like
):
$newer_file_exist += Get-ChildItem -Path $profile -Recurse -Force -ErrorAction SilentlyContinue | Where-Object {$_.PSIsContainer -eq $FALSE} | where {($_.CreationTime).ToString('yyyy-MM-dd') -lt (get-date).adddays(-$DaysToDelete).ToString('yyyy-MM-dd')};
It will select all the files that are newer than -$DaysToDelete
. It will recurse and select only files {$_.PSIsContainer -eq $FALSE}
. If you want to select directory `{$_.PSIsContainer -eq $TRUE}.
# get all files to be deleted
ForEach ($dir in $profiles_with_path) {
# to check
$test_current_pathPath = Test-Path -Path $dir
If ($test_current_pathPath) {
#write-host 'Currently writing for these months:'$($time.Name);
$files_to_delete += Get-ChildItem -Path $dir -recurse -Force | Where-Object {$_.PSIsContainer -eq $FALSE} | % { $_.FullName }
}
}
To delete files:
If ($files_to_delete) {
ForEach ($file in $files_to_delete) {
#Remove-Item $file -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item $file -Force -ErrorAction SilentlyContinue
If ($? -eq $true) {
$files_deleted ++;
#Write-Verbose -Verbose "$File deleted successfully!"
}
}
and
all the directories
ForEach ($dir in $profiles_with_path) { #
Remove-Item $dir -Recurse -Force -ErrorAction SilentlyContinue
If ($? -eq $true) {
$directories_deleted ++;
#Write-Verbose -Verbose "$File deleted successfully!"
}
}
These snippets work for 2.0 (tested on WinXP and Windows 2003 (SPx) and 4.0 Win7 tested.
First EDIT:
I tried to pick the valid codes for you, but apparently I could do better job. The logic was the following: I wanted to delete all profiles that did not contain any files newer than 3 months.
The variable $newer_file_exist
- was used to indicate if such file was found. If it was found
the whole profile was skipped - added to $excluded_directories.Add($profile)
(for more see the source code link)
$profiles_with_path
was populated by - $profiles_with_path = Get-ChildItem -Path $folder_to_cleanse -exclude $excluded_directories | Where-Object {$_.PSIsContainer -eq $True}
where I have excluded all directories from $excluded_directories
This is my script which I have made public on my BB: The whole source code on my BB (it includes logic for test run, time specification, etc.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With