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

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])

Related

Windows MDM update management

I'm trying to figure out Windows update management via MDM (https://learn.microsoft.com/en-us/windows/client-management/mdm/device-update-management) and I would like to show installed and installable updates details for clients.
So following this guide, I'm getting installed/installable/... update GUIDs from the client using Update-CSP, then try to query GUID from sws.update.microsoft.com to get the metadata.
The problem is, the client is reporting update GUIDs that cannot be found in sws.update.microsoft.com. For example the device returns an update id: "1f36097b-e8c9-41a3-bcc3-baae597f692d" as an installed update.
When I query this Using GetUpdateData, it doesn't exists.
I queried installed updated on the client and found the detail:
PS C:\Windows\system32> $session.CreateUpdateSearcher().Search("UpdateID='1f36097b-e8c9-41a3-bcc3-baae597f692d'").Updates
Title : 2021-09 Cumulative Update for Windows 10 Version 20H2 for x64-based Systems (KB5005565)
AutoSelectOnWebSites : True
BundledUpdates : System.__ComObject
CanRequireSource : False
Categories : System.__ComObject
Deadline :
DeltaCompressedContentAvailable : True
DeltaCompressedContentPreferred : True
Description : Install this update to resolve issues in Windows. For a complete listing of the issues that are included in this update, see the associated Microsoft Knowledge Base article for more information. After you install this item, you may have to restart your computer.
EulaAccepted : True
EulaText :
HandlerID : http://schemas.microsoft.com/msus/2016/01/UpdateHandlers/OSInstaller
Identity : System.__ComObject
Image :
InstallationBehavior : System.__ComObject
IsBeta : False
IsDownloaded : True
IsHidden : False
IsInstalled : True
IsMandatory : False
IsUninstallable : False
Languages : System.__ComObject
LastDeploymentChangeTime : 9/14/2021 12:00:00 AM
MaxDownloadSize : 110963910278
MinDownloadSize : 0
MoreInfoUrls : System.__ComObject
MsrcSeverity :
RecommendedCpuSpeed : 0
RecommendedHardDiskSpace : 0
RecommendedMemory : 0
ReleaseNotes :
SecurityBulletinIDs : System.__ComObject
SupersededUpdateIDs : System.__ComObject
SupportUrl : https://support.microsoft.com/help/5005565
Type : 1
UninstallationNotes :
UninstallationBehavior :
UninstallationSteps : System.__ComObject
KBArticleIDs : System.__ComObject
DeploymentAction : 1
DownloadPriority : 2
DownloadContents : System.__ComObject
RebootRequired : False
IsPresent : True
CveIDs : System.__ComObject
BrowseOnly : False
PerUser : False
AutoSelection : 1
AutoDownload : 2
But when I look up this update by its name or KB article, I find the correct update id is: 9a11c8f1-525f-4088-8fb7-33d7b56dd6dc
catalog page
I'm not sure why client reports an incorrect (or deprecated?) update id.
Is there a way to make client to correct it?

How to obatin a different interface from a COM object in PowerShell

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))

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

PowerShell: how to get detailed information about a WMI event?

I'm learning PowerShell 2.0 on Windows 7.
My task is simple: I want to listen for a WMI event and then display some information about it.
Here is what I'm currently doing:
Register-WmiEvent -class win32_ProcessStartTrace -sourceIdentifier processStart
Wait-Event
It seems to work. Indeed, I get this when I start a process:
ComputerName :
RunspaceId : bb0f38b9-2f2e-4f7c-98ec-ec3811e8e601
EventIdentifier : 11
Sender : System.Management.ManagementEventWatcher
SourceEventArgs : System.Management.EventArrivedEventArgs
SourceArgs : {System.Management.ManagementEventWatcher, System.Management.EventArrivedEventArgs}
SourceIdentifier : processStart
TimeGenerated : 26/09/2009 15:19:25
MessageData :
Problem is, I don't know how to get detailed information about the event. For example, how do I get the name of the process that just started? Ideally, I would have something like this:
__GENUS : 2
__CLASS : Win32_ProcessStartTrace
__SUPERCLASS : Win32_ProcessTrace
__DYNASTY : __SystemClass
__RELPATH :
__PROPERTY_COUNT : 7
__DERIVATION : {Win32_ProcessTrace, Win32_SystemTrace, __ExtrinsicEvent, __Event...}
__SERVER :
__NAMESPACE :
__PATH :
ParentProcessID : 1480
ProcessID : 6860
ProcessName : notepad++.exe
SECURITY_DESCRIPTOR :
SessionID : 1
Sid : {1, 5, 0, 0...}
TIME_CREATED : 128984449371986347
I can get the above information when I do
(get-event).sender.waitfornextevent()
But, obviously, that's not really what I had in mind - I don't want to wait for another event, I want info on the current one.
Take a gander here:
http://blogs.msdn.com/powershell/archive/2009/08/30/exploring-wmi-with-powershell-v2.aspx

Resources