Handle a COM event in PowerShell - powershell

I am controlling an application via its COM server from PowerShell. This is pretty simple:
# Start the application via COM
$app = New-Object -ComObject CoolApp.Application
# Start a data measurement in the application
$measurement = $app.Measurement
$measurement.Start()
Now comes the hard part: the Measurement object has an event called "OnFinished", that is invoked when the data measurement is done. I would like my powershell script to wait for the occurence of this event.
How can I subscribe to such an COM event PowerShell?

If a Primary Interop Assemblies(PIA) is provided from the developer to the COM object you are using, you can easily register event handlers by using it.
For example, refer to this description.
Registering and Catching Communicator 2007 Automation API Events
Like the above components and Office, PIA is provided for many of Microsoft's products.
Office primary interop assemblies
If there is no PIA, you can request it from the developer or you can create it yourself.
The way to make it is explained on this page.
How to: Generate Primary Interop Assemblies Using Tlbimp.exe

Is OnFinished a property of the app or measure object? If it is, and it returns a value when queried you could use a while loop to wait for that returned value to be a specific value e.g. if that property returns 'Completed' once the process has finished:
while($measure.OnFinished -ne 'Completed')
{
Sleep 5
}
Difficult to be more specific with my answer as I am not familiar with your COM object :)

Related

Is it possible to create a Microsoft team from a template with Powershell?

I am currently writing a Powershell script to create teams in Microsoft Teams.
Is there a way to use a template when creating a team in Powershell?
Thanks in advance.
Yes, it is possible, but not with the MicrosoftTeamsPowerShell module's New-Team. As per the docs, the -Template parameter is for Education customers:
If you have an EDU license, you can use this parameter to specify which template you'd like to use for creating your group. Do not use this parameter when converting an existing group.
Valid values are: "EDU_Class" or "EDU_PLC"
Instead, you can do this using Microsoft Graph, in particular the Create Team operation. One of the examples listed in the docs describes how to use the AdditionalProperties to specify a template, and once you know it's possible in Graph in concept, it's simply a case of finding the matching operation in the Microsoft Graph PowerShell module, in this case New-MgTeam (more info here).
For some final code, you can use the following:
Connect-MgGraph -Scopes "Team.Create"
$additionalProperties = #{
"template#odata.bind" = "https://graph.microsoft.com/v1.0/teamsTemplates('com.microsoft.teams.template.ManageAProject')"
}
New-MgTeam -DisplayName "SOTest" -AdditionalProperties $additionalProperties
This example using the Project Team template - here is a list of the out of box templates. For your custom templates, you can create them in the admin centre or via PowerShell, and you can read more about them here. To actually use a custom template, you use it's Guid in the form of:
$additionalProperties = #{
"template#odata.bind" = "https://graph.microsoft.com/v1.0/teamsTemplates('[your guid here]')"
}
Just a final note to be aware of - the PowerShell command executes quite quickly, and it creates the initial team pretty fast too, but it takes a few minutes to apply the template thereafter (e.g. creating the channels etc.) - give it 5 - 10 minutes and it should be fine.

Is it possible to get shell properties for an item not in the shell namespace?

