Uso de Objetos .Net dentro de una clase Powershell (V5)

Esta es una edición importante realizada con fines de claridad. Parece que necesito trabajar en formar pensamientos. A continuación está el código exacto con el que estoy teniendo problemas. Una breve descripción: estoy tratando de configurar una clase powershell que contendrá objetos de diferentes tipos para facilitar el acceso. Lo he hecho varias veces en C #, así que pensé que sería bastante sencillo. Los tipos buscados son [System.Printing] y WMI-Objects.

Originalmente había intentado escribir la clase directamente en mi perfil de Powershell para facilitar el uso, pero mi perfil no se carga cuando tengo que introducir el código de clase. Diciendo que no puede encontrar el tipo de nombre “System.Printing.PrintServer”, o cualquier otro tipo explícitamente listado. Después de que falló, lo moví a su propio módulo específico y luego configuré mi perfil para importar el módulo en abierto. Sin embargo, incluso cuando se almacena en su propio módulo, si incluyo explícitamente un tipo .Net para cualquiera de las propiedades, el módulo completo no se carga. Independientemente de si he agregado o importado el tipo / dll. El área problemática específica es esta: [cadena] $ Nombre [System.Printing.PrintServer] $ Server [System.Printing.PrintQueue] $ Queue [System.Printing.PrintTicket] $ Ticket [System.Management.ManagementObject] $ Unit [bool ] $ IsDefault

Cuando lo tengo configurado para esto, todo “tipo de” funciona, pero todas mis propiedades tienen el tipo de objeto, lo que no es útil. [string] $ Name $ Server $ Queue $ Ticket $ Unit $ IsDefault

Add-Type -AssemblyName System.Printing Add-Type -AssemblyName ReachFramework Class PrinterObject { [string]$Name [System.Printing.PrintServer]$Server [System.Printing.PrintQueue]$Queue [System.Printing.PrintTicket]$Ticket [System.Management.ManagementObject]$Unit [bool]$IsDefault PrinterObject([string]$Name) { #Add-Type -AssemblyName System.Printing #Add-Type -AssemblyName ReachFramework $this.Server = New-Object System.Printing.PrintServer -ArgumentList [System.Printing.PrintSystemDesiredAccess]::AdministrateServer $this.Queue = New-Object System.Printing.PrintQueue (($this.Server), ($this.Server.GetPrintQueues() | Where-Object {$_.Name -match $Name} | Select-Object -ExpandProperty Name)) $this.Ticket = $this.Queue.UserPrintTicket $this.Unit = Get-WmiObject -Query "SELECT * FROM Win32_Printer WHERE Name LIKE `"%$Name%`"" } PrinterObject([string]$Name, [bool]$IsNetwork) { #Add-Type -AssemblyName System.Printing #Add-Type -AssemblyName ReachFramework if($IsNetwork -eq $true) { $this.Server = New-Object System.Printing.PrintServer ("\\Server") $this.Queue = New-Object System.Printing.PrintQueue (($this.Server), ($this.Server.GetPrintQueues() | Where-Object {$_.Name -match $Name} | Select-Object -ExpandProperty Name)) $this.Ticket = $this.Queue.UserPrintTicket $this.Unit = Get-WmiObject -Query "SELECT * FROM Win32_Printer WHERE Name LIKE `"%$Name%`"" } else { $This.Server = New-Object System.Printing.PrintServer -argumentList [System.Printing.PrintSystemDesiredAccess]::AdministrateServer $this.Queue = New-Object System.Printing.PrintQueue (($this.Server), ($this.Server.GetPrintQueues() | Where-Object {$_.Name -match $Name} | Select-Object -ExpandProperty Name)) $this.Ticket = $this.Queue.UserPrintTicket $this.Unit = Get-WmiObject -Query "SELECT * FROM Win32_Printer WHERE Name LIKE `"%$Name%`"" } } [void]SetPrintTicket([int]$Copies, [string]$Collation, [string]$Duplex) { $this.Ticket.CopyCount = $Copies $this.Ticket.Collation = $Collation $this.Ticket.Duplexing = $Duplex $this.Queue.Commit() } [Object]GetJobs($Option) { if($Option -eq 1) { return $this.Queue.GetPrintJobInfoCollection() | Sort-Object -Property JobIdentifier | Select-Object -First 1} else { return $this.Queue.GetPrintJobInfoCollection() } } static [Object]ShowAllPrinters() { Return Get-WmiObject -Class Win32_Printer | Select-Object -Property Name, SystemName } } 

Cada secuencia de comandos de PowerShell se analiza completamente antes de que se ejecute la primera statement en la secuencia de comandos. Un token de nombre de tipo no resuelto dentro de una definición de clase se considera un error de análisis. Para resolver su problema, debe cargar sus tipos antes de analizar la definición de la clase, por lo que la definición de la clase debe estar en un archivo separado. Por ejemplo:

Main.ps1:

 Add-Type -AssemblyName System.Printing Add-Type -AssemblyName ReachFramework . $PSScriptRoot\Class.ps1 

Class.ps1:

 using namespace System.Management using namespace System.Printing Class PrinterObject { [string]$Name [PrintServer]$Server [PrintQueue]$Queue [PrintTicket]$Ticket [ManagementObject]$Unit [bool]$IsDefault } 

La otra posibilidad sería incrustar Class.ps1 como una cadena y usar Invoke-Expression para ejecutarla. Esto retrasará el análisis de la definición de clase a la hora en que los tipos están disponibles.

 Add-Type -AssemblyName System.Printing Add-Type -AssemblyName ReachFramework Invoke-Expression @' using namespace System.Management using namespace System.Printing Class PrinterObject { [string]$Name [PrintServer]$Server [PrintQueue]$Queue [PrintTicket]$Ticket [ManagementObject]$Unit [bool]$IsDefault } '@ 

Para complementar la útil respuesta de PetSerAl :

using assembly debería ser la solución correcta, pero su uso en tiempo de análisis aún no se ha implementado a partir de Windows PowerShell v5.1 / PowerShell Core v6.1, ya que requiere un trabajo adicional para evitar la posibilidad de ejecución no deseada de código arbitrario cuando un conjunto está cargado.

La implementación de esto se ha puesto verde en este problema de GitHub , y se está rastreando el trabajo necesario como parte de este problema .