Link to home
Start Free TrialLog in
Avatar of Scott Fell
Scott FellFlag for United States of America

asked on

Powershell Move Files In A Folder

My code below is part of a larger script that loops through files in a folder and sends an email with attachment.  After each email, I would like the file to be moved to a new folder.  I am getting an error that a file is in use.  It seems to loop through all files ok, but one can never be used because it is in use.  Short code and Error below with full code.

PS C:\Users\scott> $Path = "C:\temp\"
$NewPath = "C:\temp\sent"
$files = Get-ChildItem C:\temp\*.*
ForEach ($file in $files) { 
    $attachment = $path+$file.name
  #send mail
    Move-Item $attachment $NewPath -force
}

Open in new window

ERROR
Move-Item : The process cannot access the file because it is being used by another process.
At line:6 char:5
+     Move-Item $attachment $NewPath -force
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (C:\temp\test2.txt:FileInfo) [Move-Item], IOException
    + FullyQualifiedErrorId : MoveFileInfoItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand

Open in new window


I have also tried putting the move command after the loop.  It always leaves one file.

PS C:\Users\scott> $Path = "C:\temp\"
$NewPath = "C:\temp\sent"
$files = Get-ChildItem C:\temp\*.*
ForEach ($file in $files) { 
    $attachment = $path+$file.name
  #send mail
    
}
Move-Item $attachment $NewPath -force

Open in new window


My full code is
$Path = "C:\temp\"
$NewPath = "C:\temp\sent"
$files = Get-ChildItem C:\temp\*.*
ForEach ($file in $files) { 


    $SMTPServer = "smtp.example.com"
    $SMTPPort = "587"
    $Username = "me@example.com"
    $Password = "abc134"

    $to = "you@example.com"
   
    $subject = "Email Subject"
    $body = "Insert body text here"
    $attachment = $path+$file.name

    $message = New-Object System.Net.Mail.MailMessage
    $message.subject = $subject
    $message.body = $body
    $message.to.add($to)
    #$message.cc.add($cc)
    $message.from = $username
    $message.attachments.add($attachment)

    $smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
    $smtp.EnableSSL = $true
    $smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
    $smtp.send($message)
    #write-host "Mail Sent"

  # Move-Item $attachment $NewPath -force

}

Move-Item "C:\temp\*.*" $NewPath -force

Open in new window

Avatar of footech
footech
Flag of United States of America image

Always the same file, or is there any pattern?
If you think it is being locked by the mail send process, then I would insert the following at line 30.
$smtp.Dispose()
I could see how that would happen.  You could also try throwing in a delay (Start-Sleep).
I'm curious why you're not using the Send-MailMessage cmdlet.  Unless you're using an older version of PS, all the functionality is there.
Avatar of Scott Fell

ASKER

>I'm curious why you're not using the Send-MailMessage cmdlet

Because I am not very familiar with Powershell.  I'm open though.
the .Dispose() didn't work. I think it is because of the looping.  When I try the first sample code with 8 lines the same thing happens.
Actually, it might be necessary to use.
$message.Dispose()
or even just setting the attachments property to $null.

Testing would be needed to determine the impact, but some efficiency could be had by moving elements that don't change out of the foreach loop.  Maybe just keeping the $message.attachments.add($attachment) and $smtp.send() bits in there.

If you've got PS 3.0+, then I'd just use Send-MailMessage.  I think the syntax is easier.
If it's happening with just that sample (where a mail send isn't really happening), then something else is locking the file.  I'd use Process Explorer or handles.exe (Sysinternals) to try to determine what.
The key was to use both!
$smtp.Dispose()
$message.Dispose()
ASKER CERTIFIED SOLUTION
Avatar of footech
footech
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
On Windows 10, I used both $message.Dispose() and $smtp.Dispose() but on server 2008 RT it I had to only use $message.Dispose() because  $smtp.Dispose() generated an error.