If a job has status completed execude code in powershell - powershell

After about half a day of googling without any luck I've decided to post my question here.
So I want to check if a job has status completed.
Here is my code so far:
Start-job -name Copy -Scriptblock {Copy-Item -force -recurse -path
"C:\Test.temp" -destination "D:\"}
$x = 170 $length = $x / 100 While($x -gt 0) {
$min ) [int](([string]($x/60)).Split('.')[0]) $Text = " " + $min + "
mintues " + ($x % 60) + " seconds left" Write-progress "Copying file,
estimated time remaning" -status $text -percentComplete ($x/$length)
Start-sleep -s 1 $x--
if (Get-job -name Copy -status "Completed") { Break } }
So as you can see I first start a job, then I run a loop with a countdown progress bar. This is just to give the user some kind of feedback that things are still moving. Note that the "Get-job -status "completed" doesn't work since it's not a parameter of Get-job.
The problem now is that I can't get the "if get job has completed, break the loop" since the copying job might be done before the progress bar.
Does anyone know a good solution to this?
Thanks in advance!

Using ForEach is probably your best bet for breaking the loop cleanly once done.
This shows a progress bar but no timer, more so just a per file progress so it will tell you what it is up to and whats taking a while.
$srcPath = 'C:\Test.temp'
$destPath = 'D:\'
$files = Get-ChildItem -Path $srcPath -Recurse
$count = $files.count
$i=0
ForEach ($file in $files){
$i++
Write-Progress -activity "Copying from $srcPath to $destPath" -status "$file ($i of $count)" -percentcomplete (($i/$count)*100)
if($file.psiscontainer){
$sourcefilecontainer = $file.parent
} else {
$sourcefilecontainer = $file.directory
}
$relativepath = $sourcefilecontainer.fullname.SubString($srcPath.length)
Copy-Item $file.fullname ($destPath + $relativepath) -force
}

