I have the following Powershell code which should send an email in the background and should wait till that email with the special attribute was also sent successfully. All works fine, but for any reason I cannot release the COM-object $sent after I used it in a loop or pipe. As a result the background process does not terminate as expected. How can I solve that problem?
Here the code-snippet:
cls
remove-variable * -ea 0
$ErrorActionPreference = 'stop'
# connect to existing outlook or start a new instance:
$i = [System.Runtime.Interopservices.Marshal]
Add-Type -AssemblyName "Microsoft.Office.Interop.Outlook"
try {
$o = $outlook = $i::GetActiveObject('Outlook.Application')
} catch {$o = New-Object -ComObject Outlook.Application}
# create email object:
$m = $o.CreateItem(0)
# set email properties:
$m.Subject = "Test"
$m.Body = "This is a test."
$m.To = "someone@somewhere.local"
# add a unique id to the mail:
$guid = [System.Guid]::NewGuid().guid
$id = $m.UserProperties.Add("guid",1)
$id.Value = $guid
$null = $i::ReleaseComObject($id)
# send the email and release the object:
$m.Send()
$null = $i::ReleaseComObject($m)
if ($outlook) {
# no need to wait here, because outlook is still running:
write-host "sending email initiated."
} else {
# wait till email with that id appears in "sent" (or timeout):
$timeout = 30
$sent = $o.Session.GetDefaultFolder(5).Items
do {
sleep 1
$sent.Sort("[SentOn]", $true)
# this loop gets the id of the last sent mail,
# but it blocks the release of $sent COM-object later.
# same issue when using a pipe with "select -first 1"
foreach($s in $sent){
$id = $s.UserProperties['guid'].value
break
}
$timeout -= 1
} until ($timeout -eq 0 -or $id -eq $guid)
# this does NOT release the object because I used it in the loop before:
$null = $i::ReleaseComObject($sent)
if ($id -eq $guid) {write-host "email sent."}
write-host "closing background process."
$o.Quit()
}
# release the outlook object
$null = $i::ReleaseComObject($o)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()