Capture the messages by cmdlets in PowerShell - powershell

I am running the below script. If the Copy-Item command is successfully completed, it does not show any messages such as how many files are copied. How do I capture this?
Note: I also need to capture the error message which the script is doing correctly.
$LogFile = "P:\users\Logname.log"
$msg = Copy-Item P:\Bkp_20130610\* P:\users -force -recurse -ErrorAction SilentlyContinue
if (-not $?)
{
msg1 = $Error[0].Exception.Message
Write-Host "Encountered error. Error Message is $msg1."
exit
}
$msg > $LogFile
Write-Host "Hello"

You can obtein a list of copied files in this way
$files = copy-item -path $from -destination $to -passthru
pipe it to | ? { -not $_.psiscontainer } if you are copying folder and you don't want them in the count
then use
$files.count

You can use the -Verbose switch with the Copy-Item cmdlet:
$msg=Copy-Item P:\Bkp_20130610\* P:\users -force -recurse -ErrorAction SilentlyContinue -Verbose

Related

PS Script to uninstall Firefox from multiple locations

I am working on creating a script to uninstall Firefox from multiple locations. I have a script that I've created and it works to an extent. I have made changes to my original script based on the answer below plus some other changes
$LocalUsers = (Get-ChildItem -Path "C:\Users").name
# Uninstalling from Program Files
if (Test-Path "${env:ProgramFiles(x86)}\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "${env:ProgramFiles(x86)}\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
if (Test-Path "${env:ProgramFiles}\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "${env:ProgramFiles}\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
# Uninstalling for each user
ForEach ($LocalUser in $LocalUsers){
$Userpath = "C:\Users\" + $LocalUser
if (Test-Path "$Userpath\AppData\Local\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "$Userpath\AppData\Local\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
Start-Sleep 20
# Remove shortcuts from appdata
Remove-Item -Path "$userpath\AppData\Local\Mozilla" -Force -Recurse -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\AppData\LocalLow\Mozilla" -Force -Recurse -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Firefox.lnk" -Force -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\desktop\firefox.lnk" -Force -Verbose #-ErrorAction SilentlyContinue
}
# Remove related registry keys
$pathToRemove = #(
'HKLM:\Software\Mozilla'
'HKLM:\SOFTWARE\mozilla.org'
'HKLM:\SOFTWARE\MozillaPlugins'
'HKLM:\SOFTWARE\WOW6432Node\Mozilla'
'HKLM:\SOFTWARE\WOW6432Node\mozilla.org'
'HKLM:\SOFTWARE\WOW6432Node\MozillaPlugins'
'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Firefox.lnk'
)
foreach($path in $pathToRemove) {
if(Test-Path $path) {
try {
Remove-Item $path -Recurse -Force -Verbose #-ErrorAction SilentlyContinue
}
catch {
Write-Warning $_.Exception.Message
}
}
}
The script has worked on some machines where it uninstalls the application, however, for others trace of it is being left behind in Windows Program Files. It is appearing as a dead link. I know it is a dead link because it is missing the Firefox logo. The strange thing is its points to %localappdata%\Mozilla Firefox\uninstall\helper.exe per the error
What the app should look like if installed (ignoring the version just a screenshot from online):
I'm assuming the problem is your chained if \ elseif \ else conditions, what could be happening is that if the first condition was $true you're only removing the first registry key and then exiting the chained conditions (this is by design):
# only results in 'hello if' and then exits the chained conditions
if($true) {
'hello if'
}
elseif($true) {
'hello elseif'
}
What you can do in this case is store all the paths in an array and then loop over them, testing if the path exists and, if it does, remove it:
$pathToRemove = #(
'HKLM:\Software\Mozilla'
'HKLM:\SOFTWARE\mozilla.org'
'HKLM:\SOFTWARE\MozillaPlugins'
'HKLM:\SOFTWARE\WOW6432Node\Mozilla'
'HKLM:\SOFTWARE\WOW6432Node\mozilla.org'
'HKLM:\SOFTWARE\WOW6432Node\MozillaPlugins'
'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Firefox.lnk'
)
foreach($path in $pathToRemove) {
if(Test-Path $path) {
try {
Write-Verbose "Attempting to remove: $path" -Verbose
Remove-Item $path -Recurse -Force
Write-Verbose "Successfully removed: $path" -Verbose
}
catch {
Write-Warning $_.Exception.Message
}
}
}

Error not being logged into output log file

I have the following script where, when the if(-not) condition is met, the log file is being generated but not error is being written in the log file.
I have very basic understanding of scripting languages and as a result cannot understand why nothing is being logged. Help is appreciated.
$resulterror = $error[0].exception.message
$BckDate = Get-Date -Format "ddMMyyyy"
$BckFolder = "<path>"+$BckDate
$log = "<path>"+$BckDate+".log"'
Copy-Item -Path $BckFolder -Destination <drive-letter> -ErrorAction silentlyContinue -recurse
if(-not $?) {$resulterror >> $log ; invoke-expression -Command "<path-of-ps-script-to-run>"}
else {"Backup "+$BckDate+" done successfully" >> $log}
The real paths have been hidden with the "path" in <> explaining that it is a directory path.
The path of the script triggered when the if(-not) condition is met is replaced with path-of-ps-script-to-run in <>. The <> are just brackets for the comments so don't confuse them with actual code symbols.
I would use the -ErrorVariable advanced parameter to store the error message in that variable and access it:
Copy-Item -Path $BckFolder -Destination <drive-letter> -ErrorAction silentlyContinue -recurse -ErrorVariable copyError
if($copyError)
{
$resulterror | Out-File -FilePath $log -Append
invoke-expression -Command "<path-of-ps-script-to-run>"
}
else
{
"Backup "+$BckDate+" done successfully" | Out-File -FilePath $log -Append
}
Your variable $resulterror is empty since you saved it at the very begining of the script and there were no errors at that time. Try to use explicit $error[0].exception.message instead of $resulterror on IF condition.
$BckDate = Get-Date -Format "ddMMyyyy"
$BckFolder = "<path>"+$BckDate
$log = "<path>"+$BckDate+".log"
Copy-Item -Path $BckFolder -Destination <drive-letter> -ErrorAction silentlyContinue -recurse
if(-not $?) {$error[0].exception.message >> $log ; invoke-expression -Command "<path-of-ps-script-to-run>"}
else {"Backup "+$BckDate+" done successfully" >> $log}

Powershell Output to my log location not working

I am looking to log the output of my script to a log file. But not able to get the output to a file.
Set-ExecutionPolicy RemoteSigned
$server_names = Get-Content "E:\Bibin\Copy\complist.txt"
$Folder=$((Get-Date).ToString('yyyy-MM-dd'))
$Logfile = "E:\Bibin\Copy\copy.log"
Function LogWrite
{
Param ([string]$logstring)
Add-content $Logfile -value $logstring
}
Foreach ($server in $server_names)
{
$FileExists = Test-Path "\\$server\C$\temp\TEST\*"
If ($FileExists -eq $True)
{
New-Item "\\$server\C$\temp\TEST\$Folder" -type directory
Move-Item "\\$server\C$\temp\TEST\*" -Destination "\\$server\C$\temp\TEST\$Folder" -force
Copy-Item "\\DC1NAS02P00\data\IT\CPS\Projects\NGNet\CpsServerUpgradeFiles\Upgrade Version 2.0\2003_Files\*.*" -Destination "\\$server\C$\temp\TEST" -Recurse
}
Else
{
New-Item "\\$server\C$\temp\TEST" -type directory
Copy-Item "\\DC1NAS02P00\PDSdata\IT\CPS\Projects\NGNet\CpsServerUpgradeFiles\Upgrade Version 2.0\2003_Files\*.*" -Destination "\\$server\C$\temp\TEST" -Recurse
}
}
Also I want some time gap between New_item and Move-item, since it is saying file is already in use ..
Thanks
Bibin
instead of using Add-Content use Out-File.
Also try robocopy instead of copy, this will wait for the locks to release before copying.

COPY-ITEM Passthru not working when encountering error

Within ISE, I've tried both the below. Neither is working. The only way is to clear $error and test after the copy attempt. Any suggestions?
$cpy = Copy-Item -Path "D:\~a\2K0NVK0.xt" -Destination "D:\~Bkup-F\2K0NVK10.txt" -Force -passthru -ErrorAction SilentlyContinue
if($cpy){ $cpy # only displays on successful copy }
Try{
Copy-Item -Path "D:\~a\2K0NVK0.xt" -Destination "D:\~Bkup-F\2K0NVK10.txt" -Force -ErrorAction SilentlyContinue
} Catch { write-host "Hit a bug!" # not being displayed }
A try/catch only works when ErrorAction is set to Stop.

Get the list of files that are getting copied in PowerShell

I am using the PowerShell Copy-Item command to copy a directory with files to another location.
I want to display all the files on the console that are getting copied so that I know the status of the copy command.
If you just want to see that in console, use the -verbose switch:
copy-item -path $from -destination $to -verbose
If you want to get a list of files or directories:
$files = copy-item -path $from -destination $to -passthru | ?{$_ -is [system.io.fileinfo]}
$source=ls c:\temp *.*
$i=1
$source| %{
[int]$percent = $i / $source.count * 100
Write-Progress -Activity "Copying ... ($percent %)" -status $_ -PercentComplete $percent -verbose
copy $_.fullName -Destination c:\test
$i++
}
I suggest to try it this way:
(Copy-Item -Verbose C:\SrcDir\*.* c:\DstDir 4>&1).Message
Here the messages go to the output stream/pipeline rather than the verbose stream/pipeline and so will work more generally such as in TFS task scripts.
If you want to directly output the filenames, you can do it this way:
With Path
Copy-Item -Path $from -Destination $to –PassThru | ForEach-Object { Write-Host $_.FullName }
FileName Only
Copy-Item -Path $from -Destination $to –PassThru | ForEach-Object { Write-Host $_.Name }