Invoke verb on multiple files via Shell.Application - powershell

I'm using "Shell.Application" COM object for some automation via PowerShell and I'm stuck on situation where I need to invoke verb on multiple items in folder. Basically I need to simulate situation where user selects multiple files/folders and calls verb from shell menu.
I can do it without any problem on single item, but I haven't found method how to call it on multiple items. Any idea how to do it?
Edit:
This is how I call it on single item:
$shell = New-Object -Com "Shell.Application"
$shell.Namespace($Path).Self.InvokeVerb("some action")

You can use InvokeVerbEx to execute on all files in a folder:
$shell.Namespace("C:\test").Items().InvokeVerbEx()
For particular files in a folder, I would think the best way is to put the single item code that you have in a loop:
$path1, $path2 | %{ $shell.Namespace($_).Self.InvokeVerb() }
The Filter method may be of use too

Related

Powershell Set Unread flag for Outlook Desktop emails

I am trying to read emails from a folder in Outlook Desktop using powershell, and I can do that with the code below.
But is there any way by which I could also set the Unread property to $False for those emails
directly in outlook ? ( not in the objects stored in variables )
Browsing the website I found this: https://stackoverflow.com/a/34161683/13568461 which says to use MailItem.Save but I cant figure it out how to update my code to make use of that.
Much appreciated if anyone can help with that piece of code. Thank you in advance
Add-Type -assembly "Microsoft.Office.Interop.Outlook"
$Outlook = New-Object -comobject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$Folder_AI = $namespace.Folders.Item('user#domain').Folders.Item('AI-ServiceDesk-Servers')
$Count_ItemsUnread = $Folder_AI.UnReadItemCount
$All_Folder_Items = $Folder_AI.Items | Select-Object -Property UnRead, Body
$All_Folder_Items | ForEach-Object {
$Email_Status = $PSItem.Unread
$Email_Body = $PSItem.Body
$Email_Status
}
But is there any way by which I could also set the Unread property to $False for those emails directly in outlook ? ( not in the objects stored in variables )
No, you need to get an item to set up a property. The Save method is required to make changes permanent and avoid any dialogs for saving changes made programmatically in Outlook.
When dealing with Exchange accounts in Outlook you may reach the limit of concurrently opened items if you iterate over all items in the folder/store. That is why Find/FindNext or Restrict methods are recommended. They allow getting items that correspond to your search criteria and iterate over them only. Read more about these methods in the article that I wrote for the technical blog:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder

How to Delete Outlook Item in Archive.pst

