tech.guitarrapc.cóm

Technical updates

PowerShell で プリンターのポート操作と紐づけを行ってみる

Windows の操作を自動化したい。 PowerShellに触れるのにもっとも簡単な題材はこれではないでしょうか。

そういえば、 プリンターに関する操作について触る機会がなくて紹介していませんでしたが、少し触ってみたので簡単に。

目次

Printer に関するコマンドレット(Cmdlet)

PowerShell 3.0 から以下のコマンドレットが利用可能になっています。

一連のコマンドレットは、PrintManagementモジュールに格納されているので見てみましょう。

Get-Command -Module PrintManagement
CommandType Name                   ModuleName
----------- ----                   ----------
Function    Add-Printer            PrintManagement
Function    Add-PrinterDriver      PrintManagement
Function    Add-PrinterPort        PrintManagement
Function    Get-PrintConfiguration PrintManagement
Function    Get-Printer            PrintManagement
Function    Get-PrinterDriver      PrintManagement
Function    Get-PrinterPort        PrintManagement
Function    Get-PrinterProperty    PrintManagement
Function    Get-PrintJob           PrintManagement
Function    Read-PrinterNfcTag     PrintManagement
Function    Remove-Printer         PrintManagement
Function    Remove-PrinterDriver   PrintManagement
Function    Remove-PrinterPort     PrintManagement
Function    Remove-PrintJob        PrintManagement
Function    Rename-Printer         PrintManagement
Function    Restart-PrintJob       PrintManagement
Function    Resume-PrintJob        PrintManagement
Function    Set-PrintConfiguration PrintManagement
Function    Set-Printer            PrintManagement
Function    Set-PrinterProperty    PrintManagement
Function    Suspend-PrintJob       PrintManagement
Function    Write-PrinterNfcTag    PrintManagement

多くのコマンドレットがありますね。 今回利用するのは、*-PrinterPortコマンドレットです。

Get-Command -Module PrintManagement -Noun PrinterPort
CommandType Name               ModuleName
----------- ----               ----------
Function    Add-PrinterPort    PrintManagement
Function    Get-PrinterPort    PrintManagement
Function    Remove-PrinterPort PrintManagement

現在のプリンターポートを取得する

まずは、現在のプリンターポート取得です。

これは、Get-PrinterPortコマンドレットで可能です。

Windows 8.1 インストール直後のデフォルトはこんな感じですね。

Get-PrinterPort
Name        ComputerName Description      PortMonitor
----        ------------ -----------      -----------
LPT1:                    Local Port       Local Monitor
COM3:                    Local Port       Local Monitor
LPT2:                    Local Port       Local Monitor
COM4:                    Local Port       Local Monitor
LPT3:                    Local Port       Local Monitor
PORTPROMPT:              Local Port       Local Monitor
FILE:                    Local Port       Local Monitor
COM1:                    Local Port       Local Monitor
COM2:                    Local Port       Local Monitor
nul:                     Local Port       Local Monitor
SHRFAX:                  Fax Monitor Port Microsoft Shared Fax Monitor

プリンターポートの追加

TCP/IPプリンターポートを追加しましょう。

これは、Add-PrinterPortコマンドレットで可能です。例えば、192.168.11.200 のプリンターポートを追加してみましょう。

TCP/IPプリンターポートは、通常ポートと名称を同一で作るのでこのままですね。(WindowsでGUIを使って追加したときのデフォルトの動作)

[ipaddress]$TCPIPPort = "192.168.11.200"
Add-PrinterPort -PrinterHostAddress $TCPIPport -Name $TCPIPport

これで、Get-PrinterPortすると追加結果がわかります。

Name           ComputerName Description          PortMonitor
----           ------------ -----------          -----------
COM1:                       Local Port           Local Monitor
COM2:                       Local Port           Local Monitor
COM3:                       Local Port           Local Monitor
COM4:                       Local Port           Local Monitor
FILE:                       Local Port           Local Monitor
LPT1:                       Local Port           Local Monitor
LPT2:                       Local Port           Local Monitor
LPT3:                       Local Port           Local Monitor
nul:                        Local Port           Local Monitor
PORTPROMPT:                 Local Port           Local Monitor
192.168.11.200              Standard TCP/IP Port TCPMON.DLL
SHRFAX:                     Fax Monitor Port     Microsoft Shared Fax Monitor

プリンターポートの削除

誤って追加した場合は、Remove-PrinterPortコマンドレットで削除可能です。

[ipaddress]$TCPIPPort = "192.168.11.200"
Remove-PrinterPort -Name $TCPIPPort

消えてますね。

Name        ComputerName Description      PortMonitor
----        ------------ -----------      -----------
LPT1:                    Local Port       Local Monitor
COM3:                    Local Port       Local Monitor
LPT2:                    Local Port       Local Monitor
COM4:                    Local Port       Local Monitor
LPT3:                    Local Port       Local Monitor
PORTPROMPT:              Local Port       Local Monitor
FILE:                    Local Port       Local Monitor
COM1:                    Local Port       Local Monitor
COM2:                    Local Port       Local Monitor
nul:                     Local Port       Local Monitor
SHRFAX:                  Fax Monitor Port Microsoft Shared Fax Monitor

既存プリンターへのポートセット

ないのですね。既定では。これは CIM (WMI) を利用します。

