在Powershell(V5)类中使用.NET对象

在Powershell(V5)类中使用.NET对象,.net,powershell,.net,Powershell,下面是我遇到问题的确切代码 简要说明: 我正在尝试设置一个PowerShell类,该类将保存不同类型的对象以便于访问。我在C#中已经做过很多次了,所以我认为这将是相当直接的。需要的类型是[System.Printing]和WMI对象 最初,我试图将该类直接写入我的PowerShell配置文件以便于使用,但当我必须在其中对代码进行分类时,我的配置文件无法加载。表示找不到类型名“System.Printing.PrintServer”或任何其他明确列出的类型 失败后,我将其移动到自己的特定模块,然后

下面是我遇到问题的确切代码

简要说明:

我正在尝试设置一个PowerShell类,该类将保存不同类型的对象以便于访问。我在C#中已经做过很多次了,所以我认为这将是相当直接的。需要的类型是[System.Printing]和WMI对象

最初,我试图将该类直接写入我的PowerShell配置文件以便于使用,但当我必须在其中对代码进行分类时,我的配置文件无法加载。表示找不到类型名“System.Printing.PrintServer”或任何其他明确列出的类型

失败后,我将其移动到自己的特定模块,然后将配置文件设置为在打开时导入该模块。但是,即使存储在自己的模块中,如果我为任何属性显式列出.NET类型,整个模块也无法加载。无论我是否添加或导入了类型/dll

具体问题是:

    [string]$Name
    [System.Printing.PrintServer]$Server
    [System.Printing.PrintQueue]$Queue
    [System.Printing.PrintTicket]$Ticket
    [System.Management.ManagementObject]$Unit
    [bool]$IsDefault
当我将它设置为这个值时,所有的“种类”都可以工作,但是我的所有属性都有_对象类型,这是没有帮助的

    [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
    }

}

在执行脚本中的第一条语句之前,会对每个PowerShell脚本进行完全解析。类定义中无法解析的类型名标记被视为解析错误。为了解决问题,必须在解析类定义之前加载类型,因此类定义必须位于单独的文件中。例如:

Main.ps1:

Add-Type -AssemblyName System.Printing
Add-Type -AssemblyName ReachFramework

. $PSScriptRoot\Class.ps1
using namespace System.Management
using namespace System.Printing

Class PrinterObject
{
    [string]$Name
    [PrintServer]$Server
    [PrintQueue]$Queue
    [PrintTicket]$Ticket
    [ManagementObject]$Unit
    [bool]$IsDefault
}
Class.ps1:

Add-Type -AssemblyName System.Printing
Add-Type -AssemblyName ReachFramework

. $PSScriptRoot\Class.ps1
using namespace System.Management
using namespace System.Printing

Class PrinterObject
{
    [string]$Name
    [PrintServer]$Server
    [PrintQueue]$Queue
    [PrintTicket]$Ticket
    [ManagementObject]$Unit
    [bool]$IsDefault
}
另一种可能是将
Class.ps1
嵌入为字符串,并使用
Invoke Expression
执行它。这会将类定义的解析延迟到类型可用的时间

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
    }
’@
补充:

使用程序集
应该是正确的解决方案,但从Windows PowerShell v5.1/PowerShell Core v6.1开始,它在解析时的使用尚未实现,因为它需要额外的工作,以避免在加载程序集时不希望执行任意代码

实现这一点已被绿灯亮起,并且正在跟踪必要的工作。

一个更好的解决方案(不仅仅是在字符串中调用整个类)是创建对象并将它们作为参数传递给类。例如,这运行良好:

Add-Type -AssemblyName PresentationCore,PresentationFramework

class ExampleClass {
    $object

    ExampleClass ($anotherClass) {
        $this.object = $anotherClass
    }

    [void] Show () {
        $this.object::Show('Hello')
    }
}

$y = [ExampleClass]::new([System.Windows.MessageBox])
$y.Show()
但是,如果您要执行类似操作,您可能会发现
无法找到类型[System.Windows.MessageBox]。

Add-Type -AssemblyName PresentationCore,PresentationFramework

class ExampleClass2 {
    $object

    ExampleClass () {
        $this.object = [System.Windows.MessageBox]
    }

    [void] Show () {
        $this.object::Show('Hello')
    }
}

你能用“指定的类型”具体化/文字化吗?您给出的伪代码没有任何意义。您可能没有正确分离命名空间、类和值部分。没有人能从[System.Object.SomeDotNetObject]:Enum.问题类型属于哪里?它是在标准.NET程序集中、GAC中的自定义程序集、通过路径加载的自定义程序集还是动态程序集
添加类型-类型定义…
?@PetSerAl其实并不重要-如果命名空间/类型可以在类定义之外解析,为什么不应该在类内部解析?@MathiasR.Jessen我无法在我的电脑上重现这种行为,因此我要求提供额外的详细信息,以检查我是否遗漏了某些内容。@MartinMaat我已经用我正在使用的类的确切代码进行了更新。我觉得这可能是类型没有正确加载到powershell中的问题,因为如果我手动加载类型,然后手动将这个类输入到shell中,它工作得非常好,所以。我试过了,我猜是一个非常奇怪的错误导致了无数的powershell窗口快速弹出,以至于我的系统内存不足。您点源于dot source语句所在的文件?例如,将“$PSScriptRoot\Class.ps1”放入名为“Class.ps1”的文件中?那么,这种行为是一个bug,还是PowerShell的导入系统如此糟糕?@tyteen4a03
使用程序集
不会导致分析时程序集加载。程序集加载可能导致执行任意代码,这可能是不需要的。从程序集元数据中提取类型而不加载它还没有实现,AFAIK@TNT如果
eval
超过常量字符串,那么执行任意脚本文件会更危险吗?