How to obatin a different interface from a COM object in PowerShell - visual-studio

Using COM methods like [System.Runtime.InteropServices.Marshal]::GetActiveObject("VisualStudio.DTE") I can navigate the Visual Studio DTE object model fine. For instance from DTE object I can get Debugger, and then LocalProcesses, and the the Process object. But I need the derived Process2 interface on it, to call Attach2("<my debug engine>").
I could not find a way to obtain the interface I want, a simple cast results in runtime error: Cannot convert the "System.__ComObject" value of type "System.__ComObject#{5c5a0070-f396-4e37-a82a-1b767e272df9}" to type "EnvDTE80.Process2".
PS> $dte = [System.Runtime.InteropServices.Marshal]::GetActiveObject("VisualStudio.DTE")
PS> $p = $dte.Debugger.LocalProcesses | where {$_.ProcessID -eq 11212}
PS> $p
Name : C:\Program Files\IIS Express\iisexpress.exe
ProcessID : 11212
Programs : System.__ComObject
DTE : System.__ComObject
Parent : System.__ComObject
Collection : System.__ComObject
PS> [EnvDTE80.Process2]$p2 = $p
Cannot convert the "System.__ComObject" value of type "System.__ComObject#{5c5a0070-f396-4e37-a82a-1b767e272df9}" to type "EnvDTE80.Process2".
At line:1 char:1
+ [EnvDTE80.Process2]$p2 = $p
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException

You can't really, at least not in a way that PowerShell will be able to remember when it comes to member binding.
PowerShell only ever operates based on runtime information. Even if you cast it in C# first, if QueryInterface returns the same pointer for that interface then all PowerShell is going to see is the IDispatch it currently detects. Even if the object you obtained was a strongly typed version from the primary interop assembly, PowerShell only sees concrete types (which there doesn't seem to be one for Process2).
As a workaround, you can use reflection:
[EnvDTE80.Process2].InvokeMember(
'Attach2',
[Reflection.BindingFlags]::InvokeMethod,
<# binder: #> $null,
<# target: #> $process,
<# args: #> #($myEngine))

Related

Cannot create com object - Powershell

Below is the msg while creating a New-Object (Powershell)
I tried opening Powershell
as Admin
32bit ISE
64bit ISE
Nothing helped
> New-Object : Retrieving the COM class factory for component with CLSID
> {00000000-0000-0000-0000-000000000000} failed due to the following
> error: 80040154 Class not registered (Exception from HRESULT:
> 0x80040154 (REGDB_E_CLASSNOTREG)). At line:1 char:8
> + $obj = New-Object -ComObject Microsoft.SMS.Client -Strict
> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + CategoryInfo : ResourceUnavailable: (:) [New-Object], COMException
> + FullyQualifiedErrorId : NoCOMClassIdentified,Microsoft.PowerShell.Commands.NewObjectCommand
I was able find alternative way to set the site code which I was trying to earlier with the com-object and fix the issue. but still not sure what is wrong with the above method

How to output objects to various coordinates of a powershell console window at the same time?

I have been using powershell on a win 10 environment for a few months now, so still new to powershell and am trying use the powershell console as a technical point of display, whereby it cycles/loops through various components of data and displays the information at various coordinates of the console window. The problem I have is it can only display the data from any one particular loop at any one time. I suspect a type of multithreading is going to be needed like runspaces or psjobs, but I believe they are both background functions and cant display data in real-time, so not sure if the console even supports this kind of request.
Perhaps there is another way of going about this
I have tried putting all my scripts and get- command under one loop but it doesnt provide the "look" and feel we are trying to achieve. I want to be able to use the entire window as realestate for outputing objects. I have looked at psjobs and runspaces but they seem to work in the background.
So the code presented should output the get-service ojbects and the get-process objects to the coordinates specified at the same time.
function OBJ1{
[console]::setcursorposition(60,120)
Get-Process
]}
function OBJ2{
[console]::setcursorposition(10,70)
Get-Service
]}
Workflow obj3
{
Parallel
{
obj1
obj2
}
}
obj3
Instead the errors I get are:
<!-- language: lang-none -->
Microsoft.PowerShell.Utility\Write-Error : Exception calling "SetCursorPosition" with "2" argument(s): "The handle is invalid.
"
At obj3:20 char:20
+
+ CategoryInfo : NotSpecified: (:) [Write-Error], RemoteException
+ FullyQualifiedErrorId : System.Management.Automation.RemoteException,Microsoft.PowerShell.Commands.WriteErrorCommand
+ PSComputerName : [localhost]
Microsoft.PowerShell.Utility\Write-Error : Exception calling "SetCursorPosition" with "2" argument(s): "The handle is invalid.
"
At obj3:20 char:20
+
+ CategoryInfo : NotSpecified: (:) [Write-Error], RemoteException
+ FullyQualifiedErrorId : System.Management.Automation.RemoteException,Microsoft.PowerShell.Commands.WriteErrorCommand
+ PSComputerName : [localhost]

