7Zip - Powershell - $LastExitCode Issues - powershell

Pretty sure just me not knowing what to do but I am having issues with a 7zip PS script and the $LastExitCode
ForEach ($File in $Files) {
7zip a “$DestDir\$file.7z” "$SourceDir\$File” -m0=LZMA2 -mx=9 -mmt4 | findstr /I "archive everything error" | Out-File $LOGPath -Force -Append
7zip t "$DestDir\$file.7z" | findstr /I "testing size compressed archive everything error" | Out-File $LOGPath -Force -Append
if ($LASTEXITCODE -eq 0) {
Write-Output “Compression SUCCEEDED and zip file tested OK” | Out-File $LOGPath -Force -Append
Write-Output “DELETING ORIGINAL file - $File `n” | Out-File $LOGPath -Force -Append
Remove-Item -Path “$SourceDir\$File” | Out-File $LOGPath -Force -Append
}
else {
Write-Output “Compression FAILED, source file not deleted `n” | Out-File $LOGPath -Force -Append
}
}
This is the script (important bits)
It does a zip then a test of the created package
So to test that the $LastExitCode is working (or not), I # out the zip part and leave the test step and remove any zip files from the destination folder. The zip test step fails as expected and sends an error to log (Error:cannot find archive) but still goes through with the remove-item, which should only occur if the test passes I would have throught??
Not sure what I am doing worng here? Or if this is the incorrect way to go about this?
I want to create the archive, confirm it is OK, then delete the original source file if it is (i.e. no errors).
Any advice really apprecited
thanks
EDIT
Ended up with below that seems to do the trick - thanks for the advice
ForEach ($File in $Files) {
Write-Output “Compressing $File” | Out-File $LOGPath -Force -Append
7zip a "$DestDir\$file.7z” "$SourceDir\$File" -m0=LZMA2 -mx=9 -mmt4
if ($LASTEXITCODE -eq 0) {
Write-Output "Compression SUCCEEDED" | Out-File $LOGPath -Force -Append
Write-Output “TESTING compressed file - $File” | Out-File $LOGPath -Force -Append
7zip t "$DestDir\$file.7z"
if ($LASTEXITCODE -eq 0) {
Write-Output "Zip file tested OK" | Out-File $LOGPath -Force -Append
Write-Output "DELETING original file - $File `n" | Out-File $LOGPath -Force -Append
#Remove-Item -Path “$SourceDir\$File” | Out-File $LOGPath -Force -Append
}
else {
Write-Output “Zip test FAILED, source file not deleted `n” | Out-File $LOGPath -Force -Append
}
}
else {
Write-Output "Compression FAILED for file - $file - moving onto next file" | Out-File $LOGPath -Force -Append
}
}

Related

Powershell. Writing information to the log with and without an error

I'm trying to get powershell to write information about the execution of an operation to a log file. There is a folder with logs, it is necessary that the script delete files older than a certain number of days from the folder (implemented) and record information about the deletion of files or the absence of files in the folder (in case of an error when executing the script). Now the script writes information to the log about the absence of files, then if they are. Tell me what to do wrong? The text is as follows:
if ($error) {"No files found" *>> "D\TEST\Log $(gat-date -f dd-MM-yyy).txt"}
else {"Files deleted" *>> "D\TEST\Log $(gat-date -f dd-MM-yyy).txt"}
In principle $error is a automatic variable containg all errors occured within the current session. From my point of view its a better approach to use try/catch to handle errors. By doing so you can specify the error message to write to the logfile that matches the error, instead of writing the same error message for any kind of errors e.g.:
try {
#do someting
"Did something successfully" | set-content -path $logfilePath -Append -Force -Confirm:$false
}
Catch {
#gets executed if a terminating error occured
write-error "Failed to do something, Exception: $_"
"Failed to do something, Exception: $_" | set-content -path $logfilePath -Append
}
But back to your example, you could do:
$date = get-date -Format dd-MM-yy
$logFilePath = "D\TEST\Log_$date.txt"
If ($error){
"No files found" | set-content -path $logfilePath -Append -Force -Confirm:$false
}
Else {
"Files deleted" | set-content -path $logfilePath -Append -Force -Confirm:$false
}
ok based on the comment you could go this route:
$date14daysBack = (get-date).AddDays(-14)
$date = Get-Date -Format dd-MM-yyyy
$LogfilePath = "D:\TEST\Log_$date.txt"
try {
#try to map drive, if something goes wrong stop processing. You do not have to escape the $ if you use single quotes
New-PSDrive -Name "E" -PSProvider "FileSystem" -Root '\\Computer\D$\TEST' -Persist -ErrorAction:Stop
}
Catch {
"Failed to map drive '\\Computer\D$\TEST' - Exception $_" | Set-Content -Path $logfilePath -Append -Force
throw $_
}
try {
#I replaced forfiles and the delete operation with the powershell equivalent
$files2Remove = get-childitem -path E:\ -recurse | ?{$_.LastWriteTime -ge $date14daysBack}
$null = remove-item -Confirm:$false -Force -Path $files2remove.FullName -ErrorAction:stop
}
Catch {
"Failed to delete files: $($files2remove.FullName -join ',') - Exception: $_" | Set-Content -Path $logfilePath -Append -Force
}
#If files were found
If ($files2Remove){
"Files deleted, count: $($files2remove.count)" | Set-Content -Path $logfilePath -Append -Force
}
Else {
"No files found" | Set-Content -Path $logfilePath -Append -Force
}
Currently the code does not filter for '.' like in your sample: /m . - do I understand this correctly the filename is only a dot, nothing else?
The script has earned in the following form:
#cleaning up errors
$Error.Clear()
#days storage
$int = 11
#connecting a network drive
New-PSDrive -Name "E" -PSProvider "FileSystem" -Root "\\Computer\D`$\TEST" -Persist
#deleting files
FORFILES /p E:\ /s /m *.* /d -$int /c "CMD /c del /Q #FILE"
#disabling a network drive
Remove-PSDrive E
#recording information in the log
$date = Get-Date -Format dd-MM-yyyy
$LogfilePath = "D:\TEST\Log_$date.txt"
(Get-Date) >> $LogfilePath
if ($Error){"No files found" | Add-content -path $LogfilePath -Force -Confirm:$false}
Else {"Files deleted" | Add-Content -path $LogfilePath -Force -Confirm:$false}

Logging file output

The logging only traps on the IDs in my text file (get-content) it does not print the file name which gets copied
I've tried using the log option with robocopy however it only logs the last enter in my get-content text file
$Source = "F:\Temp\"
$Test = "F:\Output\"
$Daily_Results="F:\Output\Test\"
foreach ($ID in Get-Content F:\Files\files.txt) {
$ID
Get-ChildItem -Path $Source | foreach {
if($_ -match $ID) {
$Path=$Source+"$_\"
$Path
robocopy $path $test
Write-Host $Path
"File copied"
Write-Output $ID "File copied" | Out-File $Daily_Results\$(get-date -f yyyy-MM-dd)_CopyMove_Results.txt -append
Write-Output $_ | Out-File $Daily_Results\$(get-date -f yyyy-MM-dd)_CopyMove_Results.txt -append
}
}
}
What happens is that $_ gets you the full object, you need to explicitly say you want the Name.
Write-Output $_.Name | Out-File $Daily_Results\$(get-date -f yyyy-MM-dd)_CopyMove_Results.txt -append
As you are copying the files one-by-one, I see no real advantage in using robocopy here, but rather user PowerShell's own Copy-Item cmdlet.
Because you didn't say what the $ID from the text file could be, from the code you gave I gather that it is some string that must be part of the file name to copy.
This should work for you then
$Source = 'F:\Temp'
$Destination = 'F:\Output'
$Daily_Results = Join-Path -Path 'F:\Output\Test' -ChildPath ('{0:yyyy-MM-dd}_CopyMove_Results.txt' -f (Get-Date))
foreach ($ID in Get-Content F:\Files\files.txt) {
Get-ChildItem -Path $Source -File -Recurse | Where-Object { $_.Name -like "*$ID*" } | ForEach-Object {
$_ | Copy-Item -Destination $Destination -Force
Write-Host "File '$($_.Name)' copied"
# output to the log file
"$ID File copied: '$($_.Name)'" | Out-File -FilePath $Daily_Results -Append
}
}

PowerShell Event Viewer Errors

I am running a PowerShell script which I have a list of IDs in a text file that matches to files on a server and then Robocopy copies them to other servers. Recently a file that is present on a server doesn't get copied to 1 out of 2 destinations. The weird thing is it only happens approximately 10 files out of 500.
I am seeing weird errors in EventViewer. Would this cause the issue?
Event ID 400 Engine state is changed from None to Available.
Details: NewEngineState=Available PreviousEngineState=None
Event ID 403
Engine state is changed from Available to Stopped.
Details: NewEngineState=Stopped PreviousEngineState=Available
Changing copy-item to robocopy in the scripts
$CC="S:\CC 2019"
$Daily_Results="S:\~Copy_Move Daily Results\"
$Missing_Files = "S:\~Missing Files\Results\"
$Lab = "\\********\E-Drive\Logs\Files"
$Source = "S:\"
foreach ($ID in Get-Content 'S:\~Master CSC Location Files\CC_Listings.txt') {
$ID
$Count=0
Get-ChildItem -Path $Source -ErrorAction SilentlyContinue | where {$_.name -match $ID} |foreach {
$Path="S:\"+$_.name
Robocopy $Source $Lab $_.name /COPY:DAT /IS
Robocopy $Source $CC $_.name /MOV /IS
Write-Host $_.name
"File copied"
Write-Output $ID "File copied" | Out-File $Daily_Results\$(get-date -f yyyy-MM-dd)_CC_CopyMove_Results.txt -append
Write-Output $_.name | Out-File $Daily_Results\$(get-date -f yyyy-MM-dd)_CC_CopyMove_Results.txt -append
$Count++
}
If($Count –eq 0){
Write-Host $ID "No File Found"
Write-Output $ID "No File Found at $(get-date -f hh:mm:ss)" | Out-File $Missing_Files\$(get-date -f yyyy-MM-dd)_CC_Missing_Files_Results.txt -append
}
}

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.

What is the easiest way to create log file in powershell?

I have a code which modify user attribute in active directory.
How can I modify the code, to see in a log file what changed? I would like to see too if there was an error or not. If was an error what was that.
The code:
$csvdata = Import-Csv $csv -Delimiter $delimiter -Encoding "UTF8"
ForEach-Object -InputObject $csvdata {
$params = #{Identity = $_.ObjectGUID}
$sn = $_.Surname.Trim()
$gn = $_.GivenName.Trim()
$Manager = $_.Manager
if (-not [string]::IsNullOrWhiteSpace($_.Surname)) {
$params.Surname = $_.Surname
}
if (-not [string]::IsNullOrWhiteSpace($_.Givenname)) {
$params.Givenname = $_.Givenname
}
Set-ADUser #params
}
You can use transcript commands.
Start-Transcript
& ".\Script.ps1"
Stop-Transcript
I wrote the following function for logging in a little script I made a while back, feel free to rip it up and abuse it!
function Write-Log {
param(
[Parameter(ValueFromPipeline =$true,
ValueFromPipelineByPropertyName=$true,
Position=0
)]
[string[]]
$Message,
[string]
$Level = "Informational"
)
if (!$loglocation)
{
write-error -Message 'No $LogLocation set.'
break
}
$logarchive = split-path $loglocation
$logarchive = $logarchive + "\Archive.log"
$truedate = get-date -f yyyy-MM-dd_HH:MM:ss
if (test-path $loglocation)
{
if ((get-item $loglocation).length -ge 5242880)
{
"$truedate : Log exceeds 5MB, archiving and creating new log." | out-file -append -filepath $loglocation
if (test-path $logArchive)
{
"$truedate : Log archive already exists, removing this log first before archiving current log." | out-file -append -filepath $loglocation
get-item $logArchive | remove-item
}
get-childitem $loglocation | rename-item -NewName {"Archive.log"}
"$truedate : New log created, old log archived." | out-file -append -filepath $loglocation
}
}
"$truedate : $level - $message" | out-file -append -filepath $loglocation
}
You just need to set a variable in your script called $loglocation to the file path you want the log to save too, i.e. "C:\MyLogs" etc. Then when you want to log something out to it, just use write-log -Message "Whatever you are logging".