Remove-Item not deleting files - windows

This is my PowerShell script:
$dir = ([io.fileinfo]$MyInvocation.MyCommand.Definition).DirectoryName
Get-ChildItem -Path .\ -Filter *.png -Recurse -File | Where-Object {$_.Name -match ".+[\]]+.png"} | ForEach-Object {
echo $_.FullName $(Test-Path $_.FullName)
Remove-Item $_
echo $_.FullName $(Test-Path $_.FullName)
}
The echos give actual filenames, but Test-Path resolves to False and nothing is ever deleted.

Because your paths contain ] which is interpreted by the -Path parameter (which you're using implicitly) as part of a pattern.
You should use the -LiteralPath parameter instead:
$dir = ([io.fileinfo]$MyInvocation.MyCommand.Definition).DirectoryName
Get-ChildItem -Path .\ -Filter *.png -Recurse -File | Where-Object {$_.Name -match ".+[\]]+.png"} | ForEach-Object {
echo $_.FullName $(Test-Path -LiteralPath $_.FullName)
Remove-Item -LiteralPath $_
echo $_.FullName $(Test-Path -LiteralPath $_.FullName)
}
Note that if you instead piped in the original object from Get-ChildItem, it would automatically bind to -LiteralPath so that's something to consider:
$dir = ([io.fileinfo]$MyInvocation.MyCommand.Definition).DirectoryName
Get-ChildItem -Path .\ -Filter *.png -Recurse -File | Where-Object {$_.Name -match ".+[\]]+.png"} | ForEach-Object {
echo $_.FullName $($_ | Test-Path)
$_ | Remove-Item
echo $_.FullName $($_ | Test-Path)
}
To prove this:
$dir = ([io.fileinfo]$MyInvocation.MyCommand.Definition).DirectoryName
$fileSample = Get-ChildItem -Path .\ -Filter *.png -Recurse -File |
Where-Object {$_.Name -match ".+[\]]+.png"} |
Select-Object -First 1
Trace-Command -Name ParameterBinding -Expression {
$fileSample.FullName | Test-Path
} -PSHost # $fileSample.FullName is a string, still binds to Path
Trace-Command -Name ParameterBinding -Expression {
$fileSample | Test-Path
} -PSHost # binds to LiteralPath

Related

I can't access Simbolic Links remotely

I have created the following powershell script that copies the files from the source folder and moves them to the destination folder, and instead of these moved files it creates symbolic links for these files.
I have given all possible sharing permissions and locally it works perfectly and I can open these files but when I try to do it remotely it doesn't open the files, I can see them but they don't open.
> $sourceDir = "C:\sorce"
> $destinationDir = "D:\Destiny"
> $logfile = "C:\Temp\log.txt"
> Copy folder structure to destination
> Get-ChildItem -Path $sourceDir -Recurse |
> ?{ $_.PSIsContainer } |
> Copy-Item -Destination {Join-Path $destinationDir $_.Parent.FullName.Substring($sourceDir.length)} -Force -ErrorAction Continue
>
> Move files and folders to destination
> `$items = Get-ChildItem $sourceDir -Recurse
> foreach ($item in $items)
> {
> $filename = Split-Path -Path $item.FullName -Leaf
> $sourcepath = Split-Path -Path $item.FullName
> $destination = ($item.FullName -replace [regex]::Escape($sourceDir), $destinationDir)
> Move-Item -Force -Path $item.FullName -Destination $destination -Verbose -ErrorVariable err -ErrorAction Continue *>> $logfile
> $err >> $logfile
>
> Create symbolic link in original location
> New-Item -ItemType SymbolicLink -Path $sourcepath -Name $filename -Value $destination -Force -Verbose -ErrorVariable err -ErrorAction Continue *>> $logfile
> $err >> $logFile
> }
Open the files remotely

PowerShell - Print Move-Item in Console

I have the following code:
$SchoolFolder = "C:\Users\MyUser\Desktop\School Folder\$StudentName\$Month. $MonthWrite\$Day. $DayWrite"
$MP4Lenght = (Get-ChildItem -Path $RenderFolder).Length -ne "0"
$MP4existsToCopy = Test-Path -Path "$RenderFolder\*.mp4"
If (($MP4existsToCopy -eq $True) -and ($MP4Lenght -eq $True)) {
Get-ChildItem $MyFolder |
Where-Object { $_.Length -gt 0KB} |
Move-Item -Destination (new-item -type directory -force ($SchoolFolder + $newSub)) -force -ea 0
Write-Host "Done!"
}
I would like to know how do I make all correspondence in $MP4Lenght be printed in the console with the format $MP4Lenght + "was moved", because that way I can know which files were moved.
Your "exist to copy" logic isn't really required, because if the file doesn't exist then get-childitem is not going to find it. Similarly with the check if MP4lenght is true.
The following will check if the file does not exist in the source and does exist in the destination and if that is true then write to the host that the file has moved:
$source = 'C:\Users\myuser\playground\powershell\Source\'
$destination = 'C:\Users\myuser\playground\powershell\Destination'
$files = Get-ChildItem $source -File | where-object {$_.Length -ne 0}
foreach ($file in $files) {
Move-Item $file.FullName -Destination .\Destination
if (-not(Test-Path $file.FullName) -and (test-path (Join-Path -Path $destination -ChildPath $file.Name))) {
Write-Host "$($file.name) has moved"
}
}
Why not just use -verbose?
Move-Item -Destination (new-item -type directory -force ($SchoolFolder + $newSub)) -force -ea 0 -Verbose
Update as per your comment.
Try it this way...
$source = 'C:\Users\myuser\playground\powershell\Source\'
$destination = 'C:\Users\myuser\playground\powershell\Destination'
Get-ChildItem $source -File |
where-object {$PSItem.Length -ne 0} |
ForEach-Object{
Move-Item $PSItem.FullName -Destination '.\Destination'
if (-not(Test-Path $PSItem.FullName) -and (test-path (Join-Path -Path $destination -ChildPath $PSItem.Name))) {
"$($PSItem.name) has moved"
}
}
Final script:
$StudentName = Tyler
$RenderFolder = "C:\Users\MyUser\Desktop\Render"
$MP4existsToCopy = Get-ChildItem $RenderFolder -File | where-object {$_.Length -ne 0}
$SchoolFolder = "C:\Users\MyUser\Desktop\School Folder\$StudentName\$Month. $MonthWrite\$Day. $DayWrite"
foreach ($file in $MP4existsToCopy) {
Move-Item $file.FullName -Destination (new-item -type directory -force ($SchoolFolder)) # new-item - Serves to create the folder if it does not exist
if (-not(Test-Path $file.FullName) -and (test-path (Join-Path -Path $SchoolFolder -ChildPath $file.Name))) {
Write-Host "$($file.name) was moved!"
}

Compress and Delete multiple folders one by one

Ho Guys,
I was trying a powershell script which can compress and delete the subfolders with folder name of 8 numbers.
The script is working fine. But the problem is the script works like, first the whole compression process gets done and then goes for the whole deletion. So that if am running this script through 1tb folder...During the compression process it goes upto 1.5tb . To overcome this, how can I change the script so that the script should compress and delete one folder and moves to next folder compress and delete and so on.
Here is what I tried.
$path = Read-host "Enter the desired path"
$directory = "$path"
Add-Type -AssemblyName System.IO.Compression.FileSystem
$folders = Get-ChildItem $directory -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name.Length -ge "8" -and $_.Name -match '^\d+$'} | Select-Object -ExpandProperty FullName
foreach ($folder in $folders) {
Write-Verbose "Archiving $archive"
$archive = $folder + '.zip'
[System.IO.Compression.ZipFile]::CreateFromDirectory($folder, $archive, 'Optimal', $True) | wait-process
}
Foreach-Object {
Remove-Item -Path $folders -Force -Recurse -Confirm:$false -Verbose
}
What about this?
$path = Read-host "Enter the desired path"
$directory = "$path"
Add-Type -AssemblyName System.IO.Compression.FileSystem
$folders = Get-ChildItem $directory -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name.Length -ge "8" -and $_.Name -match '^\d+$'} | Select-Object -ExpandProperty FullName
foreach ($folder in $folders) {
Write-Verbose "Archiving $archive"
$archive = $folder + '.zip'
[System.IO.Compression.ZipFile]::CreateFromDirectory($folder, $archive, 'Optimal', $True)
Remove-Item $folder -recurse -force
}

Copying files and it's subfolders

I'm trying to copy to another directory but it's copying over there all the way (C: \ users ...), and I don't want that. I just want to copy the current folder and its subdirectories. I also want to leave a symbolic link when the file is moved. I got this script here on the site, it's a great script! Thank you all for your attention The script is this:
$sourceDir = "C:\Users\295078898\Documents\Teste"
$archiveTarget = "C:\Users\295078898\Downloads\Teste"
$dateToday = Get-Date
$date = $dateToday.AddDays(-20)
$items = Get-ChildItem $sourceDir -recurse |
Where-Object {!$_.PSIsContainer -and $_.LastWriteTime -le $date}
foreach ($item in $items) {
$withoutRoot = $item.FullName.Substring([System.IO.Path]::GetPathRoot($item.FullName).Length);
$destination = Join-Path -Path $archiveTarget -ChildPath $withoutRoot
$dir = Split-Path $destination
if (!(Test-Path $dir)) {
mkdir $dir
}
Move-Item -Path $item.FullName -Destination $destination
function CreateLink {
param (
[string] $LinkName,
[string] $TargetFile
)
&"cmd.exe" /c mklink "$LinkName" "$TargetFile" | Out-Null
}
CreateLink -LinkName $item.FullName -TargetFile $destination
}
Try something like this:
$sourceDir = [string]"C:\TMP\295078898\Teste"
$archiveTarget = [string]"C:\Temp\295078898\Teste"
$dateToday = Get-Date
$date = $dateToday.AddDays(-20)
$items = Get-ChildItem $sourceDir -recurse |
Where-Object {!$_.PSIsContainer -and $_.LastWriteTime -le $date}
foreach ($item in $items) {
Move-Item -Path $item.FullName -Destination $archiveTarget
New-Item -ItemType SymbolicLink -Target $archiveTarget -Path $item.FullName -Force
}

How to run script for each element in pipe?

Get-ChildItem -recurse | Where {!$_.PSIsContainer -and `
$_.LastWriteTime -lt (get-date).AddDays(-31)} | Remove-Item -whatif
Get-ChildItem -recurse | Where {$_.PSIsContainer -and `
#(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0} |
Remove-Item -recurse -whatif
the above Script can work properly, now I want to combine it with the fllowing script into one script:
$path = "<path to file>"
$shell = new-object -comobject "Shell.Application"
$item = $shell.Namespace(0).ParseName("$path")
$item.InvokeVerb("delete")
Here is my combined Script:
Get-ChildItem -recurse | Where {$_.PSIsContainer -and `
#(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0} |
$path = $_.Fullname
$shell = new-object -comobject "Shell.Application"
$item = $shell.Namespace(0).ParseName("$path")
$item.InvokeVerb("delete") -recurse -whatif
but, I always get the error message:
Expressions are only allowed as the first element of a pipeline.
At line:3 char:7
You must provide a value expression on the right-hand side of the '-' operator.
At line:6 char:28
Unexpected token 'recurse' in expression or statement.
At line:6 char:29
Unexpected token '-whatif' in expression or statement.
At line:6 char:37
anyone can help me?
You need to use the Foreach-Object cmdlet (alias is foreach) in the last part of your pipeline. Also, you don't want to create the Shell.Application object each time in your pipeline:
$shell = new-object -comobject "Shell.Application"
Get-ChildItem -recurse |
Where {$_.PSIsContainer -and `
#(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0} |
Foreach {
$item = $shell.Namespace(0).ParseName(($_.Fullname))
$item.InvokeVerb("delete")
}
That said, I'm not sure why you just don't use the Remove-Item cmdlet e.g.:
Get-ChildItem . -r | Where {$_.PSIsContainer -and !$(Get-ChildItem $_.fullname)} |
Remove-Item -WhatIf
To make this a script, just put the above command in a .ps1 file like so:
-- Contents of DeleteEmptyDirs.ps1 --
param([string]$path, [switch]$whatif)
Get-ChildItem $path -r | Where {$_.PSIsContainer -and !$(Get-ChildItem $_.fullname)} |
Remove-Item -WhatIf:$whatif
Then invoke like so:
PS> .\DeleteEmptyDirs c:\temp -WhatIf
PS> .\DeleteEmptyDirs c:\temp

Resources