"Path cannot be found" Pester Test Results - powershell

Im testing out a script on Pester. I keep getting a Path cannot be found error.
Apparently something is wrong with some of my lines.
$userFolders = Get-ChildItem C:\Users -Directory
foreach($folder in $userFolders)
{
Get-ChildItem C:\Users\$folder\AppData\Local\Temp -Recurse | Remove-Item -Recurse -Force
Get-ChildItem C:\Users\$folder\AppData\Local\Google\Chrome\User Data\Default\Cache -Recurse | Remove-Item -Recurse -Force
}
Get-ChildItem C:\Windows\Temp -Recurse | Remove-Item -Recurse -Force
I can't seem to find what is wrong, but I know it is somewhere here.
Any help would be greatly appreciated.

$folder is an object. Casting to string will give you the folder name. You can do this by using quotes.
As Mark has identified, you would also need quotes if there a space in the path.
$userFolders = Get-ChildItem C:\Users -Directory
foreach($folder in $userFolders) {
Write-Host "This is the folder object:"
$folder
Write-Host "This is folder object cast to string: $folder"
Get-ChildItem "C:\Users\$folder\AppData\Local\Temp" -Recurse | Remove-Item -Recurse -Force
Get-ChildItem "C:\Users\$folder\AppData\Local\Google\Chrome\User Data\Default\Cache" -Recurse | Remove-Item -Recurse -Force
}
Get-ChildItem C:\Windows\Temp -Recurse | Remove-Item -Recurse -Force

One of your paths has a space in it so needs to wrapped in quotes:
Get-ChildItem "C:\Users\$folder\AppData\Local\Google\Chrome\User Data\Default\Cache" -Recurse | Remove-Item -Recurse -Force
It needs to be double quotes so that the $folder variable is still expanded.

The other answers have pointed out the main flaw in your script which is the lack of quotes. There is also some redundancy in two ways.
Repetition of Get-ChildItem <something> | Remove-Item <something>
Recursion on both sides of the pipe.
Consider the following:
function Get-TempFolderItem {
foreach ($Local in (Get-ChildItem -Path "C:\Users\*\AppData\Local")) {
'Temp','Google\Chrome\User Data\Default\Cache' |
ForEach-Object { Get-ChildItem -Path "$Local\$_" -Recurse }
}
}
Get-TempFolderItem | Remove-Item -Force
Here there is less repetition which simplifies debugging if you make a mistake. And if the getting of directory content is exhaustive, the removal shouldn't have to be.
Because you are saying that this is in the context of testing you should probably look into mocking for something like removal of files. With temp-files it doesn't matter much if you delete something you didn't intend to, but generally that is something you need to avoid when testing.
You can do this by writing
Mock Remove-Item {}
inside the Describe block.
Hope this answer is useful to you.

Probably not every user folder has a 'Google' sub-directory
C:\Users\$folder\AppData\Local\**Google**\...

Related

How to loop through all subfolders in a directory, and remove files with a specific filename

I am trying to write a script in Powershell to remove some files automatically with a certain file name.
My idea is to get all the folders in the directory, then loop through the subdirectory, and remove all items with the file name, but it doesn't seem to be working as expected.
Here is my script
$folders = Get-ChildItem -path "C:\Website-Backup" -Recurse | Where-Object {$_.PsIsContainer} |Group-Object {$_.FullName.Split('_')[0] }
$subfolders = Get-ChildItem -path $folders -Recurse | Where-Object {$_.PsIsContainer} | Group-Object {$_.FullName.Split('_')[0] }
ForEach($subfolder in $subfolders)
{
Remove-Item * -Include *100x*
}
Any idea why the script doesn't seem to be doing anything?
I think you can simplify your code if I understand correctly to:
Get-ChildItem "C:\Website-Backup" -Recurse -include "*100x*" -file | remove-item
The Group-Object command is likely what's confusing things here - Remove-Item is expecting a path - you're not referencing the subfolder variable in your loop as well, so this is the same as just running the Remove-Item command as many times as there are items in the array.
You can try this instead;
Get-ChildItem -Path "C:\Website-Backup" -Recurse | Where-Object -FilterScript { $_.name -like 'MyFile.txt' } | Remove-Item
This will pipe the returned child items into Where-Object, filter it to the specified file name, then pass that to Remove-Item as a file path.
You can also skip the Where-Object, but you lose a bit of control this way;
Get-ChildItem -Path 'C:\WebSiteBackup\*MyFile.txt' -Recurse | Remove-Item

