2

With reference to Would like to run PowerShell code from inside a C++ program, I have created a program to execute the PowerShell script in C++ using System.Management.Automation.dll. But, I wasn't able to retrieve the return data from the Invoke() function. I can create individual PSObject, but I couldn't create the collection of PSObject.

Attached the the code:

#include <vcclr.h>
#include<Windows.h>
#include<iostream>
#using <mscorlib.dll>
#using <System.dll>
#include<vector>
#using <System.Management.Automation.dll>
using namespace std;

using namespace System;
using namespace System::Management::Automation;

void RunPowerShell( )
{
    Collection<PSObject> powObject= PowerShell::Create()->AddScript(gcnew String("get-wmiobject -query \"select * from win32_bios\""))->Invoke();
    PSObject k;
    
    String ^s=PowerShell::Create()->AddCommand("(Get-Variable PSVersionTable -ValueOnly).PSVersion")->ToString();
    printf("%s\n", s);
}
int main()
{
    RunPowerShell();
    return 0;
} 

Errors:

E0020 identifier "Collection" is undefined
E0254 type name is not allowed
E0020 identifier "powObject" is undefined
C2065 'Collection': undeclared identifier
C2275 'System::Management::Automation::PSObject': expected an expression instead of a type
C2065 'powObject': undeclared identifer
mklement0
  • 382,024
  • 64
  • 607
  • 775
Vineeth
  • 23
  • 4
  • 1
    Don't put texts (error, whatever) as images, put it as text – Simon Mourier Sep 21 '22 at 17:42
  • Switch to the build output tab, highlight the errors and then copy-paste here, format as preformatted text. – zett42 Sep 21 '22 at 17:44
  • Judging by the existing code, you need a `using namespace System::Collections::ObjectModel;` statement in order to be able to reference .NET type [`System.Collections.ObjectModel.Collection`](https://learn.microsoft.com/en-US/dotnet/api/System.Collections.ObjectModel.Collection-1) by its mere type name, `Collection`, allone. – mklement0 Sep 22 '22 at 00:27
  • Two asides:`(Get-Variable PSVersionTable -ValueOnly).PSVersion"` can be simplified to `$PSVersionTable.PSVersion`. The CIM cmdlets (e.g., `Get-CimInstance`) superseded the WMI cmdlets (e.g., `Get-WmiObject`) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell (Core) v6+, where all future effort will go, doesn't even _have_ them anymore. Note that WMI still _underlies_ the CIM cmdlets, however. For more information, see [this answer](https://stackoverflow.com/a/54508009/45375). – mklement0 Sep 22 '22 at 00:30

1 Answers1

1

You need to either import the proper namespaces, like this:

#include <Windows.h>
#include <vcclr.h>
#include <iostream>
#include <vector>

#using <mscorlib.dll>
#using <System.dll>
#using <System.Management.Automation.dll>

using namespace std;
using namespace System;
using namespace System::Collections::ObjectModel; // you need this one
using namespace System::Management::Automation;

void RunPowerShell()
{
  // or simply use C++ auto!
  Collection<PSObject^>^ powObject = PowerShell::Create()->AddScript(gcnew String("get-wmiobject -query \"select * from win32_bios\""))->Invoke();

  for (int i = 0; i < powObject->Count; i++)
  {
    Console::WriteLine(powObject[i]);
  }
}

int main()
{
  RunPowerShell();
  return 0;

or just use the cool C++ auto keyword, like this:

auto powObject = PowerShell::Create()->AddScript(gcnew String("get-wmiobject -query \"select * from win32_bios\""))->Invoke();

And as a bonus, Visual Studio's magic will show the namespace for you if you hover the mouse around the auto keyword:

enter image description here

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298