Sledování tisku ve firmě
Sledování tisku ve firmě
Jak dělat statistiky tisku pomocí nástrojů ve Windows serveru    

Opět jsem se jednou pustil do něčeho, o čem jsem nic nevěděl. Vzhledem k počtu tiskáren a kopírek, které mám v práci, jsem potřeboval nějakým způsobem začít auditovat, kolik se kde vytiskne stránek. Podle toho se pak dají plánovat náhrady, přesuny a vůbec rozpočet na IT. Co se týká velkých A3 kopírek / tiskáren, tak na nich používáme MyQ, takže není problém nechat si poslat každý měsíc report, kde se dozvím kolik stránek se kde vytisklo a nakopírovalo. Horší je to u menších tiskáren, kde nic takového nemáme. Ale i tam to jde sledovat. Možností, jak to sledovat je více. Pokud máte pár tiskáren, tak asi není problém jednou měsíčně vlézt do servisního menu, vytisknout si stránku s informacemi o tiskárně a opsat si stav počítadla. Pak je tu možnost dostat data přes SNMP. Každá normální tiskárna toho na sebe přes SNMP napráská spoustu. Od počtu vytisknutých stran až po stav toneru. Jenže dostat z tiskárny informace pro složitější statistiku není úplně lehké. A vůbec mi práce s SNMP připadá zbytečně komplikovaná. Takže já použiju log na print serveru a powershell script, který si bude data každý den ukládat bokem.

Základem je mít tiskárny nasdíleny přes Active Directory. Tedy lépe řečeno je vhodné mít jeden server, přes který budou sdíleny všechny tiskárny. A technicky zabránit tisku přímo na IP adresu z PC. To se dá udělat třeba tak, že se všechny tiskárny dají do speciální VLANy a přístup do té VLANy je pouze z toho tiskového serveru. Pak stačí zapnout logování tisku na tom serveru a všechna data budou na jednom místě. Tak to zapneme. Ve starší dokumentaci se vždycky u auditování tisku psalo, že je potřeba jít do vlastností tiskárny, na záložku security, do advanced, blablabla. Našel jsem několik návodů, které popisují stejně i u Windows Server 2012 R2, ale není to potřeba. Stačí zapnout log. Můžete to naklikat, ale to se mi nechce, takže použiju PowerShell.

Get-WinEvent -Listlog "Microsoft-Windows-PrintService/Operational" | fl IsEnabled, MaximumSizeInBytes

IsEnabled : False
MaximumSizeInBytes : 1052672

Potřebujeme zapnout log Microsoft-Windows-PrintService/Operational a nastavit jeho maximální velikost. Defaultní velikost, kterou vidíte výše mi asi po dvanácti hodinách začala přepisovat záznamy. Já je chci aspoň pár dnů držet, takže povolím log a nastavím velikost na 10MB (Bacha, velikost musí být dělitelná 64kB). Jak na to:

$logName = "Microsoft-Windows-PrintService/Operational"
$log = New-object System.Diagnostics.Eventing.Reader.EventLogConfiguration $logName
$log.isEnabled=$true
$log.MaximumSizeInBytes=10240000
$log.savechanges()

A uděláme zase kontrolu, jak to dopadlo:

Get-WinEvent -Listlog "Microsoft-Windows-PrintService/Operational" | fl IsEnabled, MaximumSizeInBytes

IsEnabled : True
MaximumSizeInBytes : 10240000

Teď se nám začnou logovat tisky. Jen tak pro zajímavost, defaultní velikost logu mi nestačila ani na 24 hodin. Co 24 hodin, záznamy v logu se dopoledne přibližně po třech hodinách začaly přepisovat. Současná velikost 10 MB vydrží bez přepsání přibližně sedm dní. Samozřejmě by bylo možné zvednou velikost logu, aby udržel celý měsíc, ale je tam riziko, že při nějakém výjimečném měsíci se data odmažou. A naopak, pokud udělám moc velký soubor, tak se bude zpracovávat velké množství dat a zvedne se zátěž serveru. Já jsem zvolil takovou cestu, že mám data za týden, ale každou noc si odliju data za předchozí den do textového souboru na disk. Mohl bych to samozřejmě cpát i do databáze, například MS SQL serveru, ale tam je strašně režije při navazování spojení. Neumím to udělat tak, aby se to tam nasázelo rychle. Nicméně není problém později dostat data z toho texťáku do MS SQL. Takže jdeme zpracovávat log.

Těch záznamů v logu se ukládá víc, než potřebujeme. Mají různé ID. Pro nás je podstatné ID 307. Vypadají nějak takto.

Document 26, Print Document owned by jan.kovar on KOVAR was printed on prt_14_chodba through port 192.168.89.51. Size in bytes: 17173. Pages printed: 1. No user action is required.

