Szybka zmiana portów drukarek


windows-server

Dzień dobry, poza byciem pasjonatą webdesigner-em zawodowo jestem integratorem – administratorem do wynajęcia.

Dzisiaj jeden z naszych dużych klientów przedstawił dość nietypową prośbę jak na poziom usług, które proponujemy – zazwyczaj zajmujemy się dużymi wdrożeniami lub administracją złożonych środowisk wirtualizacyjnych. Klient jest w trakcie migracji środowiska sieciowego co ciągnie za sobą różne zadania administracyjne, czasem tak prozaiczne jak przeadresowanie wszystkich drukarek wewnątrz korporacji.

Zmiana adresacji samych urządzeń fizycznych to żmudne zadanie, ja miałem na tyle szczęścia, że udało się to zrobić za pomocą ansible, choć i tak ze względu na różnorodność hardware (Canon, Lexmark, Brother) nie wszystko dało i chciało się automatyzować.

Co jednak można z całą pewnością zautomatyzować to dodanie portu na podstawie starego, podpięcie do niego drukarki i usunięcie starego portu. Od początku wiedziałem, że problem ten można rozwiązać dwojako. Zrobić to ręcznie albo napisać skrypt, który zrobi to za mnie.

Skrypt

Aby bezpiecznie używać skryptów w środowisku produkcyjnym, szczególnie tym dużym, dużej międzynarodowej firmy należy go najpierw przeanalizować, żeby wiedzieć co dokładnie robi skrypt, czego możemy się spodziewać po jego wykonaniu i czy po jego egzekucji w systemie nie zostaną niepożądane śmieci. Przeanalizujmy więc skrypt, który użyłem do wykonania operacji w obrębie WinSrv.

Zacznijmy od początku czyli pobrania starego i nowego IP żeby powershell wiedział co i na co ma podmienić.

#Najpierw należy zadbać aby nasz skrypt dobrze obsłużył dekorator Parameter
[CmdletBinding()] 
#Następnie definiujemy parametry, będziemy podawać je po wywołaniu skryptu
param(
    [Parameter (Mandatory=$true,Position=0,HelpMessage="Printer's old IP: ")][String]$OldIP,
    [Parameter (Mandatory=$true,Position=1,HelpMessage="Printer's new IP: ")][String]$NewIP
)

Następnie zdefiniowałem sobie furtkę w postaci logowania operacji, każde wykonanie skryptu tworzy plik tekstowy dot. pojedynczego wykonania. Funkcja logowania korzysta z informacji, które pojawiają się w konsoli. Oczywiście można ten krok pominąć jednak w niektórych przypadkach pomogło to szybko sprawdzać czy dobra drukarka została “zautomatyzowana”. Tak więc definiujemy funkcje Log, która będzie zapisywała wszystko co pojawi się w prompt-cie. Informację będą zapisywały się w folderze, w którym znajduje się skrypt, oprócz starego IP w nazwie pliku znajdzie się też zmienna środowiskowa, czyli nazwa komputera oraz data.

function Log {
    [CmdletBinding()]
    param(
        [Parameter (Mandatory=$true,Position=1,HelpMessage="String to be saved to log file and displayed to screen: ")][String]$String,
        [Parameter (Mandatory=$false,Position=2)][String]$Color = "White",
        [Parameter (Mandatory=$false,Position=3)][String]$Logfile = $myinvocation.mycommand.Name.Split(".")[0] + "_" + (Get-Date -format yyyyMMdd_hhmmsstt) + ".txt"
    )
    write-host $String -foregroundcolor $Color  
    ((Get-Date -format "yyyy.MM.dd hh:mm:ss tt") + ": " + $String) | out-file -Filepath $Logfile -append
}

Dalej chcemy wyświetlić informację o starym porcie.

Jeśli programujecie w jakimkolwiek języku to pewnie nie jest to dla was żadna nowość, zresztą jeśli umiecie programować to pewnie dawno przerwaliście czytanie, ściągnęliście skrypt i analizujecie go na własną rękę. W PowerSellu tak jak w innych – nie wszystkich – językach programowania możecie przypisać obiekt do zmiennej. Następnie skorzystać z właściwości (properties) tego obiektu wyrażeniem “kropkowym?” – to na pewno ma fachową nazwę, podejrzewam, że nawet ją gdzieś słyszałem ale teraz nie jestem sobie w stanie tego przypomnieć.

#Pobieramy port
$Port = Get-PrinterPort -Name "IP_$OldIP"
# Następnie korzystając z wcześniej zdefiniowanej funkcji log wyświetlamy oraz zapisujemy żądane informacje
log "Old printer port:" Cyan $LogFile
#zwróćcie proszę uwagę w jaki sposób wyciągamy informację o protokole, opisie, nazwie itd.
log ("    Protocol:           " + $port.Protocol) Cyan $LogFile
log ("    Description:        " + $port.Description) Cyan $LogFile
log ("    Name:               " + $port.Name) Cyan $LogFile
log ("    Port Number:        " + $port.PortNumber) Cyan $LogFile
log ("    PrinterHostAddress: " + $port.PrinterHostAddress) Cyan $LogFile
log ("Printer was attached to printer port: " + (Get-Printer | Where-Object { $_.PortName -eq "IP_$OldIP" }).PortName) Cyan $LogFile