I think you could get the condition to work like this:
if ( Get-job -State Completed | Where-Object {$_.Name.Contains("Copy"){ Break }
Your -status does not exist in the get-job

Related

( Get-ChildItem c:\MyFolder | Measure-Object ).Count results in ObjectNotFound

The command
( Get-ChildItem c:\MyFolder | Measure-Object ).Count
sometimes gives the error
CategoryInfo :ObjectNotFound: (:\MyFolder\myfile.xml:String) [Get-ChildItem], IOException
FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
It is correct that the object that cannot be found has been moved to the folder by another process but how to make not checking more than once?
To be clear, the problem is not the missing object but that the count files if the content change between Time1 and Time2 - and I dont get what Time2 is.
EDIT
I have simplified it and added some switches - partly at random
This exactly what I do
$i = 0
ForEach ($file in $files) {
ProcessOneFile ($file)
start-sleep -Milliseconds 500
$i++
if ($i -eq 100) {
write-host '100'
while((Get-ChildItem -force -file -name $Myfolder'\*xml').Count -gt 200)
{
write-host 'too many, wait 30 sec'
start-sleep -Milliseconds 30000
}
$i = 0
}
}
It seems it works if -name is used. I suppose it disconnects the collection from the actual file system. Surprising to me but I lack the indepth knowledge (clearly)
So for count only
(Get-ChildItem -name -force -file $MyDir'\*xml').Count
Is the safer bet

Adding a Write Progress bar to a script Powershell

I'm actually writing a powershell script that sort pictures and videos by dates. The script works fine but i would like to add a progress bar, and i don't know where to start, this might be a bit tricky for me, that's why i'm looking for help.
Here is the function that sort pictures
foreach ($file in $Images)
{
$Directory = $destinationDirectory + "Pictures\" + $file.LastWriteTime.Date.ToString('yyyy') + "\" + $file.LastWriteTime.Date.ToString('MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
Copy-Item $file.fullname $Directory
}
I read the documentation about the Write-progress function but i really don't know how i'm supposed to manage it in this script
Use a variable to hold the count of files copied, increment it for each operation, then display the percentage. The example for Write-Progress has a pretty good example.
I'd recommend using the PowerShell pipeline as well instead of a foreach.
Something like this (remove the -WhatIfs when you're ready):
$images |
ForEach-Object
-Begin {
$filesCopied = 0
} `
-Process {
$Directory = "$destinationDirectory\Pictures\$($_.LastWriteTime.Date.ToString('yyyy'))\$($_.LastWriteTime.Date.ToString('MMM'))"
if (!(Test-Path $Directory)) {
New-Item $directory -type directory -WhatIf
}
Copy-Item $_.fullname $Directory -WhatIf
$filesCopied += 1
Write-Progress -Activity "Copied $_.FullName" `
-CurrentOperation "Copying $_" `
-Status "Progress:" `
-PercentComplete (($filesCopied / $Images.Count) * 100)
}
The Write-Progress cmdlet needs a bit of math to make it work for your situation. This should do it:
$i = 1
foreach ($file in $Images)
{
$Directory = $destinationDirectory + "Pictures\" + $file.LastWriteTime.Date.ToString('yyyy') + "\" + $file.LastWriteTime.Date.ToString('MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
Copy-Item $file.fullname $Directory
[int]$Percent = $i / $Images.count * 100
Write-Progress -Activity "Copying photos" -Status "$Percent% Complete:" -PercentComplete $Percent
$i++
}
First, start with a counter variable $i and set it to 1 to represent the first item. This is setup outside the loop so that it doesn't reset back to 1 every time the loop runs.
Then, inside the loop the $Percent variable is defined by dividing the value of $i by the number of items and multiplying it by 100. Then, Write-Progress is called with the necessary parameters to display the progress. Then the counter is incremented upward by one using $i++.
Side note: $Percent is set to be an integer by placing [int] in front of it, which forces it to display whole numbers. If you want to see fractional values, just remove the [int].

Write-Progress function to tell user percent completion of deletion script

I am writing a PowerShell script to delete various files and want to write a function that will prompt the user the percentage completed for each file deletion so that the user doesn't think that the script has crashed. Instead of a progress bar such as {000000.... I would rather have the screen print out a percent number like 10% complete.
#Variables
$Comp_Name = $env:COMPUTERNAME
$DateTime = Get-Date -Format "DMM-dd-yyyy_THH-mm-ss"
#Log Errors
Start-Transcript -Path C:\TEMP\error_Log-$Comp_name-$DateTime.log -Append
# Get the date and time and remove the directory specified in the function
Function Remove-Directory
{
Param([string]$Location)
$files = Get-ChildItem -Path $Location -Recurse | Where-Object {!$_.PSIsContainer}
for ($i = 1; $i -lt $Files.count; $i++) {
Write-Progress -Activity 'Deleting files...' -Status $Files[$i].FullName -PercentComplete ($i / ($Files.Count*100))
Try
{
Get-ChildItem $Location -Recurse -ErrorAction SilentlyContinue | Remove-Item -Force -Recurse -ErrorAction SilentlyContinue -Verbose 4>&1 | Add-Content C:\TEMP\ModifiedData-$Comp_Name-$DateTime.log
#Write-Output "SUCCESS: $Location has been been Modified Successfully"
}
Catch{Write-Output "ERROR: $Location could be Modified. Please Verify This Location Manually."}
}
}
#Remove the below files from computer
If ($Comp_Name -eq "X")
{
Remove-Directory "C:\Users\X"
}
Stop-Transcript
Write-Output "Script Process Complete. Please Check logs for additional details"
Instead of using -percentcomplete you can use one of the other status indicators
-CurrentOperation "($i / ($Files.Count*100))% complete"
You may wish to round or cast the percentage to an integer, something like:
-CurrentOperation "$([int]($i / $Files.Count*100))% complete"
The order the parameters show up is as follows, so use which one depending on how you want the hierarchy of messages to display.
-Activity
-Status
-CurrentOperation

Progress Bar Login in Powershell Delete Task

Good afternoon Stack Community,
I'm new to progress bar displays in PS. But after reviewing the documentation and a few forums I've ended up with the script below. It just doesn't do anything. It does not delete the folder/subfolders, nor does it display a progress bar, nor does it error out. Is my logic out of context or is there a better way to nest the progress bar with the associated task?
$computerlist = get-content -path c:\scripts\Computerlist-test.txt
$FolderPath = "c$\IT\9.0.0"
$Path = "\\$computer\$FolderPath"
foreach ($computer in $computerlist) {
for ($i = 1; $i -lt $ListOfFiles.count; $i++) {
Write-Progress -Activity 'Deleting Folders/Files...' -Status $ListOfFiles[$i].FullName -PercentComplete ($i / ($ListOfFiles.Count*100))
Remove-Item -path $Path -Recurse -WhatIf
$ListOfFiles = Get-ChildItem -Path $Path -Recurse | Where-Object {!$_.PSIsContainer}
}
}
The remove-item portion works without the secondary "I" loop for the taskbar so I am assuming this is illogical.

Powershell Script to delete files not in a list with progress bar

I have a folder with .jpg files in it. I associate these with products in an access database. One of the sources for products provides these .jpg files but they do not allow you to easily download only the pictures that you currently use. Therefore I have found a PowerShell Script to delete the files that I do not need.
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name } | Remove-Item
Credit to #x0n Powershell script to delete files not specified in a list
And it works great! but the problem is it takes forever and I have over 180,000 items to search through and delete. So I wanted to make a progress bar that would let me know how far I had gone through the process.
So after a little bit of searching I found an article called "using the progress bar"
The problem is I don't know how to mash the two together, However I have made an attempt here:
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
1..100 | foreach-object {
Write-Progress -Activity "Deleting Files" -Status "$_ %" -Id 1 -PercentComplete $_ -CurrentOperation "Deleting File $_"
dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name } | Remove-Item
}
However that seems to take even longer than the original script did, I don't know exactly how it is working, and I am testing it when I only need to remove 10-15 files.
It is likely there is something really basic I am missing But I would really appreciate some help understanding this.
Here I have added a screenshot:
PowerShell Console
However that seems to take even longer than the original script did
That's because you're attempting to enumerate, filter and delete the files 100 times - which is obviously unnecessary.
What you want to do is calculate how far in the process of deleting the files you are, and then use that as a basis for the percentage you pass to Write-Progress. The easiest way to keep count is probably to use a regular for loop:
Note: these first two examples are very generic, go to the bottom for an example that takes your volume (~180.000 files) into account.
# Grab all the files you need to delete
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
$filesToDelete = Get-ChildItem M:\PhotoDirectory\PhotoFolder -Recurse | Where-Object {$exclusions -notcontains $_.Name }
for($i = 0; $i -lt $filesToDelete.Count; $i++){
# calculate progress percentage
$percentage = ($i + 1) / $filesToDelete.Count * 100
Write-Progress -Activity "Deleting Files" -Status "Deleting File #$($i+1)/$($filesToDelete.Count)" -PercentComplete $percentage
# delete file
$filesToDelete[$i] |Remove-Item
}
# All done
Write-Progress -Activity "Deleting Files" -Completed
Another characteristic you might want to use to indicate a percentage is the relative volume (total number of bytes) removed. We can do this by simply keeping track of how many bytes we need to remove total, and how many we've removed so far:
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
$filesToDelete = Get-ChildItem M:\PhotoDirectory\PhotoFolder -Recurse | Where-Object {$exclusions -notcontains $_.Name }
$TotalSize = ($filesToDelete |Measure-Object -Property Length -Sum).Sum
$BytesRemoved = 0
foreach($file in $filesToDelete){
$percentage = $BytesRemoved / $TotalSize * 100
Write-Progress -Activity "Deleting Files" -Status "Deleted $BytesRemoved/$TotalSize bytes" -PercentComplete $percentage
$file |Remove-Item
$BytesRemoved += $file.Length
}
Write-Progress -Activity "Deleting Files" -Completed
As #MatthewWetmore points out, invoking Write-Progress every time you delete a file will of course incur some overhead. And with 180.000 files, you're probably not that interested in having the UI update when the progress goes from 3.56325% to 3.56331%
What you could do is use the for loop to count in increments of 1% of the entire set of items, and then remove a whole range of files on each iteration:
[int]$hundredthStep = $filesToDelete.Count / 100
for($i = 0; $i -lt $filesToDelete.Count; $i += $hundredthStep){
# calculate progress percentage
$percentage = ($i + 1) / $filesToDelete.Count * 100
Write-Progress -Activity "Deleting Files" -Status "Deleting File up to #$($i+1)/$($filesToDelete.Count)" -PercentComplete $percentage
# delete file
$filesToDelete[$i..($i + $hundredthStep - 1)] |Remove-Item
}
# All done
Write-Progress -Activity "Deleting Files" -Completed
You want to do something like this (beware this is untested so i've put -whatif on the remove cmdlet which you should remove when you're happy it's working correctly):
$exclusions = Get-Content C:\Users\office\Desktop\ExcludedPhotos.txt
$files = dir -rec M:\PhotoDirectory\PhotoFolder | Where-Object {$exclusions -notcontains $_.name }
$files | foreach-object {
$num += 1
Write-Progress -Activity "Deleting Files" -Status "$_ %" -Id 1 -PercentComplete (($num / $files.count) * 100) -CurrentOperation "Deleting File $($_.name)"
$_ | Remove-Item -WhatIf
}