I'm stucked, i'm able to connect a pst file in Outlook, I would like to loop through all folders / search a certain email with a certain subject and then, delete it. I've searched through the web but don't know how to start, can someone explain me plz ? I'm lost with $namespace.folders.item.
Clear-host
Add-Type -Assembly "Microsoft.Office.Interop.Outlook"
$Outlook = New-Object -ComObject Outlook.Application
$Namespace = $Outlook.GetNameSpace("MAPI")
$folders = "C:\Tools\Archive.pst"
$namespace.AddStore($folder)
I'm thinkin' about this but I know i'm wrong :
$email = $folders.Folders.items | Where-Object {$_.Subject -like "*alert*"} OR
Foreach ($Folder in $SubFolder.Folders)
{
$ItemsToDelete = $Folder.Items | Where-Object -Property subject -like "*alert*"
foreach ($item in $ItemsToDelete)
{
$item.Delete()
}
}
(all articles at Microsoft's are related to VB which I don't know and i'm starting Powershell : https://learn.microsoft.com/en-us/office/vba/api/outlook.namespace.addstore)
Thx for your advices.
After adding a new store in Outlook you can find it in the Stores collection which you may get by using the Stores property of the Namespace class. Use the Stores and Store objects to enumerate all folders and search folders on all stores in the current session. The following VBA sample code shows how you can use these objects to iterate over all stores and folders in Outlook:
Sub EnumerateFoldersInStores()
Dim colStores As Outlook.Stores
Dim oStore As Outlook.Store
Dim oRoot As Outlook.Folder
On Error Resume Next
Set colStores = Application.Session.Stores
For Each oStore In colStores
Set oRoot = oStore.GetRootFolder
Debug.Print (oRoot.FolderPath)
EnumerateFolders oRoot
Next
End Sub
Private Sub EnumerateFolders(ByVal oFolder As Outlook.Folder)
Dim folders As Outlook.folders
Dim Folder As Outlook.Folder
Dim foldercount As Integer
On Error Resume Next
Set folders = oFolder.folders
foldercount = folders.Count
'Check if there are any folders below oFolder
If foldercount Then
For Each Folder In folders
Debug.Print (Folder.FolderPath)
EnumerateFolders Folder
Next
End If
End Sub
Note, the Outlook object model is common for all programming languages, so you may find the sequence of property and methods calls in the sample shown above.
To find items that correspond to your conditions you need to use the Find/FindNext or Restrict methods of the Items class. In that case you will get only items that correspond to the search criteria and then you can iterate over them only. Read more about these methods in the articles I wrote for the technical blog:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
If you need to find items in multiple folders I'd recommend choosing the AdvancedSearch method of the Application class instead. The key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.
See Advanced search in Outlook programmatically: C#, VB.NET for more information.

Powershell automation, email MS-Access Query

At an impasse, (a complete loss as to where to go next)
I am building a powershell script to automate a number of manual tasks one of which is to run a query within access and then email that object to a number of recipients.
The closest I have got to was running
$Acc = New-Object -com Access.Application
$Acc.OpenCurrentDataBase("L:\Operations Database\OPS\OPS-V2.0.accdb")
##Test email object
$Acc.DoCmd.RunMacro("EmailLiveFNZ")
This ran the macro that I had produced in Access but I was then required to manually click on an Outlook warning box so it has not resolved the issues.
I have then started playing around with various versions of the following script but can't get it to work.
$Acc = New-Object -com Access.Application
$Acc.OpenCurrentDataBase("L:\Operations Database\OPS\OPS-V2.0.accdb")
##Test email object
$Acc.DoCmd.SendObject acSendQuery, "LiveFNZFundXfer", acFormatXLS, _
"email#address.com", , , _
"Live Transfers", , False
I am assuming that I can send the query out using powershell automatically I just can't find the assistance I need online...
Alternatively if anyone knows how to save an access object to a specific folder location on a PC I could have the script email the file from there, I can't work it out...
Thanks for your help!
Regards
R
I also tried;
$Acc = New-Object -com Access.Application
$Acc.OpenCurrentDataBase("L:\Operations Database\OPS\OPS-V2.0.accdb")
##Test export object
$Acc.DoCmd.OpenQuery("LiveFNZFundXfer") | Export-CSV "C:\LiveFNZFundXfer.csv"
This compiles without errors but does not export anything

Create a particular type of link between two WorkItem's in TFS using PowerShell

I am creating test cases (Test Case type of task) in PowerShell and I am trying to link them to a story (Product Backlog Item) as "Test Cases" and not as ordinary links.
Suppose $WIT is the WorkItemStore and $testcaseId and $storyId are valid IDs.
If I do:
$testCase = $WIT.GetWorkItem($testcaseId)
$workitem.Links.Add($storyId)
$workitem.Save()
I will have a bunch of "normal" links from the test case to the story, which is not what I want.
In C#, this seems to be achievable by creating a new RelatedLink and specifying the type of the link. Here's a snippet (more info here)
source.Links.Add(new RelatedLink(linkTypeEnd, approval.Id));
Is there any way to do the same in PowerShell?
You can do it in Powershell the same way that you do it in C#... that's the awesome power of PowerShell :)
[Microsoft.TeamFoundation.WorkItemTracking.Client.Hyperlink]$NewLink = New-Object -TypeName Microsoft.TeamFoundation.WorkItemTracking.Client.Hyperlink -ArgumentList $newlocation
$wit.Links.Add($NewLink)
I first use the PowerShell function above to pull in the relevant DLL's then I have access to the Above is the code to create and add a new Hyperlink. From this you should be able to easily create other types of links.

Powershell com object with parameters

I want to write a powershell script that will open an Internet Explorer instance as a com object so i can manipulate it. The problem is I need to run it with a parameter to make sure IE is run as a new session.
The parameter I need to pass is -noframemerging I need to pass this so each instance is a new session. Here is the code I've been using to get the instance started.
$ie = new-object -com "InternetExplorer.Application"
If someone could give me a hand figuring out how to be able to create multiple objects as a new session in IE that would be fantastic!
Here is my solution:
$IEProcess = [System.Diagnostics.Process]::Start("iexplore", "-noframemerging")
Sleep -Seconds 1
$ie = $(New-Object -ComObject "Shell.Application").Windows() | ? {$_.HWND -eq $IEProcess.MainWindowHandle}
I launch an instance with the System.Diagnostic.Process library, I was using Start-Process but getting some weird outcomes, this fixed that right up. At this point I have an instance of IE open with the noframemerging switch and a variable pointing the process.
I threw a sleep in there to give the com object a chance to construct before trying to reference it.
Then I grab all the windows com objects and select the one that has a handle (HWND) that is the same as the one from the process I just started and assign it to my $ie variable.
The end result is I have a variable that references a com object of Internet Explorer that is independent of all other sessions. The reason I needed this in particular is I'm opening many instances of IE and logging into a website with different user accounts, if they share a session the login page is skipped and they will already be logged in as the first user that logged in.
Thanks for all the help guys!