I need to find a Folder on the Network Share

How can I find Folders called BlueMountain when this folder could be nested anywhere in my Users home folder
\\Server\Users\<personsname>\
Ultimately I want to delete the folder but just to be on the safe side. The BlueMountain folder must have one of these subfolder
Certs
Config
Macros
Scripts
Spool
Traces
Transfer
This is what I have so far
Get-ChildItem -Path \\Server\Users -Recurse -Directory -Filter $_.FOLDERNAME | ForEach-Object {
If $_.FullName --eq "BlueMountain" {
}
}
You can use -recurse to look for the last thing in your path recursively. So this:
Get-ChildItem \\server\Users\BlueMountain -recurse
Will look in all subfolders of "\server\Users" for anything named "BlueMountain". Then you just need to make sure it has one of your folders.
$SubFolders = 'Certs','Config','Macros','Scripts','Spool','Traces','Transfer'
Get-ChildItem \\server\Users\BlueMountain -recurse | Where{Get-ChildItem "$($_.FullName)\*" -Include $SubFolders}
That should list only the BlueMountain folders found recursively in \server\Users which contain one of the specified subfolders. Then you can just pipe that to Remove-Item -force and call it a day. Or if you want to track things pipe it to tee-object and then to remove-item.
try this :
$SubFolders = 'Certs','Config','Macros','Scripts','Spool','Traces','Transfer'
$wordtosearch="BlueMountain"
$SearchPattern= ($SubFolders | %{ "$wordtosearch\\$_" }) -join "|"
get-childitem "\\Server\Users" -directory -Recurse |
where FullName -match $SearchPattern |
Split-Path -path {$_.FullName} -Parent |
remove-item -Recurse -ErrorAction SilentlyContinue

Splatting with Move-Item gives an error

Ok, so the script itself is over 500 lines long, so I'll refrain from posting the entire thing. However, I have narrowed down the issue to a single line.
If I use the below line of code, everything works as expected.
Move-Item -Path $path -Include *.txt,*.doc,*.pdf -Destination $dest -Force
But when I change it to use splatting, it gives me an error
$downloadDir = "G:\Downloads"
$dest = "G:\Test\"
$editList = Get-ChildItem -LiteralPath "$downloadDir" -include "[" -File | ForEach-Object -Process {Rename-item -LiteralPath $_.FullName -NewName ($_.Name -replace "[][]"," ") -ErrorAction SilentlyContinue}
$mainList = Get-ChildItem -Path "$downloadDir" -File | Select-Object Name
ForEach ($list in $mainList) {
$item = $list.Name
$path = "$downloadDir\*"
$opts = #{
Path = $path;
Include = '*.txt,*.doc,*.pdf';
Force = $true;
Destination = $dest
}
Move-Item #opts
}
Move-Item : Cannot move item because the item at 'G:\Downloads\test.txt' does not exist.
I feel like I am probably missing something very basic, but I don't know enough about hash tables/splatting yet, to spot the mistake.
Any ideas?
EDIT:
Just to clarify, G:\Downloads\test.txt comes from $path which is generated from a Get-ChildItem.
I am literally doing a straight swap of the 2 versions of code(Splatting/Non-splatting).
EDIT 2:
Added all the parts of the script relevant to that Move-Item
EDIT 3:
Got this working by using double quotes for the "Include" line:
Include = "*.txt","*.doc","*.pdf";
Change your Include from:
Include = '*.txt,*.doc,*.pdf';
to
Include = "*.txt","*.doc","*.pdf";
The Path statement can be tricky as well.
For example
get-childitem c:\temp -include *.txt
will not work, while
get-childitem c:\temp\* -include *.txt
will work, if you have any .txt files in c:\temp
It's stupid, but that's how it is with some of these cmdlets.

Delete all files and folders but exclude a subfolder