Všechny záznamy jsou poskládány stejně. To je super když z toho chceme dostat jen nějaká data. Třeba mezer je ve všech záznamech stejný počet, takže se podle nich dá rozsekat ta zpráva na jednotlivé slova, data, položky. Ve zprávě je vidět jméno uživatele - v tomto případě jan.kovar, jméno počítač, ze kterého se tisklo: KOVAR, jméno tiskové fronty (budu mluvit o jménu tiskárny) v systému prt_14_chodba a je tam vidět počet stránek, které uživatel vytisknul. Tady se asi zastavím. Aby to slušně fungovalo, tak je vhodné pojmenovat tiskárny nějakým rozumným způsobem, ideálně nějakým prefixem. V našem případě mají běžné tiskárny prefix prt_, pak tu máme nějaké zebry a plottry. V tiskárnách na serveru je i PDF a XPS tiskárna, tam ale nemá smysl cokoliv sledovat, takže budu v logu hledat řetězec: prt, zeb a plot. Jak načíst data z logu?

Get-WinEvent -LogName "Microsoft-Windows-PrintService/Operational"

Takže co budeme dělat? Vytvoříme dva scripty. Jeden script se bude spouštět denně a vytáhne z logu čas, jméno uživatele, jméno tiskové fronty a počet vytisknutých stránek za předchozí den a přidá je do souboru, který bude udržovat data za měsíc. Pak budeme mít druhý script, který první den nového měsíce vezme data za předchozí měsíc a udělá statistiku za jednotlivé tiskárny - kolik se na které vytisklo a udělá druhou statistiku za uživatele, kolik toho kdo vytiskl a připraví nám prázdný soubor, do kterého se budou sypat data nového měsíce. Jak to bude celé vypadat?

$yesterday = (get-date (get-date).addDays(-1) -UFormat "%m/%d/%Y")
$mesic = (get-date (get-date).addDays(-1) -UFormat "%Y-%m")
$filename = "c:\Scripts\printer_stats_" + $mesic + ".txt"
$messages = Get-WinEvent -LogName "Microsoft-Windows-PrintService/Operational" | where {$_.timecreated -like "*$yesterday*" -and $_.id -eq 307 -and ($_.message -like "*prt_*" -or $_.message -like "*zeb*" -or $_.message -like "*plot*")} | sort timecreated

foreach ($msg in $messages) {

$text = $msg.message
$cas = $msg.timecreated

# Jak dostat jmeno tiskarny z logu

$printer_all_out = $text.split(" ")
$printer = $printer_all_out[12]

# Jak dostat jmeno uzivatele z logu

$user = $printer_all_out[6]

# Jak dostat pocet vytisknutych stranek z logu

$end_out = $printer_all_out[23].split(".")
$count = $end_out[0]

$result = '"' + $cas + '","' + $user + '","' + $printer + '","' + $count + '"'
$result >> $filename

}

Největší porod bylo porovnávání datumů. PowerShell vypisuje datum jinak, než jak si jej uchovává a porovnávání je pak komplikované. V prvním řádku do proměné $yesterday dám datum přechozího dne ve formátu, který mi fungoval pro porovnání s logem. Proměnnou $mesic použiju do jména souboru. Každý den který patří do stejného měsíce ukládám do společného souboru. A $filename je cesta k souboru, kam budu vkládat výsledky.

$messages = Get-WinEvent -LogName "Microsoft-Windows-PrintService/Operational" | where {$_.timecreated -like "*$yesterday*" -and $_.id -eq 307 -and ($_.message -like "*prt_*" -or $_.message -like "*zeb*" -or $_.message -like "*plot*")} | sort timecreated

Tady jsem do proměnné $messages načetl záznamy z logu z předchozího dne, očesal jsem to o ID, které nechceme a beru jen ty, které obsahují nějakou naši tiskárnu a seřadil jsem je, ať jdou v souboru za sebou. A pak budeme brát řádek po řádku z $messages a budeme očesávat text. Čas je jednoduchý, ten vezmeme z logu a už s ním není potřeba nic dělat. Text zprávy v logu musíme rozsekat. Na to použijeme split. U té jsem se trochu vztekal, protože jsem netušil, že to nefunguje na řetězec, ale na jednotlivé znaky. Takže pokud byste třeba chtěl rozdělit řetězec podle řetězce "prt", tak nebude hledat ten řetězec, ale kterýkoliv z těch tří znaku a když některý z nich najde, tak text rozdělí. Výsledek pak naháže do pole. No já hledám mezery a spočítal jsem, že po dvanácté mezeře bude jméno tiskárny. A protože za jménem tiskárny je zase mezera, tak máme hotovo. V proměnné $printer máme jméno tiskárny. Uživatel bude podobný případ. Ten je po šesté mezeře a za ním je další mezera, takže máme hotovo i pro proměnnou $user. Pak potřebujeme vědět, kolik stránek se vytisklo. Tahle informace je za 23. mezerou, ale za číslem není mezera, ale tečka, takže musíme udělat další split, ať se jí zbavíme. A pak to celé vložím jako řetězec do proměnné $result a přihodím k souboru, který jsem si připravil. Pokud to pouštíte poprvé, tak si do souboru udělejte hlavičku. Na prvním řádku má být: datum,user,tiskarna,pocet