Short Version
How does the shell get the properties of a file?
Long Version
The Windows Shell exposes a rich system of properties about items (e.g. files and folders) in the shell namespace.
For example:
System.Title: A Quick Guide for SQL Server Native Client OLE DB to ODBC Conversion
System.Author: George Yan (KW)
System.Document.LastAuthor: rohanl
System.Comment: To learn more about this speaker, find other TEDTalks, and subscribe to this Podcast series, visit www.TED.com Feedback: tedtalks#ted.com
System.ItemParticipants: George Yan (KW)
System.Company: Contoso
System.Language: English (United States)
System.Document.DateCreated: 6/‎10/‎2014 ‏‎5∶16∶30 ᴘᴍ
System.Image.HorizontalSize: 1845 pixels
System.Image.VerticalSize: 4695 pixels
System.Image.HorizontalResolution: 71 dpi
System.Image.VerticalResolution: 71 dpi
In order for the shell to read these properties, it obviously has to use a lot of sources:
Windows Media Foundation IMFMetadata works great for images and movies
Windows Imaging Component (WIC) probably has a lot of APIs for reading metadata
I'm not sure if IFilter can retrieve Title, Author, Subject, Comments etc from Office documents
Either way, it has to read the file contents stream and do something with the contents of the file in order to get all these fancy shell properties. In other words:
IStream \
+ |--> [magic] --> IPropertyStore
.ext /
Can use it with my own stream?
I have items that are not in the shell namespace; they are in a data store. I do expose them to the shell through IDataObject as CF_FILEDESCRIPTOR with an IStream when its time to perform copy-paste or drag-drop. But outside of that they are just streamable blobs in a data store.
I'd like to be able to leverage all the existing work done by the very talented and hard-working1 shell team to read metadata from a "file", which in the end only exists as an IStream.
Is there perhaps a binding context option that lets me get a property store based on an IDataObject rather than a IShellItem2?
So rather than:
IPropertyStore ps = shellItem2.GetPropertyStore();
is there a:
IPropertyStore ps = GetShellPropertiesFromFileStream(stream);
?
How does the shell get all the properties of a file?
Bonus Chatter - IPropertyStoreFactory
This interface is typically obtained through IShellFolder::BindToObject or IShellItem::BindToHandler. It is useful for data source implementers who want to avoid the additional overhead of creating a property store through IShellItem2::GetPropertyStore. However, IShellItem2::GetPropertyStore is the recommended method to obtain a property store unless you are implementing a data source through a Shell folder extension.
Tried
IPropertyStore ps = CoCreateInstance(CLSID_PropertyStore);
IInitializeWithStream iws = ps.QueryInterface(IID_IInitializeWithStream);
But CLSID_PropertyStore does not support IInitializeWithStream.
Bonus Reading
MSDN: Initializing Property Handlers
Property handlers are a crucial part of the property system. They are invoked in-process by the indexer to read and index property values, and are also invoked by Windows Explorer in-process to read and write property values directly in the files.
MSDN: Registering and Distributing Property Handlers (spellunking the registry for fun and reading contracts from the other side)
(Have some experience in Property Store handlers) How I see a solution:
Get PropertyStore handler CLSID for your file extension. You should use 2 regkeys key:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers\.yourext
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\SystemPropertyHandlers
Create two objects with CoCreateInstance
If you have 2 object you can combine them into single object with PSCreateMultiplexPropertyStore
Query for IInitializeWithStream (also you can try to query IPersistStream).
If the PropertyStore object supports IInitializeWithStream/IPersistStream: you are lucky - just init your object and query the properties you need. If does not - you still have (dirty) variant to create temporary file and then use IPersistFile.

Can I enable / Disable an Azure Service Bus Topic using Powershell

I have spent a couple of hours search for a solution to disable my Azure Service Bus Topics using Powershell.
The background for this is we want to force a manual failover to our other region.
Obviously I could click in the Portal:
but I want to have a script to do this.
Here is my current attempt:
Any help would be great.
Assuming you're sure your $topic contains the full description, modify the status parameter in the array and then splat it back using the UpdateTopic method. I'm afraid I can't test this at present.
$topic.Status = "Disabled"
$topicdesc = $NamespaceManager.UpdateTopic($topic)
I don't think you'll need to set the entity type for the Status, nor do you require semi-colons after each line of code in your loop.
References
PowerShell Service Bus creation sample script (which this appears to be based off): https://blogs.msdn.microsoft.com/paolos/2014/12/02/how-to-create-service-bus-queues-topics-and-subscriptions-using-a-powershell-script/
UpdateTopic method: https://msdn.microsoft.com/en-us/library/azure/microsoft.servicebus.namespacemanager.updatetopic.aspx
Additional note: please don't screenshot the code - paste it in. I'd rather copy-and-paste than type things out.

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!