Formatting the verbose output of a Remove-Item command - powershell

I have the following command:
Get-ChildItem $build_path `
-Include *.bak, *.orig, *.txt, *.chirp.config `
-Recurse | Remove-Item -Verbose
to clear some files from the build folder of a VS solution. I use the Verbose switch so that I can see which files are being deleted. It works fine but the output is too verbose:
VERBOSE: Performing operation "Remove File" on Target "R:\Visual Studio 2010\Projects\SomeProject\SomeProject.Web.build\App_Readme\glimpse.mvc3.readme.txt".
VERBOSE: Performing operation "Remove File" on Target "R:\Visual Studio 2010\Projects\SomeProject\SomeProject.Web.build\App_Readme\glimpse.readme.txt".
I just need to see something like that:
Removing file \App_Readme\glimpse.mvc3.readme.txt".
Removing file \App_Readme\glimpse.readme.txt".
...
I know i can do this with a foreach statement and a Write-Host command, but I believe it can be done with some pipelining or something. Any ideas?

Using ForEach-Object is pretty straightforward:
Get-ChildItem $build_path `
-Include *.bak, *.orig, *.txt, *.chirp.config `
-Recurse | foreach{ "Removing file $($_.FullName)"; Remove-Item $_}
As #user978511 pointed out, using the verbose output is more complicated:
$ps = [PowerShell]::Create()
$null = $ps.AddScript(#'
Get-ChildItem $build_path `
-Include *.bak, *.orig, *.txt, *.chirp.config `
-Recurse | Remove-Item -Verbose
'#)
$ps.Invoke()
$ps.Streams.Verbose -replace '(.*)Target "(.*)"(.*)','Removing File $2'

In PowerShell 3.0 you can write the Verbose stream to the output stream (e.g 4>&1) and then replace the message:
Get-ChildItem $build_path `
-Include *.bak, *.orig, *.txt, *.chirp.config `
-Recurse | Remove-Item -Verbose 4>&1 | Foreach-Object{ `
Write-Host ($_.Message -replace'(.*)Target "(.*)"(.*)','Removing File $2') -ForegroundColor Yellow
}

This is a few years too late but it might help someone else who stumbles upon this like I did so I'll provide it anyway.
I would try the file deletion and then report on success or failure. See below:
$FileList = $build_path `
-Include *.bak, *.orig, *.txt, *.chirp.config `
-Recurse
foreach ($File in $FileList)
{
Try
{
Remove-Item $File.FullName -Force -ErrorAction Stop
Write-Output "Deleted: $($File.Parent)\$($File.Name)"
}
Catch
{
Write-Output "Error deleting: $($File.Parent)\$($File.Name); Error Message: $($_.Exception.Message)"
}
}
If you wanted to both output to console and log to a file you can use Tee-Object at the end of each line starting with Write-Output above.
| Tee-Object -FilePath $your_log_file -Append

To be able to modify the message you need first to cath the output that is not that easy. You can refer to answer on this page:
Powershell Invoke-Sqlcmd capture verbose output
to catch the output. From there on you can modify the message and show it in your format, but foreach options looks easier to me

Related

Powershell exclude pdf extension files

I am trying to run powershell script to separate files of all extensions by iterating all the subfolders and creating a subfolder attachments at depth 3 except pdf but it is not working. Can someone help me out by pointing what I am doing incorrectly in script.
Thanks in advance
ForEach($Folder in (Get-ChildItem -Directory .\*\*\*)){
echo "Done"
Get-ChildItem -path $Folder -Exclude *.pdf | Move-Item -Destination $Folder\Attachments -ErrorAction Stop
}
I'd suggest adding the -WhatIf parameter to Move-Item to troubleshoot what that command is actually trying to do. It will probably be quite clear from the output that it's not doing what you think it's doing.
My guess is the problem is the fact that $Folder contains a DirectoryInfo item. The default string expansion for that is just the name, and you probably want the FullName.
Try:
ForEach($Folder in (Get-ChildItem -Directory .\*\*\*)){
echo "Done"
Get-ChildItem -path $Folder -Exclude *.pdf | Move-Item -Destination "$($Folder.FullName)\Attachments" -ErrorAction Stop
}
However, it's not clear from your question what you're actually trying to accomplish, primarily because "it doesn't work" is not a problem description. I'm not sure where the attachments folder is supposed to be.
Extending from my comment. Try something like this.
'PowerShell -Whatif or Confirm'
$Destination = 'D:\temp'
(Get-ChildItem -Directory -Recurse -Exclude '*.pdf' -Depth 3) |
ForEach-Object {
Write-Verbose -Message "Processing: $PSItem" -Verbose
# Remove the whatIf after you validate the results of the move and run it again.
Try {Move-Item -Path $PSItem.FullName -Destination "$Destination\Attachments" -ErrorAction Stop -WhatIf}
Catch
{
Write-Warning -Message "Error processing request"
$PSItem.Exception.Message
}
}
# Results
<#
VERBOSE: Processing: D:\Scripts\.vs
What if: Performing the operation "Move Directory" on target "Item: D:\Scripts\.vs Destination: D:\temp\Attachments".
VERBOSE: Processing: D:\Scripts\.vs\Scripts
What if: Performing the operation "Move Directory" on target "Item: D:\Scripts\.vs\Scripts Destination: D:\temp\Attachments".
VERBOSE: Processing: D:\Scripts\.vs\Scripts\v16
What if: Performing the operation "Move Directory" on target "Item: D:\Scripts\.vs\Scripts\v16 Destination: D:\temp\Attachments".
...
#>
If you want to see what is happening under the covers as part of your check, you can do this.
Trace-Command
# Review what the command expression is doing
Trace-Command -Name metadata,parameterbinding,cmdlet -Expression {
$Destination = 'D:\temp'
(Get-ChildItem -Directory -Recurse -Exclude '*.pdf' -Depth 3) |
ForEach-Object {
Write-Verbose -Message "Processing: $PSItem" -Verbose
# Remove the whatIf after you validate the results of the move and run it again.
Try {Move-Item -Path $PSItem.FullName -Destination "$Destination\Attachments" -ErrorAction Stop -WhatIf}
Catch
{
Write-Warning -Message "Error processing request"
$PSItem.Exception.Message
}
}
} -PSHost

Powershell Remove-Item get Loggingfile

i have probably searched the whole web, but I'm not able to help myself. Otherwise I'm just incapable.
All I want is to delete folders after 30 days and display the results in a simple .log file.
dir "C:\Users\sam\Desktop\Files_todelete\*" -ErrorAction SilentlyContinue | Where { ((Get-Date) - $_.LastWriteTime).days -gt 30 } | Remove-Item -Recurse
This works for me, but I tried nearly everything to log the results.
Hopefully you can help me to fix this issue.
You need to include logging part to your script. You can make foreach loop for every item that needs to be removed and write down activity to log file. Here is an example:
$LogFile = 'C:\log.txt'
dir "C:\Users\sam\Desktop\Files_todelete\*" -ErrorAction SilentlyContinue |
Where { ((Get-Date) - $_.LastWriteTime).days -gt 30 } |
ForEach-Object {
Remove-Item $_.FullName -Recurse
Out-File -InputObject $('Removed {0}' -f $_.FullName) -FilePath $LogFile -Append
}
So in this case it worked for me, but I want to use the Script for network drives. If I edit the path everything seems to be fine. But the problem here is the permission. Therefore I found a solution with Get-ChildItem -Directory.
My question here is can pipe this in front of the Remove-Item command?
Like:
$LogFile = '\netshare\folder\log.txt'
dir "\netshare\Files_todelete*" -ErrorAction SilentlyContinue |
Where { ((Get-Date) - $_.LastWriteTime).days -gt 30 } |
ForEach-Object {
Get-ChildItem -Directory | Remove-Item $_.FullName -Recurse
Out-File -InputObject $('Removed {0}' -f $_.FullName) -FilePath $LogFile -Append
}
Logically the Get-ChildItem needs to be in front of the loop?! But I'm not that firm to edit the beginning of the loop correctly.

Scan C disk and copy files

I would appreciate some help here.
The Powershell script should close Outlook process which works.
Aswell as scan C disk for .pst files which works.
Copy these files to "\fileserver01\temp\test\"
Export to csv/excel list where these files where located and last write time.
Possible hide error messages for the user when running the script since it complains about not full access on a few folders when running the scan.
Code:
Get-Process outlook | Foreach-Object { $_.CloseMainWindow() }
Get-ChildItem -path c:\ -recurse -include *.pst | `
Copy-Item -destination "\\fileserver01\temp\test\" | `
Select-object fullname,lastwritetime|export-csv "\\fileserver01\temp\test\"
How should I fix the last couple of things on my list?
Thanks
First you have to use double backslash for UNC paths.
Second, the copy-item does not output anything to the pipeline, you have to use the -Passthru parameter.
Get-ChildItem -path z:\ -recurse -include *.pst -PipelineVariable source |
Copy-Item -Destination "\\path\temp" -Verbose -PassThru |
Select-Object #{n="Source";e={$source.versioninfo.filename}},fullname,lastwritetime | export-csv "\\path\temp\copy_result.csv" -Append -Verbose
I believe the issue is that after the files are copied, the object is gone from the pipeline.
This works:
Get-ChildItem -Path C:\ -Include *.pst -ErrorAction SilentlyContinue | Select-Object FullName, LastWriteTime | Export-Csv -Path "\fileserver01\temp\test\MyCSV.csv"
This doesn't directly answer the question you've asked, as #Adamar's answer appears to do just that.
however, your issue could also be resolved by querying ost/pst files from registry using a snippet like this:
(Get-ChildItem HKCU:\Software\Microsoft\Office\16.0\Outlook\Search).Property | ? {$_ -match "(o|p)st$"}
which will return all of the ost/pst files the logged in user has open in outlook.
a snippet like this will then copy them all to a network share and print the logs to a file.
$FilesToCopy = (Get-ChildItem HKCU:\Software\Microsoft\Office\16.0\Outlook\Search).Property | ? {$_ -match "(o|p)st$"}
$FilesToCopy | ForEach { Copy-Item -Path $_ -Destination "\\network\share" ; $_ | Out-File "\\network\share\log.txt" -Append }
This saves a LOT of time over indexing through all of the C: drive - there's also an issue where very long directory names (greater than 260 char length) are not indexed properly by Get-ChildItem - making this method a bit more reliable and appealing for a production script.
This is the final code.
Thanks everyone for your support.
#Kill Oulook process
Get-Process outlook -ErrorAction SilentlyContinue | Foreach-Object { $_.CloseMainWindow() }
#Scan for .pst files on the C disk
Get-ChildItem -path c:\ -recurse -include *.pst -ErrorAction SilentlyContinue |
#Copy located .pst files to the destination
Copy-Item -Destination "\\networkpath\home\$env:username\ComputerChange\" -Verbose -PassThru -ErrorAction SilentlyContinue |
#Log where files were located and when they were last written to.
Select-Object fullname,lastwritetime | export-csv \\networkpath\home\$env:username\ComputerChange\PSTlog.csv -Verbose
Write-Host "PST Files have successfully been copied, press any key to close" -ErrorAction SilentlyContinue
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
end
So I have created a much faster script as I have excluded some systemfolders and programfiles folders where .PST files doesn't save.
I bet some of you expert can find out why this code doesn't work?
#Exclude systemfolders etc
$folders=get-childitem c:\ | where-object{$_.mode -like "d-*" -AND $_.name -notlike "windows" -AND $_.name -notlike "drivers" -AND $_.name -notlike "program files*"}
#Search thru each root folder for PST-files
$allfiles=$folders | ForEach-Object{get-childitem -Path $_.fullname -include "*.pst" -recurse -ErrorAction silentlycontinue};
$env:username
$foldertocreate="\\destination\$env:username\"
#Check if folder with username exists in the \\destination folder otherwise create folder with username.
if((Test-Path -Path $foldertocreate -PathType Container)) {write-host "Folder already created"}
else {write-host "Creating Folder", New-Item -ItemType Directory -Force -Path $foldertocreate }
#Copy .PST files which is in $allfiles to the folder created in fileshare> $foldertocreate.
#Copy .PST files in $allfiles to the destination folder created.
robocopy $allfiles $foldertocreate
Write-Host "Press any key to close" -ErrorAction SilentlyContinue $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
end

remove-item -force not working on download

so i had writen this script that will clear out the files in thedownload but it doesn't work
$DaysToDelete = 1
download
Get-ChildItem "C:\users\*\Downloads\*"-Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { ($_.CreationTime -lt $(Get-Date).AddDays(-$DaysToDelete))} |
remove-item -force -Verbose -recurse -ErrorAction SilentlyContinue
This code is valid in what it is supposed to do. If there are any errors with file access or anything else, you can inspect them via $Error
automatic variable

powershell backup script with error logging per file

Really need help creating a script that backs up, and shoots out the error along the file that did not copy
Here is what I tried:
Creating lists of filepaths to pass on to copy-item, in hopes to later catch errors per file, and later log them:
by using $list2X I would be able to cycle through each file, but copy-item loses the Directory structure and shoots it all out to a single folder.
So for now I am using $list2 and later I do copy-item -recurse to copy the folders:
#create list to copy
$list = Get-ChildItem -path $source | Select-Object Fullname
$list2 = $list -replace ("}"),("")
$list2 = $list2 -replace ("#{Fullname=") , ("")
out-file -FilePath g:\backuplog\DirList.txt -InputObject $list2
#create list crosscheck later
$listX = Get-ChildItem -path $source -recurse | Select-Object Fullname
$list2X = $listX -replace ("}"),("")
$list2X = $list2X -replace ("#{Fullname=") , ("")
out-file -FilePath g:\backuplog\FileDirList.txt -InputObject $list2X
And here I would pass the list:
$error.clear()
Foreach($item in $list2){
Copy-Item -Path $item -Destination $destination -recurse -force -erroraction Continue
}
out-file -FilePath g:\backuplog\errorsBackup.txt -InputObject $error
Any help with this is greatly appreciated!!!
The answer to complex file-copying or backup scripts is almost always: "Use robocopy."
Bill
"Want to copy all the items in C:\Scripts (including subfolders) to C:\Test? Then simply use a wildcard character..."
Next make it easier on yourself and do something like this:
$files = (Get-ChildItem $path).FullName #Requires PS 3.0
#or
$files = Get-ChildItem $path | % {$_.Fullname}
$files | Out-File $outpath
well it took me a long time, considering my response time. here is my copy function, which logs most errors(network drops, failed copies , etc) the copy function , and targetobject.
Function backUP{ Param ([string]$destination1 ,$list1)
$destination2 = $destination1
#extract new made string for backuplog
$index = $destination2.LastIndexOf("\")
$count = $destination2.length - $index
$source1 = $destination2.Substring($index, $count)
$finalstr2 = $logdrive + $source1
Foreach($item in $list1){
Copy-Item -Container: $true -Recurse -Force -Path $item -Destination $destination1 -erroraction Continue
if(-not $?)
{
write-output "ERROR de copiado : " $error| format-list | out-file -Append "$finalstr2\GCI-ERRORS-backup.txt"
Foreach($erritem in $error){
write-output "Error Data:" $erritem.TargetObject | out-file -Append "$finalstr2\GCI- ERRORS-backup.txt"
}
$error.Clear()
}
}
}