Display duration of outlook appointment? - powershell

I am unable to display the duration of each appointment in my list box. I'm trying to print in the listbox 11:30; (60) B/H or 11:30-12:30; B/H, however unsure of how to do this, please may someone help?
I have tried $Duration and $._Duration, putting them between "[...]Start.ToString('HH:mm'), $_.Subject } " 'HH:mm' and $_. subject however these haven't been successful
#listbox for calendar entry
$Listboxcal= New-Object System.Windows.Forms.ListBox
$Listboxcal.Location = New-Object System.Drawing.Size(10,55)
$Listboxcal.Size = New-Object System.Drawing.Size(80,270)
$Listboxcal.Height = 150
add-type -assembly “Microsoft.Office.Interop.Outlook” | out-null
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace(“MAPI”)
# https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.outlook.oldefaultfolders?view=outlook-pia
# Calendar = olFolderCalendar = 9
$calendar = $namespace.GetDefaultFolder(9)
# get today's calendar items!
$cItems = $calendar.Items | Where-Object {$_.Start -ge $(Get-Date $StrCaldate) -and $_.Start -le $(Get-Date $StrCaldate).AddDays(1)} |Sort-Object -Property Start | foreach { "{0}; {1}" -f $_.Start.ToString('HH:mm'), $_.Subject }
ForEach ($calendars in $cItems) {[void]$Listboxcal.Items.Add($calendars)}

The calendar appointments have a duration property. You just need to add that to the $cItems variable
$cItems = $calendar.Items | Where-Object {$_.Start -ge $(Get-Date $StrCaldate) -and $_.Start -le $(Get-Date $StrCaldate).AddDays(1)} |Sort-Object -Property Start | foreach { "{0}; ({1}) {2}" -f $_.Start.ToString('HH:mm'), $_.Duration, $_.Subject }
When I run this on my own calendar, I get the following:
16:30; (60) Appointment 1
18:30; (120) Appointment 2