Otestujte si, že vám všechno chodí. Pokud ano, tak dejte tento script do scheduled tasks. Založíte basic tasks, jako program spouštíte powershell a do políčka Add arguments dáte: -file "c:\scripts\print_report_daily.ps1" Spouštějte to pod uživatelem, který má práva run as batch job. Pokud vám všechno prošlo, tak se vám vytvořil soubor, který vypadá nějak takto:

datum,user,tiskarna,pocet
"05/05/2016 13:35:32","lu.lin","prt_251_laborator","1"
"05/05/2016 13:35:14","sergej.stokurev","prt_62_serizovaci","1"
"05/05/2016 13:35:02","oje.bahlstrom","prt_65_chodba","1"
"05/05/2016 13:34:57","rani.srani","prt_65_chodba","10"

Tak a každý den se přisypou do souboru nové záznamy z logu. A první den nového měsíce si spustíme nový script, který nám z těchto dat udělá dva měsíční reporty. Jeden spočítá kolik stránek se vytisklo na každé tiskárně a druhý nám spočítá, kolik stránek vytiskl každý uživatel. Na to se výborně hodí hash table. Budeme počítat, kolik toho spočítali uživatelé a nevíme kteří uživatelé.

$tiskarny = @{}
$users = @{}
$tento_mesic = (get-date -UFormat "%Y-%m")
$minuly_mesic = (get-date (get-date).addDays(-1) -UFormat "%Y-%m")
$input_file = "c:\Scripts\printer_stats_" + $minuly_mesic + ".txt"
$output_file_printer = "c:\Scripts\printer_stats_" + $minuly_mesic + "_per_printer.txt"
$output_file_user = "c:\Scripts\printer_stats_" + $minuly_mesic + "_per_user.txt"
$new_input_file = "c:\Scripts\printer_stats_" + $tento_mesic + ".txt"

$data = import-csv $input_file

foreach ($line in $data) {

$tiskarna = $line.tiskarna
$count = [int]$line.pocet
$decide = $tiskarny.ContainsKey($tiskarna)

if ($decide -eq $true) {

$oldcount = [int]$tiskarny.get_item($tiskarna)
$newcount = $oldcount + $count
$tiskarny.set_item($tiskarna,$newcount)

}
else {
$tiskarny.add($tiskarna,$count)
}

$user = $line.user
$count = [int]$line.pocet
$decide = $users.ContainsKey($user)

if ($decide -eq $true) {

$oldcount = [int]$users.get_item($user)
$newcount = $oldcount + $count
$users.set_item($user,$newcount)

}
else {
$users.add($user,$count)
}

}
$tiskarny.getenumerator() | select key, value | export-csv $output_file_printer -notypeinformation
$users.getenumerator() | select key, value | export-csv $output_file_user -notypeinformation

"datum,user,tiskarna,pocet" > $new_input_file

Na začátku vytvoříme dvě prázdné hash tables. Hash table uchovává dvojice, klíč a hodnotu. V našem případě budeme mít v $tiskarny jako klíč jméno tiskárny a jako hodnotu počet stránek, které se na ní vytiskly. V případě $users bude klíč uživatelské jméno a jako hodnota bude opět počet stránek, které uživatel vytiskl. Na začátku vkládám do proměnných datumy. Pak definuju cesty k souborům a potřebuji ty datumy pro jméno souboru odkud budu brát data a kam je budu ukládat. Pro ukládání budou dva soubory. A na konec definuju nový vstupní soubor. To je soubor, kam na konci scriptu vložím hlavičku, aby se tam pak přidávala data dalšího měsíce.

Zpracování je jednoduché. Načtu data z CSV. Vezmu si tiskárnu a počet stránek. Pak se podívám, jestli v hash table existuje klíč se jménem té tiskárny. Jestli ano, tak si vytáhnu počet vytištěných stránek a přičtu další. Pokud ne, tak tam vložím ten klíč s počtem stránek. Prakticky totéž pak dělám pro uživatele. Buď tam už je a pak přičtu stránky k aktuálnímu číslu a nebo není, takže to tam vložím. Protože se hash table nedá přímo udělat CSV, tak se musí použít ta funkce getenumerator(). Ta by ale samotná přidala další sloupec, kterým by si pojmenovala klič. Ten tam nechceme, proto ten select, no a pak už jen export do CSV. Zcela záměrně ukládám ty soubory s příponou TXT, protože mi to pak při načítání do excelu nabízí další volby. No a to je vše. Teď už jen druhý script přidat do plánovaných úloh na server. Nezapomeňte, že se musí spustit každý první den v měsíci. A musí se spustit až po tom, co se spustí script, který zpracuje data za předchozí den.

Poslední aktualizace - Středa, 25. Května 2016 12:48
 
 
 
Page 1 of 1
© TNX alias Jan Kovář. Původní design stránky byl určen pro CMS Joomla! a vytvořen společností Siteground web hosting