I'm trying to log data surrounding the renaming of files using the following script. The only problem is that the log file contains files that were not renamed due to 'access denied' errors when attempting to rename. I need to figure out how to only create log entries for files that were SUCCESSFULLY renamed or pipe the failed renames to a different log file. I'd also like the total number of files renamed listed at the top of the log file if at all possible(ie 'xxx files were renamed') I appreciate any suggestions for getting this to work using powershell v2.
$drivesArray = Get-PSDrive -PSProvider 'FileSystem' | select -Expand Root
foreach ($drive in $drivesArray) {
Get-ChildItem $drive | Where-Object {
$_.FullName -notlike "${Env:WinDir}*" -and
$_.FullName -notlike "${Env:ProgramFiles}*"
} | ForEach-Object {
Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue
} | Where-Object {
-not $_.PSIsContainer -and
$_.Extension -notmatch '^\.(xxx|exe|html)$'
} | ForEach-Object {
$newName = $_.FullName + '.xxx';
Rename-Item -Path $_.FullName -NewName ($_.FullName + '.xxx') -ErrorAction SilentlyContinue
Add-Content c:\temp\renameLog.txt -Value $('{0} {1} {2} {3}' -f $(Get-Date),$_.fullname,$_.name,$newName )
}
}
Here is an example, untested of course.
$success = 0
$failed = 0
$drivesArray = Get-PSDrive -PSProvider 'FileSystem' | select -Expand Root
foreach ($drive in $drivesArray) {
Get-ChildItem $drive | Where-Object {
$_.FullName -notlike "${Env:WinDir}*" -and
$_.FullName -notlike "${Env:ProgramFiles}*"
} | ForEach-Object {
Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue
} | Where-Object {
-not $_.PSIsContainer -and $_.Extension -notmatch '^\.(xxx|exe|html)$' -and $_.Name -notmatch '^renameLog.txt|^renameLog_failed.txt'
} | ForEach-Object {
try {
$newName = $_.FullName + '.xxx';
Rename-Item -Path $_.FullName -NewName ($_.FullName + '.xxx') -ErrorAction Stop
Add-Content c:\temp\renameLog.txt -Value $('{0} {1} {2} {3}' -f $(Get-Date),$_.fullname,$_.name,$newName )
$success ++
} catch [exception] {
Add-Content c:\temp\renameLog_failed.txt -Value $('{0} {1} {2} {3}' -f $(Get-Date),$_.fullname,$_.name,$newName )
$failed ++
$error.Clear()
}
}
}
Add-Content "c:\temp\renameLog.txt" -Value $("Total: " + $success)
Add-Content "c:\temp\renameLog_failed.txt" -Value $("Total: " + $failed)
Related
I have this comand
Get-ChildItem -path Z:\htdocs\zz | where { $_.Length -eq 2254 } | ?{Remove-Item $_.fullname}
I would like it to also return the amount of files deleted/removed so I can compare it with a variable (like N).
try this:
Get-ChildItem -path "c:\temp" -file | where Length -eq 2254 | %{
try
{
Remove-Item $_.FullName
$CountDeleted++
}
catch
{
$CountNotDeleted++
}
}
"Result : {0} file(s) deleted, {1} file(s) cant removed" -f $CountDeleted, $CountNotDeleted
This is an example when you don't need a oneliner:
$Files = Get-ChildItem -Path "Z:\htdocs\zz" | Where-Object { $_.Length -eq 2254 }
Remove-Item -Path $Files.Fullname
Write-Host "Deleted $($Files.Count) files"
I want this to recurse every directory and create a zero-byte file for every file using the same name as the file with the extension .xxx added. I was thinking New-Item would be good to use here but I cant seem to get it working right.
Here is what I've tried with no success in PS version 2:
$drivesArray = Get-PSDrive -PSProvider 'FileSystem' | select -Expand Root
foreach ($drive in $drivesArray) {
ls "$drive" | where {
$_.FullName -notlike "${Env:WinDir}*" -and
$_.FullName -notlike "${Env:ProgramFiles}*"
} | ls -ErrorAction SilentlyContinue -recurse | where {
-not $_.PSIsContainer -and
$_.Extension -notmatch '\.xxx|\.exe|\.html'
} | New-Item -Path { $_.BaseName } -Name ($_.FullName+".xxx") -Type File -Force
}
This errors out with
A positional parameter cannot be found that accepts argument "+xxx".
You need to wrap both the second Get-ChildItem (ls) and the New-Item in ForEach-Object statements. Also, do not pass $_.Basename as the path to New-Item. Do it either like this:
New-Item -Path ($_.FullName + '.xxx') -Type File -Force
or like this:
New-Item -Path $_.Directory -Name ($_.Name + '.xxx') -Type File -Force
Modified code:
foreach ($drive in $drivesArray) {
Get-ChildItem $drive | Where-Object {
$_.FullName -notlike "${Env:WinDir}*" -and
$_.FullName -notlike "${Env:ProgramFiles}*"
} | ForEach-Object {
Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue
} | Where-Object {
-not $_.PSIsContainer -and
$_.Extension -notmatch '^\.(xxx|exe|html)$'
} | ForEach-Object {
New-Item -Path ($_.FullName + '.xxx') -Type File -Force
}
}
I need create this list to allow an other program to properly work. I use this code:
function analyse {
Param(
[parameter(Mandatory=$true)]
[String]$newPath
)
cd $newPath
dir | Foreach-Object {
$data = Get-Content -Path o:\******\public\ParcoursArborescence\Limitless\data.txt
if ($_.PsisContainer -eq $True) {
$testPath = $_.FullName + ";"
$name = $testPath
$testPath = $data -match [regex]::escape($testPath)
$testpath
if($testPath.Length -eq 0) {
$name | Out-File -Append "o:\******\public\ParcoursArborescence\Limitless\data.txt"
if ($_.FullName.Length -gt 248) {
"ecriture"
$result += $_.FullName + "`r"
} else {
"nouvelle analyse"
$_.Fullname
analyse $_.FullName
}
}
} else {
$testPath = $_.Directory.FullName + ";"
$name = $testPath
$testPath = $data -match [regex]::escape($testPath)
if($testPath.Length -eq 0) {
$name | Out-File -Append "o:\******\public\ParcoursArborescence\Limitless\data.txt"
$_.FullName.Length
if ($_.FullName.Length -gt 260) {
"ecriture2"
$result += $_.Directory.Name + "`r"
}
}
}
}
$result | Out-File -Append "o:\******\public\ParcoursArborescence\Limitless\bilanLimitless.txt"
}
But it takes hours and hours... I need to use this in thousands of folders. So, do you have any idea about how could it get faster ?
Maybe I'm oversimplifying things here, but why not list all the files at once, and test their FullName Length (PS 3.0 needed for the -File parameter of Get-ChildItem) ?
$maxLength = 248
Get-ChildItem $newPath -Recurse |
Where-Object { ($_.FullName.Length -gt $maxLength) } |
Select-Object -ExpandProperty DirectoryName -Unique |
Out-File "overlength_paths.txt"
For PS 2.0:
$maxLength = 248
Get-ChildItem $newPath -Recurse -File |
Where-Object { ($_.FullName.Length -gt $maxLength) -and (-not $_.PSisContainer) } |
Select-Object -ExpandProperty DirectoryName -Unique |
Out-File "overlength_paths.txt"
I'm trying to delete all files (not folders) in %TEMP% which are older than 30 days. The problem is that some files are in use by a program so they can not be deleted. I tried to solve the problem as follow:
function IsFileLocked($filePath){
#write-host $filePath
Rename-Item $filePath $filePath -ErrorVariable errs -ErrorAction SilentlyContinue
$errs.Count
if ($errs.Count -ne 0)
{
return $true #File is locked
}
else
{
return $false #File is not locked
}
}
$Path= "$env:temp"
if ((Test-Path -Path $Path) -ieq $true)
{
$Daysback = '-30'
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
get-childitem $Path -recurse | Where-Object {$_.LastWriteTime -lt $DatetoDelete } |
Where-Object {$_.PSIsContainer -eq $False }| Where-Object {(IsFileLocked -filePath "($_)") -eq $false }# | remove-item -force #-WhatIf
}
The problem is that (IsFileLocked -filePath "($_)") -eq $false doesn't return any element.
Is it possible that get-childitem blocks the files, so that all of them are locked when I run get-childitem?
Any other ideas how to solve this problem?
How about just removing files older than 30 days and ignore the errors:
$old = (Get-Date).AddDays(-30)
Get-ChildItem $env:TEMP -Recurse |
Where-Object {!$_.PSIsContainer -and $_.LastWriteTime -lt $old } |
Remove-Item -Force -ErrorAction SilentlyContinue
I am trying to rename certain files and then copy them to a backup location as below:
gci $src `
| ?{!$_.psiscontainer -and $_.extension.length -eq 0 -and $_ -match "tmp_\d{1}$"} `
| %{ ren -path $_.fullname -new ($_.name + ".ext") } `
| %{ cpi -path $_.fullname -dest $bkup -force}
The renaming part is working fine. But the renamed files are not being copied over to the backup location. What I am doing wrong here?
Rename-Item doesn't return anything so there is nothing to pipe to Copy-Item. You could just put both commands in the for each block together:
gci $src `
| ?{!$_.psiscontainer -and $_.extension.length -eq 0 -and $_ -match "tmp_\d{1}$"} `
| %{ $renamedPath = $_.FullName + ".ext"; `
ren -path $_.FullName -new $renamedPath; `
cpi -path $renamedPath -dest $bkup -force }
By default renamed items will not be pushed back onto the pipeline, use the -PassThru switch to pass them on:
gci $src `
| ?{!$_.psiscontainer -and $_.extension.length -eq 0 -and $_ -match "tmp_\d{1}$"} `
| %{ ren -path $_.fullname -new ($_.name + ".ext") -PassThru } `
| %{ cpi -path $_.fullname -dest $bkup -force}
You accomplish both in one operation with move-item.
gci $src
| ?{!$_.psiscontainer -and $_.extension.length -eq 0 -and $_ -match "tmp_\d{1}$"}
| %{
$newname = $_.Name + ".ext"
move-item -path $_.FullName -dest "$bkup\$newname"
}
One liner:
gci $src | ?{!$_.psiscontainer -and !$_.extension -and $_ -match 'tmp_\d$'} | move-item -dest {"$bkup\$($_.Name + '.ext')"}