2011-09-26 13 views
9

Próbuję uruchomić skrypty PowerShell z mojego kodu C#, który użyje niestandardowych poleceń Cmdlets ze złożenia, który je uruchamia. Oto kod:Hostowany PowerShell nie widzi cmdletów w tym samym zestawie

using System; 
using System.Management.Automation; 

[Cmdlet(VerbsCommon.Get,"Hello")] 
public class GetHelloCommand:Cmdlet 
{ 
    protected override void EndProcessing() 
    { 
     WriteObject("Hello",true); 
    } 
} 

class MainClass 
{ 
    public static void Main(string[] args) 
    { 
     PowerShell powerShell=PowerShell.Create(); 
     powerShell.AddCommand("Get-Hello"); 
     foreach(string str in powerShell.AddCommand("Out-String").Invoke<string>()) 
      Console.WriteLine(str); 
    } 
} 

Kiedy próbuję go uruchomić, otrzymuję wyjątek CommandNotFoundException. Czy napisałem Cmdlet źle? Czy jest coś, co muszę zrobić, aby zarejestrować moje Cmdlet w PowerShell lub Runspace, czy coś w tym stylu?

Odpowiedz

9

Najłatwiej to zrobić z aktualnym fragmencie kodu jest tak:

using System; 
using System.Management.Automation; 

[Cmdlet(VerbsCommon.Get,"Hello")] 
public class GetHelloCommand:Cmdlet 
{ 
    protected override void EndProcessing() 
    { 
     WriteObject("Hello",true); 
    } 
} 

class MainClass 
{ 
    public static void Main(string[] args) 
    { 
     PowerShell powerShell=PowerShell.Create(); 

     // import commands from the current executing assembly 
     powershell.AddCommand("Import-Module") 
      .AddParameter("Assembly", 
        System.Reflection.Assembly.GetExecutingAssembly()) 
     powershell.Invoke() 
     powershell.Commands.Clear() 

     powershell.AddCommand("Get-Hello"); 
     foreach(string str in powerShell.AddCommand("Out-String").Invoke<string>()) 
      Console.WriteLine(str); 
    } 
} 

Zakłada PowerShell v2.0 (można sprawdzić w twoja konsola z $ psversiontable lub według daty praw autorskich, która powinna być 2009.) Jeśli jesteś na Win7, jesteś na v2.

+0

Działa jak urok! dzięki! –

1

Musisz zarejestrować swoje polecenie cmdlet, zanim będzie można go użyć w sesji Powershell. Zwykle robisz to za pomocą Snap-inu Powershell. Oto przegląd wysokiego poziomu procesu:

  • Tworzenie niestandardowych apletów poleceń (już zrobić tę część)
  • Tworzenie PowerShell Snap-in, który zawiera i opisuje twoje cmdlet
  • zainstalować nowy Snap -w systemie używając Installutil
  • Dodawanie przystawki do konkretnej sesji PowerShell użyciem Add-PSSnapin

Istnieje kilka przydatnych artykułów na MSDN, które wyjaśniają th Proces e dość dokładnie:

Jest też seria 2-częściowy na ByteBlocks który omawia piszących własne aplety poleceń. Ta seria może być najlepszym wyborem, ponieważ wydajesz się, że zrobiłeś już odpowiednik części 1. Możesz być w stanie wykorzystać część 2 jako szybkie odniesienie i być dobrym do zrobienia.

+1

SnapIn to sposób działania robaka powershell v1, odradzany w dzisiejszych czasach, ponieważ wymaga uprawnień administratora, aby je zarejestrować. Powinien używać modułów powershell v2. – x0n

+0

Nie odpowiada na pytanie, co próbuje zrobić. – manojlds

+0

@manojlds To odpowiada na pytanie, ale zdecydowanie nie jest tak aktualne i eleganckie jak odpowiedź x0n. – ajk

4

Jeszcze jednym prostym sposobem jest zarejestrowanie cmdletów w konfiguracji runspace, utworzenie runspace z tą konfiguracją i użycie tego runspace.

using System; 
using System.Management.Automation; 
using System.Management.Automation.Runspaces; 

[Cmdlet(VerbsCommon.Get, "Hello")] 
public class GetHelloCommand : Cmdlet 
{ 
    protected override void EndProcessing() 
    { 
     WriteObject("Hello", true); 
    } 
} 

class MainClass 
{ 
    public static void Main(string[] args) 
    { 
     PowerShell powerShell = PowerShell.Create(); 
     var configuration = RunspaceConfiguration.Create(); 
     configuration.Cmdlets.Append(new CmdletConfigurationEntry[] { new CmdletConfigurationEntry("Get-Hello", typeof(GetHelloCommand), "") }); 
     powerShell.Runspace = RunspaceFactory.CreateRunspace(configuration); 
     powerShell.Runspace.Open(); 

     powerShell.AddCommand("Get-Hello"); 
     foreach (string str in powerShell.AddCommand("Out-String").Invoke<string>()) 
      Console.WriteLine(str); 
    } 
} 

Na wszelki wypadek przy takim podejściu klasy cmdlet nie muszą być publiczne.

+0

Dzięki.Czy istnieje sposób, aby to zrobić z wnętrza PowerShell? To znaczy, aby załadować bibliotekę DLL za pomocą [Reflection.Assembly] :: LoadFrom, a następnie wywołać funkcję, która ładuje Cmdlets do bieżącej sesji PowerShell? –

+0

Nie próbowałem tego (tylko dlatego, że nie musiałem). W PowerShell można uzyskać dostęp do konfiguracji domyślnego (mniej lub bardziej * bieżącego * ale zależy) runspace jako: '[System.Management.Automation.Runspaces.Runspace] :: DefaultRunspace.RunspaceConfiguration'. Następnie spróbuj wywołać '.Cmdlets.Append (...)' na tym. Byłoby miło, gdybyś spróbował tego i opowiedział nam o wynikach. –

+0

Nie mogę go uruchomić. Wygląda na to, że Runspace nie załaduje Cmdlets w ten sposób, chyba że znajduje się w stanie BeforeOpen. Jakikolwiek sposób załadować Cmdlets do otwartej otwartej Runspace? –

Powiązane problemy