Can't access FileCodeModel from Powershell console in Visual Studio 2017 DTE

I'm trying to automate some code-related routines in VisualStudio 2017 using integrated Powershell console and VS Automation model (DTE). When I'm working on Solution/Project/File level, things are ok, e.g.
PS> $dte.ActiveDocument.ProjectItem
IsDirty : False
FileCount : 1
Name : FeaturesComposition.cs
Collection : System.__ComObject
Properties : System.__ComObject
DTE : System.__ComObject
Kind : {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}
ProjectItems : System.__ComObject
Object : System.__ComObject
ExtenderNames : {}
ExtenderCATID : {610D4615-D0D5-11D2-8599-006097C68E81}
Saved : True
ConfigurationManager :
FileCodeModel : System.__ComObject
Document : System.__ComObject
SubProject :
ContainingProject : System.__ComObject
But when I come to the code model of some particular file, there is nothing to work with:
PS> $dte.ActiveDocument.ProjectItem.FileCodeModel | Format-List -Property *
System.__ComObject
PS> $dte.ActiveDocument.ProjectItem.FileCodeModel | gm
PS>
Is it possible to get access to such submodels? Is there any easy way of dispatching EnvDTE.DTE interface to the existing $dte instance? I've tried some ideas below, but without no success.
Add-Type -Path "$env:VSAPPIDDIR\PublicAssemblies\envdte.dll"
PS> # Explicit cast doesn't work
PS> [EnvDTE.DTE]$dte
[ERROR] Cannot convert the "System.__ComObject" value of type "System.__ComObject#{04a72314-32e9-48e2-9b87-a63603454f3e}" to type "EnvDTE.DTE".
PS> # Wrapper works but it's useless
PS> $wrapped = [Runtime.InteropServices.Marshal]::CreateWrapperOfType($dte, [EnvDTE.DTEClass])
PS> $wrapped.ActiveDocument.ProjectItem.FileCodeModel
System.__ComObject
PS> # GetComInterfaceForObject gives the same IntPtr as IUnknown:QueryInterface
PS> # different from the call to GetComInterfaceForObject for example,
PS> # so I hoped to get another casting results. But it is the same.
PS> $contract = [Runtime.InteropServices.Marshal]::GetComInterfaceForObject($dte, [EnvDTE.DTE])
PS> [EnvDTE.DTE][Runtime.InteropServices.Marshal]::GetObjectForIUnknown($contract)
[ERROR] Cannot convert the "System.__ComObject" value of type "System.__ComObject#{04a72314-32e9-48e2-9b87-a63603454f3e}" to type "EnvDTE.DTE".
Try this:
$fileCodeModel = Get-Interface $dte.ActiveDocument.ProjectItem.FileCodeModel ([ENVDTE80.FileCodeModel2])

Scaffolding Get-ProjectType not recognized as the name of a cmdlet