プリンターの取得

まずは Win43_printer でプリンターを取得します。

$printer = Get-CimInstance -Class Win32_printer | where name -eq $printerName

PortName のセット

あとは、PortNameをセットします。単純にいうとこうですね。

$printer.PortName = $TCPIPport

ファンクション

面倒なので用意しました。

これはSet-PrinterPort のみの機能です。

GitHub-SetPrinterPort

#Requires -Version 3.0

function Set-PrinterPort
{
<#
.Synopsis
   Set TCP/IP to PrinterName you specified.
.DESCRIPTION
   This Cmdlet will Assign current TCP/IP Port include what you specified.
.EXAMPLE
    Set-PrinterPort -TCPIPport 192.168.1.2 -printerName "HP-hogehoge"
.EXAMPLE
    Set-PrinterPort -TCPIPport 192.168.1.2 -printerName "HP-hogehoge" -Verbose
#>

    [CmdletBinding()]
    Param
    (
        # Input TCP/IP port number you want to create, assign to Printer
        [Parameter(
            Mandatory,
            Position = 0)]
        [ipaddress]
        $TCPIPport,

        # Input Printer Name to asshign Port Number you want
        [Parameter(
            Mandatory,
            Position = 1,
            ValueFromPipeline,
            ValueFromPipelineByPropertyName)]
        [string]
        $printerName
    )

    process
    {
        if (-not(Get-PrinterPort | where Name -eq $TCPIPport))
        {
            throw ("Printer Port '{0}' not found exception!" -f $TCPIPport)
        }
        else
        {
            Write-Verbose ("Printer port '{0}' found." -f $TCPIPport)
        }

        $printers = Get-CimInstance -Class Win32_printer | where name -eq $printerName

        if ($printers.count -ne 0)
        {
            foreach ($printer in $printers)
            {
                if ($printer.PortName -ne $TCPIPport)
                {
                    Write-Verbose ("Setting Printer '{0}' port from '{1}' to '{2}'" -f $printer.Name, $printer.PortName, $TCPIPport)
                    $printer.PortName = $TCPIPport
                }
                else
                {
                    Write-Verbose ("Printer '{0}' port '{1}' was already '{2}'" -f $printer.Name, $printer.PortName, $TCPIPport)
                }
            }
        }
        else
        {
            throw ("Printer name '{0}' not exist exception!" -f $printerName)
        }
    }
}

こっちは、プリンターポートの有無を確認しなければ追加、さらに指定したプリンター名にセットまで拡張したものです。

Github - Set-PrinterPortExtend

#Requires -Version 3.0

function Set-PrinterPortExtend
{
<#
.Synopsis
   Add/check TCP/IP and assign to PrinterName you specified.
.DESCRIPTION
   This Cmdlet will check current TCP/IP Port include what you specified.
   If not exist, then add TCP/IP Port.
   Next, Get Printer Name as you desired and check Port Number which assigned to it.
   If PortNumber assigned was not same as Port Number you specified, then change it.
.EXAMPLE
    Set-PrinterPort -TCPIPport 192.168.1.2 -printerName "HP*"
.EXAMPLE
    Set-PrinterPort -TCPIPport 192.168.1.2 -printerName "HP*" -Verbose
#>

    [CmdletBinding()]
    Param
    (
        # Input TCP/IP port number you want to create, assign to Printer
        [Parameter(
            Mandatory,
            Position = 0)]
        [ipaddress]
        $TCPIPport,

        # Input Printer Name to asshign Port Number you want
        [Parameter(
            Mandatory,
            Position = 1,
            ValueFromPipeline,
            ValueFromPipelineByPropertyName)]
        [string]
        $printerName
    )

    process
    {
        if (-not(Get-PrinterPort | where Name -eq $TCPIPport))
        {
            if ($includeAddPort)
            {
                Write-Warning ("Printer port '{0}' not found. Adding port." -f $TCPIPport)
                Add-PrinterPort -PrinterHostAddress $TCPIPport -Name $TCPIPport
            }
            else
            {
                throw ("Printer Port '{0}' not found exception!" -f $TCPIPport)
            }
        }
        else
        {
            Write-Verbose ("Printer port '{0}' found." -f $TCPIPport)
            if ($PSBoundParameters.Verbose.IsPresent)
            {
                Get-PrinterPort | where Name -eq $TCPIPport
            }
        }

        $printers = Get-CimInstance -Class Win32_printer | where name -like $printerName

        if ($printers.count -ne 0)
        {
            foreach ($printer in $printers)
            {
                if ($printer.PortName -ne $TCPIPport)
                {
                    Write-Verbose ("Setting Printer '{0}' port from '{1}' to '{2}'" -f $printer.Name, $printer.PortName, $TCPIPport)
                    $printer.PortName = $TCPIPport
                }
                else
                {
                    Write-Verbose ("Printer '{0}' port '{1}' was already '{2}'" -f $printer.Name, $printer.PortName, $TCPIPport)
                }
            }
        }
        else
        {
            throw ("Printer name '{0}' not exist exception!" -f $printerName)
        }
    }
}

まとめ

なぜ Set-PrinterPort が既定でないのか謎ですね。海外のフォーラムでも困っている人が多いようなので、日本語記事にしてみました。

お役に立てば何よりです。