在Powershell(V5)类

时间:2016-01-06 04:04:31

标签: .net powershell

这是为了清晰起见而进行的主要编辑。看来我需要努力形成思想。 以下是我遇到问题的确切代码。 简要说明: 我正在尝试设置一个powershell类,它将保存不同类型的对象以便于访问。我在C#中做了很多次,所以我认为这是相当直接的。需要的类型是[System.Printing]和WMI-Objects。

最初我曾尝试将该类直接编写到我的Powershell配置文件中以方便使用,但是当我必须在其中编写代码时,我的配置文件无法加载。说它找不到类型名称" System.Printing.PrintServer"或任何其他明确列出的类型。 在失败之后,我将其移动到它自己的特定模块,然后设置我的配置文件以在打开时导入模块。但是,即使存储在自己的模块中,如果我明确列出任何属性的.Net类型,整个模块也无法加载。无论我是否添加或导入了类型/ dll。 具体问题是:         [字符串] $名称         [System.Printing.PrintServer] $服务器         [System.Printing.PrintQueue] $队列         [System.Printing.PrintTicket] $门票         [System.Management.ManagementObject] $单位         [布尔] $ ISDEFAULT

当我把它设置为这个时,一切都是"那种"工作,但然后我的所有属性都有_Object类型,这是没有用的。         [字符串] $名称         $服务器         $队列         $门票         $单位         $ 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
    }

}

3 个答案:

答案 0 :(得分:11)

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

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

另一种可能性是将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
    }
’@

答案 1 :(得分:0)

互补 PetSerAl's helpful answer

using assembly 应该是正确的解决方案,但自Windows PowerShell v5.1 / PowerShell Core起,尚未在解析时使用 v6.1,因为它需要额外的工作,以避免在加载程序集时潜在地执行任意代码的可能性。

this GitHub issue中已实现了这一点,并且在this issue中跟踪了必要的工作。

答案 2 :(得分:0)

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

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

但是,如果您要执行类似的操作,则可以期望Unable to find type [System.Windows.MessageBox].

Add-Type -AssemblyName PresentationCore,PresentationFramework

class ExampleClass2 {
    $object

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

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