Delete emails from outlook via powershell - powershell

I'm trying to run a powershell script on a shared mailbox (Exchange). when I run the script on my personal mailbox it works, altough when I change it to the share one I only get error messages.
$outlook = new-object -comobject outlook.application
$logfile = $PSScriptRoot + "\email.log"
$namespace = $outlook.GetNameSpace('MAPI')
$folder = $namespace.Folders.Item('shared.mailbox#company.com').Folders.Item('Inbox')
$folder_2 = $namespace.Folders.Item('shared.mailbox#company.com').Folders.Item('Deleted Items')
$date_check = (get-date).AddDays(-1) | Get-Date -UFormat "%m-%d-%Y"
$date_check_deleted_items = (get-date).AddDays(-2) | Get-Date -UFormat "%m-%d-%Y"
$emailToDelete = $folder.items | Where-Object { $_.ReceivedTime -lt $date_check; }
$emptyDeletedItems = $folder_2.items | Where-Object { $_.ReceivedTime -lt $date_check_deleted_items; }
Get-Date | Out-File $logfile -Append
"Amount of emails being deleted:" | Out-File $logfile -Append
$emailToDelete.Count | Out-File $logfile -Append
"Subject of Emails in the Inbox folder:" | Out-File $logfile -Append
$emailToDelete.subject | Out-File $logfile -Append
"Amount of emails being deleted from deleted items:" | Out-File $logfile -Append
$emptyDeletedItems.Count | Out-File $logfile -Append
"Subject of Emails in the Deleted Items folder folder:" | Out-File $logfile -Append
$emptyDeletedItems.subject | Out-File $logfile -Append
write-host "Emails received before" $date_check "(MM/dd/YYYY) will be deleted"
write-host "deleting emails in 5"
Start-Sleep -s 1
write-host "deleting emails in 4"
Start-Sleep -s 1
write-host "deleting emails in 3"
Start-Sleep -s 1
write-host "deleting emails in 2"
Start-Sleep -s 1
write-host "deleting emails in 1"
Start-Sleep -s 1
write-host "deleting" $emailToDelete.Count "emails"
#$EmailToDelete.Delete()
write-host $emptyDeletedItems.count "Emails to be deleted from the deleted items folder"
write-host "Emails received before" $date_check_deleted_items "(MM/dd/YYYY) will be deleted from that folder"
$emptyDeletedItems.Delete()
write-host $emailToDelete.count "Emails are deleted from the Inbox folder and" $emptyDeletedItems.count "Emails are deleted from the Deleted Items folder, application will close in 5 seconds"
Start-Sleep -s 5
I'm receiving the following errors:
The attempted operation failed. An object could not be found.
At C:\Users\username\Desktop\emails.ps1:7 char:1
+ $folder = $namespace.Folders.Item('shared.mailbox#company.com').Fold ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
The attempted operation failed. An object could not be found.
At C:\Users\username\Desktop\emails.ps1:9 char:1
+ $folder_2 = $namespace.Folders.Item('shared.mailbox#company.com').Fo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
Could you help me what am I doing wrong?

I'm trying to run a powershell script on a shared mailbox (Exchange)
Not exactly so. You are trying to automate Outlook with a shared mailbox. And the account is configured locally in Outlook. It seems you can't access it form a shared location.
Another aspect is that Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution.
Read more about that in the Considerations for server-side Automation of Office article.

Related

Powershell loops for syslog management