I have a folder where I need to delete all files and folders except a small list of files and folders.
I can already exclude a list of files, but don't see a way to exclude a folder and its contents.
Here is the folder structure:
|-C:\temp
\-C:\temp\somefile.txt
\-C:\temp\someotherfile.txt
| |-C:\temp\foldertodelete
\-C:\temp\foldertodelete\file1.txt
| |-C:\temp\foldertokeep
| \-C:\temp\foldertokeep\file2.txt
I want to keep somefile.txt and the folder foldertokeep and its content.
This is what I have right now:
Get-ChildItem -Path 'C:\temp' -Recurse -exclude somefile.txt | Remove-Item -force -recurse
This really does not delete somefile.txt. Is there a way to exclude folder foldertokeep and its content from the delete list?
Get-ChildItem -Path 'C:\temp' -Recurse -exclude somefile.txt |
Select -ExpandProperty FullName |
Where {$_ -notlike 'C:\temp\foldertokeep*'} |
sort length -Descending |
Remove-Item -force
The -recurse switch does not work properly on Remove-Item (it will try to delete folders before all the child items in the folder have been deleted). Sorting the fullnames in descending order by length insures than no folder is deleted before all the child items in the folder have been deleted.
In PowerShell 3.0 and below, you can try simply doing this:
Remove-Item -recurse c:\temp\* -exclude somefile.txt,foldertokeep
Unless there's some parameter I'm missing, this seems to be doing the trick...
Edit: see comments below, the behavior of Remove-Item has changed after PS3, this solution doesn't seem applicable anymore.
Select everything excluding what needs to be keep and pipe that to a delete command.
Say you have those folders
C:.
├───delme1
│ │ delme.txt
│ │
│ └───delmetoo
├───delme2
├───keepme1
│ keepmetoo.txt
│
└───keepme2
To delete everything but preserve the keepme1 and keepme2 folders.
Get-ChildItem -Exclude keepme1,keepme2 | Remove-Item -Recurse -Force
Other solutions are fine but I found this easy to understand and to remember.
I used the below and just removed -Recurse from the 1st line and it leaves all file and sub folders under the exclude folder list.
Get-ChildItem -Path "PATH_GOES_HERE" -Exclude "Folder1", "Folder2", "READ ME.txt" | foreach ($_) {
"CLEANING :" + $_.fullname
Remove-Item $_.fullname -Force -Recurse
"CLEANED... :" + $_.fullname
}
Yes I know this is an old thread. I couldn't get any of the answers above to work in Powershell 5, so here is what I figured out:
Get-ChildItem -Path $dir -Exclude 'name_to_ignore' |
ForEach-Object {Remove-Item $_ -Recurse }
This moves the -Recurse to Remove-Item instead of where the items are found.
According to MSDN Remove-Item has a known issue with the -exclude param. Use this variant instead.
Get-ChildItem * -exclude folderToExclude | Remove-Item
I ran into this and found a one line command that works for me. It will delete all the folders and files on the directory in question, while retaining anything on the "excluded" list. It also is silent so it won't return an error if some files are read-only or in-use.
#powershell Remove-item C:\Random\Directory\* -exclude "MySpecialFolder", "MySecondSpecialFolder" -force -erroraction 'silentlycontinue'
This would also help someone...
Adding a variable for PATH_GOES_HERE that is empty or isn't defined prior can cause a recursive deletion in the user directory (or C:\windows\system32 if the script is ran as admin). I found this out the hard way and had to re-install windows.
Try it yourself! (below will only output the file directories into a test.txt)
Get-ChildItem -Path $dir2 -Recurse -Exclude "Folder1 ", FileName.txt | foreach ($_) {
$_.fullname >> C:\temp\test.txt
}
I used this, that works perfectly for me
Get-ChildItem -Path 'C:\Temp\*' -Recurse | Where-Object {($_.FullName -notlike "*windirstat*") -and ($_.FullName -notlike "C:\Temp\GetFolderSizePortable*")} | Remove-Item -Recurse
If your paths include regex special characters then you need to use the -LiteralPath option which does not allow piping. The correct solution in that case looks like this:
Remove-Item -force -LiteralPath(
Get-ChildItem -Path 'C:\temp' -Recurse -exclude somefile.txt |
Select-Object -ExpandProperty FullName |
Where-Object { $_ -notlike 'C:\temp\foldertokeep*' } |
Sort-Object length -Descending
)
This would also help someone...
Get-ChildItem -Path PATH_GOES_HERE -Recurse -Exclude "Folder1 ", "Folder2", FileName.txt | foreach ($_) {
"CLEANING :" + $_.fullname
Remove-Item $_.fullname -Force -Recurse
"CLEANED... :" + $_.fullname
}
I want get contribution for this idea
delete all folder and files include hidden folder
$get-childitem -Path D:\path\folder\to\delete* -Force |select-object -Expandproperty Fullname |remove-item -recurse -Confirm:$false -Force
delete all folder and file include hidden folder but retain exclude folder
$get-childitem -Path D:\path\folder\to\delete* -Exclude nameexludefolder -Force | select-object -Expandproperty Fullname | remove-item -Force
$get-childitem -Path D:\path\folder\to\delete\ -Exclude nameexludefolder -Force | select-object -Expandproperty Fullname | remove-item -Force
first line remain folders,
2nd line remove remain folder