It is working for me with the Duration property:
$calendar.Items | Select -First 1 | %{ $_.StartUTC.Tostring("hh:mm") `
+ "; (" + $_.Duration + ") " + $_.Subject}

Related

How to get outlook recurring meeting items in powershell

I am using below script to pull outlook calendar items and it works for events that occur once. It fails for recurring meeting invites as the start date on it would be when the invite was sent and not the occurrence start time. Also, i dont see any variable referencing the occurrence end date, so cant dynamically lookup for the occurrence. Any suggestions on how to get that?
Function Get-OutlookCalendar {
Add-type -assembly “Microsoft.Office.Interop.Outlook” | out-null
$olFolders = “Microsoft.Office.Interop.Outlook.OlDefaultFolders” -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace(“MAPI”)
$folder = $namespace.getDefaultFolder($olFolders::olFolderCalendar)
$folder.items |
Select-Object -Property start,RequiredAttendees, Subject, IsRecurring, Organizer,ConversationID,RecurrenceState,OptionalAttendees,Body
}
$start_date=(Get-date).AddDays(-2) |Get-Date -Format 'MM/dd/yyyy'
$end_date=Get-Date -Format 'MM/dd/yyyy'
Get-OutlookCalendar| where-object { $_.start -gt [datetime]$start_date -and $_.start -le [datetime]$end_date } | sort-object start
You can try below switch:
switch ($item.IsRecurring)
{
$false {
if ($item.start -ge $dt -and $item.start -lt ($dt).AddDays(1))
{
$item | Select-Object -Property Subject, Start, Duration, Location, RequiredAttendees
}
}
$true {
try {
$rec=$item.GetRecurrencePattern()
$recitem=$rec.GetOccurrence($dt.ToString("yyyy-MM-dd") + " " + $item.Start.ToString("HH:mm"))
$recitem | Select-Object -Property Subject, Start, Duration, Location, RequiredAttendees, IsRecurring
}
catch {}
finally {}
}
}

PowerShell won't iterate through a document

A PowerShell script won't iterate through a document to change each hyperlink in the document.
The script runs through a document library on SharePoint online and can open each document in the library. Then it should iterate through each document and pull any hyperlinks that it finds and then split the hyperlink into two parts. The script should then add the second half onto a new URL and update the Address to be the new, updated URL.
add-type -AssemblyName "Microsoft.Office.Interop.Word"
$wdunits = “Microsoft.Office.Interop.Word.wdunits” -as [type]
$donotsave = “Microsoft.Office.Interop.Word.wdDoNotSaveChanges” -as [type]
$save = “Microsoft.Office.Interop.Word.wdSaveChanges” -as [type]
$application = New-Object -ComObject Word.Application
$application.Visible = $false
$tenancy = "https://tenancy.sharepoint.com"
$url = "https://tenancy.sharepoint.com/sites/siteName/"
Connect-PnPOnline -Url $url -UseWebLogin
$library = Get-PnPList | Where-Object {$_.Title -eq "libraryName"}
$items = Get-PnPListItem -List $library
foreach ($item in $items) {
if ($item["FileLeafRef"] -match ".doc*") {
Write-Host "File Name: "$item["FileLeafRef"]
$item["FileLeafRef"]
$item["FileRef"]
Write-Host `
$documentLocation = "https://tenancy.sharepoint.com"+$item["FileRef"]
$documentLocation
$document = $application.Documents.Open($documentLocation)
$docURLS = #($document.Hyperlinks)
$docURLS | foreach{
Start-Sleep -Seconds 7
$newURI = ([uri]$_.address).AbsoluteUri
$result = $newURI.Split("=") | Select-Object -Skip 1 -First 1
$result
$newUrl = "https://tenancy.sharepoint.com/sites/siteName/_layouts/DocIdRedir.aspx?ID="+$result
$_.address = $newUrl
Write-Verbose ("Updating {0} to {1}" -f $_.Address,$newUrl) -Verbose
}
$document.save()
$document.close([Ref]$save)
$item.File.Update()
}
}
$application.quit()
Disconnect-PnPOnline
The script can currently iterate through the library and open each document, the issue comes when there are multiple hyperlinks in the document.
It changes the first URL correctly, but every other link after that receives the following errors:
Object has been deleted.
At C:\filepath.ps1 :36 char:5
+ $_.address = $newUrl
The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED))
At C:\filepath.ps1:39 char:9
+ $document.save()
The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED))
At C:\filepath.ps1:40 char:9
+ $document.close([Ref]$save)
You cannot call a method on a null-valued expression.
At C:\filepath.ps1:33 char:5
+ $result = $newURI.Split("=") | Select-Object -Skip 1 -First 1
If the $_.address value like "/sites/team?ID=1", the $newURI will null, then run $newURI.Split("=") | Select-Object -Skip 1 -First 1 will get "You cannot call a method on a null-valued expression".
You can check if the $newURI is null before use $newURI.Split method.
Or we can replace the code below.
$newURI = ([uri]$_.address).AbsoluteUri
$result = $newURI.Split("=") | Select-Object -Skip 1 -First 1
with
if($_.Address)
{
$result = $_.Address.Split("=") | Select-Object -Skip 1 -First 1
}
else
{
$_
}

how to access email from a shared outlook mailbox