If I run the script below it will perform all the tasks that I need it to. I need the task to run every 15 seconds in a loop. When I add a loop of any type, the loop gets stuck on only a portion of the script an no longer functions as expected. I'm looking to loop the entire script top to bottom. The current script does not have any loops at this time. Any help would be greatly appreciated.
# Syslog Management. Automate has a max size of 977KB before it dumps everything into a file called Syslogold.txt
# If Syslogold.txt already exists it will be overwriten and logs will be gone.
# Script below will move syslogold.txt into syslog folder where it will be renamed to Syslog-(CurrentDate).TxT
# When ever a new Syslogold.txt is generated by Automate, this script will append the output to a daily file in a monthly folder.
# On the first day of every month, the previous month will be zipped and archived.
#
$LastMonth = (Get-Date).AddMonths(-1).ToString('MMM-yyyy')
$CurrentSyslogFolder = "C:\Windows\LTsvc\Syslogs\Syslogs-$(Get-Date -Format "MMM-yyyy")"
$OldDirectory = "C:\Windows\LTsvc\Syslogs\Syslogs-$LastMonth"
$CurrentLog = "Syslog-$(Get-Date -Format "dd-MMM-yyyy").txt"
$OldLog = "C:\Windows\LTSvc\syslogold.txt"
$SyslogArchive = "C:\Windows\LTSvc\Syslogs\Archive\Syslog-$LastMonth.zip"
do{
$TestPath01 = Test-Path -Path $CurrentSyslogFolder
$TestPath02 = Test-Path -Path $CurrentSyslogFolder\$CurrentLog
$TestPath03 = Test-Path -Path $OldLog
$TestPath04 = Test-Path -Path $OldDirectory
if($TestPath01)
{
write-host "Syslog directory current."
}
else
{
write-host "Current syslog directory is for last month. Creating new folder."
New-Item -ItemType Directory -Force -Path $CurrentSyslogFolder
}
if(($TestPath02) -and ($TestPath03))
{
write-host "Automate syslog archive found"
write-host "Daily syslog Found."
write-host "Appending Automate archive with daily syslog"
Add-Content -Path $CurrentSyslogFolder\$CurrentLog -Value ""
Get-Content -Path $OldLog | Add-Content -Path $CurrentSyslogFolder\$CurrentLog
Remove-Item -Path $OldLog
start-sleep -Seconds 15
}
else
{
write-host "Automate syslogs active."
write-host "Waiting for Automate to archive syslogs."
if ($TestPath03)
{
Write-Host "Automate has completed archiving Syslogs."
Write-Host "Moving archive to daily syslog."
Write-host "Daily syslog missing. Creating daily syslog now"
Move-Item $OldLog -Destination $CurrentSyslogFolder\$CurrentLog
}
}
if($TestPath04)
{
write-host "Last months directory found."
Write-Host "Compressing last months directory"
Compress-Archive -Path "$OldDirectory" -DestinationPath "$SyslogArchive"
Write-host "Moving compressed directory to archive"
Write-host "Cleaning up files"
Remove-Item -Path "$SyslogDirectory\Syslogs-$LastMonth" -Recurse
Write-host "Cleanup completed"
start-sleep -Seconds 15
}
else
{
Write-host "Will try again in 15 seconds"
start-sleep -Seconds 15
}
}until($infinity)
To be honest the best way would be Scheduled Task ScheduledTask
But you can also use do or while
do{ YOURSCRIPT start-sleep -Seconds 15 }until($infinity)

Issue while exporting output to CSV in PowerShell Parallel Workflow

I am using below script to get the details about port status of multiple remote servers.
Workflow Test-OpenPortWF
{
[CmdletBinding()]
param
(
[Parameter(Position=0)]
[String[]]$Target,
[Parameter(Mandatory=$true, Position=1)]
[int]$Port
)
If(Test-Path -Path C:\Temp\Results.csv -ErrorAction SilentlyContinue){ Remove-Item -Path C:\Temp\Results.csv -Force }
If(Test-Path -Path C:\Temp\Report.csv -ErrorAction SilentlyContinue){ Remove-Item -Path C:\Temp\Report.csv -Force }
foreach -parallel -throttle 50 ($t in $Target)
{
Sequence
{
$Out = Test-NetConnection -ComputerName $t -Port $Port -WarningAction SilentlyContinue | Select ComputerName,RemoteAddress,RemotePort,#{N="PortTestSucceeded"; E={$_.tcpTestSucceeded}}
Start-Sleep -Milliseconds 100
$Out | Export-Csv -Path C:\Temp\Results.csv -NoTypeInformation -Append
}
}
InlineScript
{
Import-Csv c:\Temp\Results.csv | Select ComputerName,RemoteAddress,RemotePort,PortTestSucceeded | Export-Csv c:\Temp\Report.csv -NoTypeInformation
Remove-Item c:\Temp\Results.csv -Force
Write-Host "Execution completed! Check Report.csv for output."
}
}
# Example use for multiple servers for one port 5985 and export results to CSV file.
# Assuming all target servers are found in c:\temp\Servers.txt (new line separated)
#
# PS C:\Temp> Test-OpenPortWF -Target (Get-Content .\Servers.txt) -Port 5985
Mostly it is working but it is not able to give complete results because since we are running this as a parallel workflow, if two servers complete the processing at the same time it will try to write the results to the CSV file at once for both the servers which is resulting in below error. And around 6% results are missing in the CSV file:
Microsoft.PowerShell.Utility\Write-Error : The process cannot access
the file 'C:\Temp\Results.csv' because it is being used by another
process. At Test-OpenPortWF:54 char:54
+
+ CategoryInfo : NotSpecified: (:) [Write-Error], CmdletInvocationException
+ FullyQualifiedErrorId : System.Management.Automation.CmdletInvocationException,Microsoft.PowerShell.Commands.WriteErrorCommand
+ PSComputerName : [localhost]
How can we get around this problem?
Because you use parallel processing, there may be conflicts when multiple threads try to output to your csv file (you run into file locks judging by the error)
Instead, try to output to single temporary files (with unique names) and at the end merge those files into one single report (and delete the temp files)
For example add a counter ($x) in the foreach loop that increments with every iteration ( $x++ ) , then output the results to -Path "C:\Temp\Results_$x.csv"
You need to use a mutex to lock the file I/O operation. Modify your Sequence as such:
Sequence
{
$Out = Test-NetConnection -ComputerName $t -Port $Port -WarningAction SilentlyContinue | Select ComputerName,RemoteAddress,RemotePort,#{N="PortTestSucceeded"; E={$_.tcpTestSucceeded}}
$mutex = New-Object System.Threading.Mutex $false, 'NetConnectionTest'
$mutex.WaitOne() > $null;
$Out | Export-Csv -Path C:\Temp\Results.csv -NoTypeInformation -Append
$mutex.ReleaseMutex();
}