just tried to get the basic basics up and running and getting some fancy error conditions - most probably some basic steps are screwed up but I don't see the point - so some hints are highly appreciated.
So whats the setup?
VS2010
MVC3 or MVC4 Project - no strings attached, just the templates
Create a really simple Model-Class Team like shown on http://blog.stevensanderson.com/2011/01/13/scaffold-your-aspnet-mvc-3-project-with-the-mvcscaffolding-package/
What happens?
Try (after installing MvcScaffolding through NuGet Console) to call:
Scaffold Controller Team
And get the following error:
PM> Scaffold Controller Team
Scaffolding TeamsController...
Invoke-Scaffolder : The term 'Get-ProjectType' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or
if a path was included, verify that the path is correct and try again.
At O:\Code\Resource\packages\MvcScaffolding.1.0.7\tools\Controller\MvcScaffolding.Controller.ps1:66 char:40
+ $dbContextScaffolderResult = Scaffold <<<< DbContext -ModelType $foundModelType.FullName -DbContextType $DbContextType -Area $Area -Project $Project -CodeLang
uage $CodeLanguage -BlockUi
+ CategoryInfo : NotSpecified: (:) [Invoke-Scaffolder], CommandNotFoundException
+ FullyQualifiedErrorId : T4Scaffolding.Cmdlets.InvokeScaffolderCmdlet
Fancy thing: of course Get-ProjectType itself seems to work (see below), so I'm kind of stuck right now - as this looks like a powershell issue somehow but the cmdlet itself works at least if called directly but not when inside the script? Any hints would be greatly appreciated!
Thanks a lot.
PM> Get-ProjectType
cmdlet Get-ProjectType at command pipeline position 1
Supply values for the following parameters:
Type: Team
DTE : System.__ComObject
Collection : System.__ComObject
Name : Team
FullName : Resource.Models.Team
ProjectItem : System.__ComObject
Kind : 1
IsCodeType : True
InfoLocation : 1
Children : System.__ComObject
Language : {B5E9BD34-6D3E-4B5D-925E-8A43B79820B4}
StartPoint : System.__ComObject
EndPoint : System.__ComObject
ExtenderNames :
ExtenderCATID :
Parent : System.__ComObject
Namespace : System.__ComObject
Bases : System.__ComObject
Members : System.__ComObject
Access : 1
Attributes : System.__ComObject
DocComment : <doc>
</doc>
Comment :
DerivedTypes :
ImplementedInterfaces : System.__ComObject
IsAbstract : False
ClassKind : 1
PartialClasses : System.__ComObject
DataTypeKind : 1
Parts : System.__ComObject
InheritanceKind : 0
IsGeneric : False
IsShared : False
PM>
With Kind Regards,
Ives

Where is type [Oracle.DataAccess.Client.OracleBulkCopy]?

I tried
[System.Reflection.Assembly]::LoadWithPartialName("Oracle.DataAccess")
$bulkCopy = new-object Oracle.DataAccess.Client.OracleBulkCopy $oraClientConnString
and got
GAC Version Location
--- ------- --------
True v2.0.50727 C:\Windows\assembly\GAC_32\Oracle.DataAccess\2.111.6.0__89b483f429c47342\Oracle.DataAccess.dll
New-Object : Cannot find type [Oracle.DataAccess.Client.OracleBulkCopy]: make sure the assembly containing this type is loaded.
At line:3 char:23
+ $bulkCopy = new-object <<<< Oracle.DataAccess.Client.OracleBulkCopy $oraClientConnString
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
Cf. OracleBulkCopy Class
What is missing?
Maybe you're using an older version of Oracle? I see documentation for this class on Oracle for 11g or later.
http://download.oracle.com/docs/html/E10927_01/OracleBulkCopyClass.htm
Oracle.DataClient.dll is the containing assembly in the above documentation.
Try this:
ps> $a = [reflection.assembly]::loadwithpartialname("oracle.dataaccess")
ps> $a.getexportedtypes() | where { $_.fullname -like "*bulk*" }
-Oisin

Resources