I need to get a the latest email from a shared outlook mailbox.
The shared inbox is eg. "Server Backup" and the email that i want to get is located
inbox\backup report\
Here is some code that I can access my Inbox but can't do it for a subfolder
$Outlook = New-Object -ComObject Outlook.Application
$OutlookFolders = $Outlook.Session.Folders.Item(1).Folders
$OutlookInbox = $Outlook.session.GetDefaultFolder(6)
#read the latest email
$latestmail=$OutlookInbox.items | select -last 1
What you are after is to navigate a little further down.
$outlook = New-Object -Com Outlook.Application
$MAPI = $Outlook.GetNamespace("MAPI")
# Gets all mailboxes tied to the account
$Mailbox = $MAPI.Folders("SharedEmail#Company.com")
# Gets the Inbox folder
$Inbox = $mailbox.Folders("Inbox").Folders("backup report")
# Shows all emails from the Inbox
$contents = $Inbox.Items
$contents.Sort("ReceivedTime", $true)
$contents | select Subject, SenderName, CreationTime -First 1
EDIT: Since the above didn't work, try the below. It will search for the Inbox, then pipe that through to look for the Server Backup.
$Outlook = New-Object -ComObject Outlook.Application
$OutlookFolders = $Outlook.Session.Folders.Item(1).Folders
(($OutlookFolders | Where-Object {$_.FolderPath -like "*Inbox*"}).Folders | `
Where-Object {$_.FolderPath -like "*Server Backup*"}).Items | `
select Subject, SenderName -Last 1
$outlook = New-Object -comobject outlook.application
$namespace = $outlook.application.GetNamespace("MAPI")
$folder = $namespace.GetDefaultFolder(6)
#goto the inbox\backup eport and select the latest email and place it in variable
#$newreport
$newreport = $namespace.Folders.Item("Server
Backup").Folders.Item('Inbox').Folders.item('backups').items | select -first 1
Add-Type -assembly "Microsoft.Office.Interop.Outlook"
Add-Type -assembly "System.Runtime.Interopservices"
$outlook = new-object -com outlook.application;
$namespace = application.GetNameSpace("MAPI")
$i = 1
$Sender = "abc#123.com" # email id
$Sender1 = "cde#123.com" # email id
$myRecipient = $namespace.CreateRecipient("Email Id") # Email id of the shared mail box
$inbox = $Namespace.GetSharedDefaultFolder($myRecipient ,[Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
# Save email contect to a file in a location
$inbox.Items | ?{$_.SenderName -match $Sender -and $_.UnRead -eq "No" } | sort receivedtime -desc |
%{
$Filepath = "C:\temp\" + "email" + $filecount +".txt"
echo $_.body | Out-File -FilePath $Filepath #do stuff with body
$i = $i + 1
$filecount = " (" + $i + ")"
$_.Unread= $False #mark as read
}
# Save email attachment to a location
$inbox.Items | ?{$_.SenderName -match $Sender1 -and $_.UnRead -eq "No" } | sort receivedtime -desc |
%{
$Filepath = "C:\Temp\"
$_.attachments| ?{$_.saveasfile((Join-Path $filePath $_.FileName)) }
$_.Unread= $False #mark as read
}

How to concatenate a value to Select-Object's output

I have a script which finds snapshots that are older than 3 days and below are my code and output. However I want to add a new column for each VM displaying the actual age of that snapshots, say for example 5 days or 4 days. I have tried getting age by subtracting created date from today's date. But I am not sure how to add it as a column to my output.
I used this to calculate age:
$StartDate = Get-Date
$created = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object Created
$age = New-Timespan -Start $StartDate -End $created
Full code:
Add-PSSnapin VMware.VimAutomation.Core
# HTML formatting
$a = "<style>"
$a = $a + "BODY{background-color:white;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;foreground-color: black;background-color: LightBlue}"
$a = $a + "TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;foreground-color: black;background-color: white}"
$a = $a + "</style>"
Connect-VIServer -Server ***** -User ****** -Password ******
# Main section of check
Write-Host "Checking VMs for for snapshots"
$date = Get-Date
$datefile = Get-Date -UFormat '%m-%d-%Y-%H%M%S'
$filename = "C:\Temp\snaps_older_than_3\" + $datefile + ".htm"
$created = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object Created
$age = New-Timespan -Start $StartDate -End $created
$ss = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object vm, name, SizeGB, SizeMB, Created, powerstate + $age |
ConvertTo-HTML -Head $a -Body "<H2>VM Snapshot Report </H2>"|
Out-File $filename
Write-Host " Complete " -ForegroundColor Green
Write-Host "Your snapshot report has been saved to:" $filename
$SMTPServer = "*******"
$SMTPPort = 25
$username = "vcenter#mmmm.com"
#Define the receiver of the report
$to = "mmmmm#hcl.com"
$subject = "VM Snapshot Report"
$body = "VM Snapshot Report"
$attachment = New-Object Net.Mail.Attachment($filename)
$message = New-Object System.Net.Mail.MailMessage
$message.Subject = $subject
$message.Body = $body
$message.To.Add($to)
$message.From = $username
$message.Attachments.Add($attachment)
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $false
$smtp.Send($message)
Write-Host "Mail Sent"
Output:
I want to add a new column named "age".
Use a calculated property:
Get-VM |Select-Object VM,Name,SizeGB,SizeMB,Created,PowerState,#{Name='Age';Expression={New-TimeSpan -Start $StartDate -End $_.Created}}
From the help text for Select-Object:
-Property
Specifies the properties to select. Wildcards are permitted.
The value of the Property parameter can be a new calculated property.
To create a calculated property, use a hash table. Valid keys are:
Name (or Label) <string>
Expression <string> or <script block>

Powershell Get-ChildItem

I have a powershell script I wrote to check the contents of a folder and if there is a file with a LastWriteTime older than 20 minutes to notify me. The problem I am having is when I get the results it is including all of the files in the email body. How would I write this to get only the latest filename in the email body?
$src = 'c:\test'
$sendmail = $false
Get-ChildItem -path $src | ForEach-Object {
#write-host $_.fullname
$dtdiff = New-TimeSpan ($_.LastWriteTime) $(Get-Date)
if ($dtdiff.TotalMinutes -gt 20){
$strbody=$strbody +$_.fullname+ " Last File Modified at " +$_.LastWriteTime +"`r`n"
$sendmail=$true
}
}
#$strbody
if($sendmail -eq $true){
# Email components
$strFromAddress = "abc#xyz.net"
$strToAddress = "abc#xyz.net"
$strMessageSubject = "REPORT"
$strMessageBody = $strbody
$strSendingServer = "smtp.com"
$SMTPPort = "587"
$emailSmtpUser = "abc#xyz.net"
$emailSmtpPass = "test123"
# Email objects
$objSMTPMessage = New-Object System.Net.Mail.MailMessage $strFromAddress, $strToAddress, $strMessageSubject, $strMessageBody
$objSMTPClient = New-Object System.Net.Mail.SMTPClient( $strSendingServer, $SMTPPort )
$objSMTPClient.EnableSsl = $true
$objSMTPClient.Credentials = New-Object System.Net.NetworkCredential( $emailSmtpUser , $emailSmtpPass );
$objSMTPClient.Send($objSMTPMessage)
}
To get only the most actual file: Edited to remove flaw
Get-ChildItem -path $src |
Sort LastWriteTime |
Select -last 1 |
ForEach-Object {
#write-host $_.fullname
$dtdiff = New-TimeSpan ($_.LastWriteTime) $(Get-Date)
if ($dtdiff.TotalMinutes -gt 20){
$strbody=$strbody +$_.fullname+ " Last File Modified at " +$_.LastWriteTime +"`r`n"
$sendmail=$true
}
}
You're appending each filename and its associated timestamp to $strbody in that loop. It's doing exactly what you specified.
If you want only the latest file that was created in the last 20 minutes, change your get-childitem/foreach loop to this:
$mostrecentfile = get-childitem -path $src |
where-object {$_.lastwritetime -gt (get-date).addminutes(-20)} |
sort-object -property lastwritetime -descending | select-object -first 1
}
if ($mostrecentfile -ne $null) {
$strbody=$_.fullname+ " Last File Modified at " +$_.LastWriteTime;
$sendmail = $true;
}
get-childitem "c:\temp" -file | where LastWriteTime -le (Get-Date).AddMinutes(-20) |
Sort lastwritetime -descending |
% {
$strFromAddress = "abc#xyz.net"
$strToAddress = "abc#xyz.net"
$strMessageSubject = "REPORT"
$strMessageBody = "Last file modifed '{0}' at {1}" -f $_.fullname, $_.LastWriteTime
$strSendingServer = "smtp.com"
$SMTPPort = "587"
$emailSmtpUser = "abc#xyz.net"
$emailSmtpPass = "test123"
# Email objects
$objSMTPMessage = New-Object System.Net.Mail.MailMessage $strFromAddress, $strToAddress, $strMessageSubject, $strMessageBody
$objSMTPClient = New-Object System.Net.Mail.SMTPClient($strSendingServer, $SMTPPort )
$objSMTPClient.EnableSsl = $true
$objSMTPClient.Credentials = New-Object System.Net.NetworkCredential( $emailSmtpUser , $emailSmtpPass );
$objSMTPClient.Send($objSMTPMessage)
$objSMTPClient.Dispose()
break
}