Registry change isn't silent

When ran with elevated privileges, the code does what it is supposed to do by turning off the laptop's onboard microphone, but it needs to be totally silent. This will be sent out to over 1600 systems. It will be pushed via logon script to the local systems. So it needs to run as Admin and without any user intervention. How do I keep it running elevated and how to get it to run without the UAC prompt?
-TIA
$audioCaptureRegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture"
$MICS = Get-Item $audioCaptureRegPath
$MICS.GetSubKeyNames() | % {`
if($(Get-ItemProperty -Path $audioCaptureRegPath"\"$_).DeviceState -eq 1 ){`
$systemNameData=$(Get-ItemProperty -Path $audioCaptureRegPath"\"$_\Properties).$systemNameVal
if(!($systemNameData -match "plant") -or !($systemNameData -match "HDX"))
{
$tmpFileFullPath = [System.io.Path]::getTempFileName()
"Windows Registry Editor Version 5.00" | Out-File -FilePath $tmpFileFullPath -Append
" " | Out-File -FilePath $tmpFileFullPath -Append
"[$($MICS.Name)\$_]" | Out-File -FilePath $tmpFileFullPath -Append
"`"DeviceState`"=dword:10000001" | Out-File -FilePath $tmpFileFullPath -Append
" " | Out-File -FilePath $tmpFileFullPath -Append
regedit.exe /S $tmpFileFullPath
}
}
}

File Output issue in PowerShell

Trying to write to a log file assigned to a variable in PowerShell, like so-
Code:
$Time = Get-Date
$FileTimeStamp = (Get-Date -f MM-dd-yyyy_HH.mm.ss)
$ErrorLog | out-file $(".\Logs\" + $FileTimeStamp + "_PushLog.log") -append
"Script started at $Time" | out-file $ErrorLog -append
Compile error-
Out-File : Cannot bind argument to parameter 'FilePath' because it is null.
At C:\OSM\Scripts\FilePush\FilePush.ps1:56 char:37
+ "Script started at $Time" | out-file <<<< $ErrorLog -append
+ CategoryInfo : InvalidData: ( [Out-File], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.OutFileCommand
What am I doing wrong? Am I getting there? It's now correctly writing one file instead of two, but the log doesn't contain the string "Session started at $Time".
Code:
$Time = Get-Date
$FileTimeStamp = (Get-Date -f HH.mm.ss_MM-dd-yyyy)
$ErrorLog = out-file $(".\Logs\" + $FileTimeStamp + "_PushLog.log") -append
$ErrorLog = [io.path]::GetFileName("$ErrorLog.FullName")
"Session started at $Time" | out-file $ErrorLog -append
The whole point of what I'm trying to do is create a variable for an error file that I can reference when I want to output text to it. I only want log each time the script runs, but that seems to be an issue when I;'m appending the time to the file name. How do I work past this?
Bob answered the question but really didn't help provide a solution, so I'll add an answer.
The issue is that when you try to define your $ErrorLog variable you're overthinking it. You just need to create a string that defines where the file is located, not have all the Out-File and -Append on that line.
$Time = Get-Date
$FileTimeStamp = (Get-Date -f MM-dd-yyyy_HH.mm.ss)
$ErrorLog = ".\Logs\$FileTimeStamp_PushLog.log"
"Script started at $Time" | out-file $ErrorLog -append
You haven't defined $ErrorLog.

get script to work on remote servers

I want the below code to work on multiple computers - any idea how to do this? I have the below but it fails as I do not currently call in the servers in question I think.
Thanks,
CODE:
Write-Host "Script to check Storage Write, Read and Delete Times"
Write-Host "`n"
$computer = Get-Content -path d:\temp\servers.txt
$path = "f:\temp\test.txt"
Foreach ($storage in $computer)
{
$date = Get-Date
Write-Host "Script being run on $date"
$write = Measure-Command { new-item -Path $path -ItemType File -Force } | select TotalMilliseconds
Write-Host "Writing file on $storage took $write"
$read = Measure-Command { Get-Content -Path $path } | select TotalMilliseconds
Write-Host "Reading file on $storage took $read"
$delete = Measure-Command {Remove-Item -Path $path -Force } | select TotalMilliseconds
Write-Host "Deleting file on $storage took $delete"
Write-Host "`n"
}
You need to step back for a second an rethink the approach. You are issuing the filesystem commands every time to f:\temp, which is on your local system.
There are two ways to make remote computers perform filesystem tasks. The easiest way is to use UNC paths. That is, \\server\share format. Assuming you have local admin access:
Foreach ($storage in $computer) {
$uncpath = $("\\{0}\f`$\temp\text.txt" -f $storage)
$write = Measure-Command { new-item -Path $uncpath -ItemType #...
# rest of code uses $uncpath for access
}
Mind you, using UNC path puts some stess on LAN, so this type of testing might or might not be accurate enough.
The second way would be using Powershell remoting to connect on remote systems and issuing the commands there. Take a look at New-PSSession, Enter-PSSession and Exit-PSSession cmdlets.