Get-ChildItem results looks like relative paths in Powershell

I would like to scan and move folders (and sub folders or even deeper) from one folder to another using Powershell.
Currently I'm using this pipe of commands.
Get-ChildItem -recurse -path sub\WORK -filter "* OK" | Where-Object { $_.PSIsContainer } | foreach { Move-Item -path $_ -destination sub\OK }
Unfortunately it doesn't work because the found results are relative to .\sub\WORK, when trying to move them Move-Item complains that the folders are not in the current folder:
Move-Item : Cannot find path 'C:\TMP\2011-12-12 test 2 OK' because it does not exist.
I expect that $_ would contain: 'C:\TMP\sub\WORK\2011-12-12 test 2 OK' because these are objects in Powershell and no strings like in Linux.
In case you use Get-ChildItem, be very careful. The best way is to pipe the objects to Move-Item and you don't need to think about it more:
Get-ChildItem -recurse -path sub\WORK -filter "* OK" | Where-Object { $_.PSIsContainer } | Move-Item -destination sub\OK
(no need to use Foreach-Object)
The main reason why I'm answering is this one: Get-ChildItem constructs object differently, depending on the parameters. Look at examples:
PS C:\prgs\tools\Console2> gci -include * | % { "$_" } | select -fir 5
C:\prgs\tools\Console2\-verbose
C:\prgs\tools\Console2\1UpdateDataRepositoryServices.ps1
C:\prgs\tools\Console2\22-52-59.10o52l
C:\prgs\tools\Console2\2jvcelis.ps1
C:\prgs\tools\Console2\a
PS C:\prgs\tools\Console2> gci | % { "$_" } | select -fir 5
-verbose
1UpdateDataRepositoryServices.ps1
22-52-59.10o52l
2jvcelis.ps1
a
Then if you use $_ in a cycle and PowerShell needs to convert FileInfo from Get-ChildItem to string, it gives different results. That happened when you used $_ as argument for Move-Item. Quite bad.
I think there is a bug that reports this behaviour.
You are correct that objects are being piped down the pipeline instead of strings. This is good in that it is more flexible. The drawback is that if you don't explicitly tell the system which property of the object to use you are at the mercy of the system designers. See if explicitly telling the system the property that you want will help:
Get-ChildItem -recurse -path sub\WORK -filter "* OK" | Where-Object { $_.PSIsContainer } | foreach { Move-Item -path $_.Fullname -destination sub\OK }
I just learn't that the PSPath is automatically used in Copy-Item, Move-Item etc. when you don't specify the source in a pipeline, so something like:
gci .\sub\Work | move-item -Destination .\sub\OK
(simplified example)
would work and it would use the PSPath of the passed object to determine the source.
Since the Get-ChildItem returns objects like you said, you can use Get-Member to see what the object has to offer ( that is know about its properties and methods)
Get-ChileItem path | Get-Member
You could see that FullName is one of the properties that you could use.
Here is what worked for me.
Get-ChildItem -Path .\ -Recurse -filter "* OK" | %{Join-Path -Path $_.Directory -ChildPath $_.Name } | Move-Item -Destination sub\OK