Teraz część właściwa, można powiedzieć wykonawcza, całego skryptu. Tak dobrze widzicie, to tylko 3 linijki ale przecież właśnie 3 czynności mieliśmy wykonać. Dodać nowy port, dodać do niego drukarkę, usunąć stary port.

# Tworzymy port
Add-PrinterPort -Name "IP_$NewIP" -PrinterHostAddress $NewIP
#
# Przypisujemy drukarkę do nowego portu, zwróćcie uwagę, że najpierw musimy pobrać starą drukarkę, na podstawie starego IP.
# później przez dwa pipe-y wartość przekazujemy do funkcji set printer
Get-Printer | Where-Object { $_.PortName -eq "IP_$OldIP" } | Set-Printer -PortName "IP_$NewIP" 
#
# Usuwamy stary port
Remove-PrinterPort -Name "IP_$OldIP"
#

Warto jeszcze zalogować zmianę, czyli wyświetlić info o “nowej” drukarce. Może być to równocześnie bardzo użyteczne gdy np. chcielibyśmy wszystko automatycznie zapisywać do excela, pliku csv lub bazy danych. Tak aby później mieć tabelę z IPkami naszych drukarek.

$Port = Get-PrinterPort -Name "IP_$NewIP"
log "New printer port:" Green $LogFile
log ("    Protocol:           " + $port.Protocol) Green $LogFile
log ("    Description:        " + $port.Description) Green $LogFile
log ("    Name:               " + $port.Name) Green $LogFile
log ("    Port Number:        " + $port.PortNumber) Green $LogFile
log ("    PrinterHostAddress: " + $port.PrinterHostAddress) Green $LogFile
log ("Printer is now attached to printer port: " + (Get-Printer | Where-Object { $_.PortName -eq "IP_$NewIP" }).PortName) Green $LogFile
log ("Port is now attached to printer: " + (Get-Printer | Where-Object { $_.PortName -eq "IP_$NewIP" }).Name) Green $LogFile

W razie problemów piszcie, dzwońcie, chętnie wyjaśnię 🙂 Poniżej pełny skrypt. Wystarczy zapisać go z rozszerzeniem *.ps1 i wywołać za pomocą .\mojskrypt.ps1 192.168.1.41 10.10.10.11

 [CmdletBinding()]
param(
    [Parameter (Mandatory=$true,Position=0,HelpMessage="Printer's old IP: ")][String]$OldIP,
    [Parameter (Mandatory=$true,Position=1,HelpMessage="Printer's new IP: ")][String]$NewIP
)
#
# Log function
function Log {
    [CmdletBinding()]
    param(
        [Parameter (Mandatory=$true,Position=1,HelpMessage="String to be saved to log file and displayed to screen: ")][String]$String,
        [Parameter (Mandatory=$false,Position=2)][String]$Color = "White",
        [Parameter (Mandatory=$false,Position=3)][String]$Logfile = $myinvocation.mycommand.Name.Split(".")[0] + "_" + (Get-Date -format yyyyMMdd_hhmmsstt) + ".txt"
    )
    write-host $String -foregroundcolor $Color  
    ((Get-Date -format "yyyy.MM.dd hh:mm:ss tt") + ": " + $String) | out-file -Filepath $Logfile -append
}
#
$LogFile = (Get-Location).path + "\Change-PrinterIP_" + $env:COMPUTERNAME + (Get-Date -format yyyyMMdd_hhmmsstt) + ".txt"
$Port = Get-PrinterPort -Name "IP_$OldIP"
log "Old printer port:" Cyan $LogFile
log ("    Protocol:           " + $port.Protocol) Cyan $LogFile
log ("    Description:        " + $port.Description) Cyan $LogFile
log ("    Name:               " + $port.Name) Cyan $LogFile
log ("    Port Number:        " + $port.PortNumber) Cyan $LogFile
log ("    PrinterHostAddress: " + $port.PrinterHostAddress) Cyan $LogFile
log ("Printer was attached to printer port: " + (Get-Printer | Where-Object { $_.PortName -eq "IP_$OldIP" }).PortName) Cyan $LogFile
#
# Create new printer port
Add-PrinterPort -Name "IP_$NewIP" -PrinterHostAddress $NewIP
#
# Assign new printer port to the printer
Get-Printer | Where-Object { $_.PortName -eq "IP_$OldIP" } | Set-Printer -PortName "IP_$NewIP" 
#
# Delete old printer port
Remove-PrinterPort -Name "IP_$OldIP"
#
$Port = Get-PrinterPort -Name "IP_$NewIP"
log "New printer port:" Green $LogFile
log ("    Protocol:           " + $port.Protocol) Green $LogFile
log ("    Description:        " + $port.Description) Green $LogFile
log ("    Name:               " + $port.Name) Green $LogFile
log ("    Port Number:        " + $port.PortNumber) Green $LogFile
log ("    PrinterHostAddress: " + $port.PrinterHostAddress) Green $LogFile
log ("Printer is now attached to printer port: " + (Get-Printer | Where-Object { $_.PortName -eq "IP_$NewIP" }).PortName) Green $LogFile
log ("Port is now attached to printer: " + (Get-Printer | Where-Object { $_.PortName -eq "IP_$NewIP" }).Name) Green $LogFile