Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

в 6:35, , рубрики: kyocera, powershell, WIA, МФУ, системное администрирование, сканирование, установка драйвера

Как и обещал в первой части, за которую я успешно получил инвайт в песочнице, в этой заметке я покажу как подключить сетевые МФУ Kyocera M2035dn, Xerox WorkCentre 3615 и 6505DN, а в конце статьи добавлю небольшой бонус с которым любой скрипт связанный с сетью становится лучше.

Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

Как бы небыли прекрасны гомогенные инфраструктуры, пусть даже в части принтеров и мфу, реальность зачастую ставит свои условия. В то время как пользователи сами в полный рост подключали и успешно сканировали с некогда проблемных МФУ HP, в компанию приехал японский гость — Kyocera M2035dn.

Kyocera M2035dn

Приехал как всегда не в мое уютное админское логово, а сразу на объект и как и мфу от HP, в глаза его я, если честно, даже не видел.
Первым делом качаем драйвер и смотрим содержимое… ба, знакомые все люди:

Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

Есть пометка о том, что подключение сетевое (network) и есть ID!
Попробуем подключить сканер через devcon, подобно тому как мы подключали МФУ от HP в первой части:
.devcon.exe /r install C:DriversScanners2035dnscankmwiadrv.inf "KM_WC_ECOSYS_M2035dn_N_WIA"

Сканер подключился, прописываем в реестр адрес сканера параметром ScannerAddress и запускаем сканирование. Приложение сканирования показало отсканированный лист, все работает отлично. Казалось бы победа, но запуск второй, используемой у нас программы для сканирования, поубавил радости — сканер в ней не отображался.

Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

Оказывается разработчики Kyocera почему-то в драйвере реализовали сканирование только через WIA, для TWAIN надо ставить отдельный косты.. враппер, который пробрасывает TWAIN интерфейс в WIA и возвращает обратно результат. Выглядит гуй этого TWAIN драйвера следующим образом:

Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

При этом, по WIA мы можем подключить несколько сканеров Kyocera, в то время как TWAIN интерфейс у нас будет всегда только один. Либо пользуйтесь WIA, либо каждый раз запускайте нашу утилиту и переключайте сканер. Придется смириться, а пока посмотрим как нам обойти запуск этой утилиты на машине пользователя.
Утилита хранит настройки в ini-файлах, по одному файлу KM_TWAIN*.ini на каждый сетевой сканер и один результирующий файл с описанием сканеров и файлов их настроек.
Скрин обоих файлов, для одного подключенного сканера:

Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

Теперь установка видится следующей:
— подключаем сканер через devcon
— если утилита TWAIN не установлена, ставим её
— добавляем адрес сканера в реестр
— проходимся по реестру в поиске подключенных сканеров Kyocera и на основе данных в реестре генерируем ini-файлы

Расширим функцию подключения сканера из предыдущей заметки следующим кодом, который я постарался по-максимуму прокомментировать:

# знакомый нам участок кода с подключением через devcon
"M2035dn" {
    Push-Location 'C:DriversScannersip2035dnscan'
    if ($(Get-Platform) -eq "Windows x64") {
        .devconx64.exe /r install $destkmwiadrv.inf "KM_WC_ECOSYS_M2035dn_N_WIA"
    } else {
        .devcon.exe /r install $destkmwiadrv.inf "KM_WC_ECOSYS_M2035dn_N_WIA"
    }
    Pop-Location

    # проверяем стоит ли костыль kyocera, если нет ставим в тихом режиме
    $twain = Get-WMIObject -Class Win32_Product -Filter 'Name = "Kyocera TWAIN Driver"'
    if (!($twain)) {
        Push-Location 'C:DriversScanners2035dnscanTWAIN'
        .setup.exe /S /v /qn
        Pop-Location
    }

    # получаем содержимое ветки реестра в которой хранятся настройки сканеров и камер
    $scanclass = 'HKLM:SYSTEMCurrentControlSetControlClass{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}'

    # так как мы только что поставили новый сканер, то его номер будет последним среди сканеров
    $item = (Get-ChildItem $scanclass | Where-Object Name -match "d{4}$" | Select -Last 1).PSChildName

    # добавляем адрес сканера
    New-ItemProperty "$scanclass$itemDeviceData" -Name "ScannerAddress" -Value $ipaddress | Out-Null

    # тут применил расширенный синтаксис Foreach-Object, состоящий из трех частей
    # первая и последняя выполняются по одному разу, при запуске цикла и его окончании соответственно;
    # код в секции process выполняется для каждого элемента цикла
    Get-ChildItem  $scanclass | Foreach-Object -Begin {
        $count = 0
        Add-Type -As System.Web
        # стандартный пароль, который задает утилита
        $pass = '43srWkUjR/8='
        $scanitem = @{}
        $filelist = @()
    } -Process {
        $path = $_.Name -replace 'HKEY_LOCAL_MACHINE', 'HKLM:'
        $prop = Get-ItemProperty $path
        if ($prop.Vendor -eq 'Kyocera') {
            $count ++
            $twfilename = "KM_TWAIN$count`.INI"
            $devicedata = Get-ItemProperty "$pathDeviceData"
            $cont = @{'Unit'='0';'ScannerAddress'=$devicedata.ScannerAddress; 'SSL'='0'}
            $auth = @{'Auth'='0';'UserName'=''; 'Account'='0'; 'ID'='';'Password'=$pass}
            $twcont = @{'Contents'=$cont; 'Authentication'=$auth}
            Out-IniFile -inputobject $twcont -FilePath "$env:temp$twfilename"
            $filelist += , "$env:temp$twfilename"

            $devicename = $devicedata.'Model Name' + " #$count"
            $modelname = $devicedata.'Model Name'
            $scanreg = @{'Name'=$devicename;'Model'=$modelname;'DefFile'=$twfilename;'LastScan'='';'ScanList'='';'Pos'=($count-1)}
            $scanitem.Add("Scanner$count", $scanreg)
        }
    } -End {
        $regfilename = 'RegList.ini'
        $settings = @{'Type'='4'; 'DefaultUse'=$count;'RegNum'=$count;}
        $reglist = @{'Setting'=$settings}
        $reglist += $scanitem
        Out-IniFile -inputobject $reglist -FilePath "$env:temp$regfilename"
        $filelist += , "$env:temp$regfilename"
    }

    # удаляем предыдущие ini-файлы и подкладываем сгенерированные выше с новым сканером
    Get-ChildItem $env:systemdriveusers -Directory -Recurse -Include 'appdata' -Force | ForEach-Object {
        $kyodir = $_.FullName + "RoamingKyoceraKM_TWAIN"
        If (!(Test-Path $kyodir)) {
            New-Item -Type Directory -Path $kyodir
        } else {
            Remove-Item "$kyodir*" -Recurse
        }
        $filelist | ForEach-Object {
            Copy-Item $_ $kyodir -Force | Out-Null
        }
    }
}

В скрипте я использовал функцию вывода хэш-таблицы в ini-файл, вот её код:

function Out-IniFile($inputobject, $filepath) {
    # .Example
    # $Category1 = @{'Key1'='Value1';'Key2'='Value2'}
    # $Category2 = @{'Key1'='Value1';'Key2'='Value2'}
    # $NewINIContent = @{'Category1'=$Category1;'Category2'=$Category2}
    # Out-IniFile -inputobject $NewINIContent -FilePath 'C:MyNewFile.INI'

    $outfile = New-Item -ItemType File -Path $filepath -Force
    foreach ($i in $inputobject.keys) {
        Add-Content -Path $outfile -Value "[$i]"
        Foreach ($j in ($inputobject[$i].keys | Sort-Object)) {
            Add-Content -Path $outfile -Value "$j=$($inputobject[$i][$j])"
        }
        Add-Content -Path $outfile -Value ''
    }
}

Xerox WorkCentre 3615 и 6505DN

Код этот успешно работал и проблем с ним не возникало, наверное, на протяжении полугода пока ветер опять не подул в другую сторону. В сторону Xerox.
В аутлук упало письмо с ip-адресами двух новых мфу, WorkCentre 3615 и WorkCentre 6505DN. Дорога хода мыслей при знакомстве с новым мфу уже проторена, открываем драйвер и видим знакомое:

Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

И настроение мое улучшилось©

Распаковываем драйвер, запускаем консоль, выполняем:
.devcon.exe /r install C:DriversScannersxx3615xrszdim.inf "NON_PNP&WorkCentre3615"

Сканер подключился и на экран выскочил новый, как это принято говорить, воркэраунд, только уже от разработчиков Xerox:

Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

Очередная странная утилита от авторов драйвера для прописывания IP, причем запускается она из драйвера при установке. Значит, для того что бы спрятать ее от пользователя, будем прибивать ее в скрипте, в общем-то не беда.

Сейчас покажу на примере 3615, как расширить функцию подключения сканера. От 6506DN она практически не отличается, разве что другое имя файла драйвера и ID:

"3615" {
    Push-Location 'C:DriversScannersxx3615'
    if ($(Get-Platform) -eq "Windows x64") {
        .devconx64.exe /r install C:DriversScannersxx3615xrszdim.inf "NON_PNP&WorkCentre3615"
    } else {
        .devcon.exe /r install C:DriversScannersxx3615xrszdim.inf "NON_PNP&WorkCentre3615"
    }
    Pop-Location
    
    Get-Process "AIOScanSettings" | Stop-Process -Force

    # не могу вразумительно ответить почему я тут применил reg add,
    # спишем на ностальгию по cmd, а замену на New-ItemProperty оставим домашкою читателю
    & reg.exe add "hklmSOFTWAREXeroxWorkCentre 3615TwainDriver" /v "EnableEnhancedBW" /t REG_DWORD /d 1 /f
    & reg.exe add "hklmSOFTWAREXeroxWorkCentre 3615TwainDriver" /v "ISO_B_Series" /t REG_DWORD /d 1 /f
    & reg.exe add "hklmSOFTWAREXeroxWorkCentre 3615TwainDriver" /v "IP Address" /t REG_SZ /d $ipAddress /f
 
}

Теперь мы умеем подключать целый зоопарк сетевых мфу и совершенно ничего не боимся, осталось добавить какой-нибудь магии… магии snmp!

Ищем МФУ в сети по snmp

SNMP (англ. Simple Network Management Protocol — простой протокол сетевого управления) — стандартный интернет-протокол для управления устройствами в IP-сетях на основе архитектур TCP/UDP.
ru.wikipedia.org/wiki/SNMP

Для работы с snmp из powershell я в скрипте использовал открытую библиотеку sharpsnmp, подробнее о ее использовании можно почитать по адресу: vwiki.co.uk/SNMP_and_PowerShell
После подключения библиотеки получение информации сводится к вызову функции Invoke-SNMPget с указанием Ip и uid, последний из которых легко гуглится.
Пример из кода:
Invoke-SNMPget $ip .1.3.6.1.2.1.25.3.2.1.3.1

Результат работы поиска выводим на экран, о том как это сделать в одну комманду чуть ниже:

Автоматическое подключение сетевых МФУ с возможностью сканирования [Часть 2]

Остается выделить нужный принтер и нажать OK, кстати множественное выделение так же возможно, в этом случае подключатся все выделенные принтеры.
Эту удобную гуёвую магию обеспечивает командлет Out-GridView, отображающий любые переданные в него объекты. При вызове с параметром PassThru, после нажатия OK он передаст дальше по конвейеру выбранные объекты, нам остается только по очереди вызвать наши функции установки драйверов с параметрами пришедшими в объекте из конвейера.

$hosts | Out-GridView -Title "Выберите принтеры для установки" -PassThru | Foreach-Object {
        $printername = $_.Name
        $printersource = $_.Source

        switch -regex ($printername) {
            "xerox.+3615" {
                $modelname = "Xerox Phaser 6600DN"
                $driverpath = 'C:DriversScannersxx6505xrxmozi.inf'
            }
        }

        Write-Host "Добавляется порт IP принтера $printerName"
        Add-PrinterPort $printername $printersource

        Write-Host "Добавляется драйвер принтера $printername"
        Add-PrinterDriver $printername  $driverpath

        Write-Host "Добавляется сканер принтера $printername"
        Add-Scanner $printersource $printername
    }

В процессе изучения откликов принтеров, столкнулся с тем, что принтеры отдают порой имя отличающееся от имени прописанного в драйвере, для обхода этой особенности добавил в скрипт простой свитч с регулярками, которые никогда не промахиваются и как мы знаем полны по Тьюрингу ;-)

switch -regex ($printername) {
    "hp.+3050" {
        $modelName = "HP LaserJet 3050"
    }
    "hp.+3052" {
        $modelName = "HP LaserJet 3052"
    }
    "hp.+3055" {
        $modelName = "HP LaserJet 3055"
    }
    "xerox.+3615" {
        $modelName = "Xerox WorkCentre 3615"
    }
    "xerox.+650[0,5]DN" {
        $modelName = "Xerox Phaser 6600DN"
    }
}
Полный код функции поиска и подключения сетевого принтера

$ErrorActionPreference = "silentlycontinue"

function Main {

	# путь к драйверам
	$driversdistrib = 'C:Drivers'

	# загружаем snmp либу
	$snmplibpath = Join-Path (Get-Location).path "SharpSnmpLib.dll"
	if (Test-Path $snmplibpath) {
		[reflection.assembly]::LoadFrom((Resolve-Path $snmplibpath))
	} else {
		Write-Host "Не удалось найти SharpSnmpLib"
		Exit
	}

	# вычисляем подсеть, без хитрой математики, в лоб и только /24
	$network = (Get-IPaddress).ToString() -replace ".[0-9]{1,3}$"

	# в диапазоне закрепленном за принтерами ищем устройства
	$hosts = 10..40 | ForEach-Object {
		$ip = "$network.$_"
		$snmpanswer= $null
		$snmpanswer = Invoke-SNMPget $ip .1.3.6.1.2.1.25.3.2.1.3.1
		if ($snmpanswer) {
			# формируем объект с двумя свойствами который улетит в переменную $hosts
			[pscustomobject]@{
				Name = $snmpanswer.Data;
				Source = $ip;
			}
		}
	}

	# выводим объекты в гуй с параметром PassThru, который передаст выбранные дальше по конвейеру
	$hosts | Out-GridView -Title "Выберите принтеры для установки" -PassThru | Foreach-Object {
		$printername = $_.Name
		$printersource = $_.Source

		switch -regex ($printername) {
			"hp.+3050" {
				$printername = "HP LaserJet 3050"
				$driverpath = Join-Path $driversdistrib 'Printers3050hppasc01.inf'
			}
			"hp.+3052" {
				$printername = "HP LaserJet 3052"
				$driverpath = Join-Path $driversdistrib 'Printers3050hppasc01.inf'
			}
			"hp.+3055" {
				$printername = "HP LaserJet 3055"
				$driverpath = Join-Path $driversdistrib 'Printers3050hppasc01.inf'
			}
			"hp.+3390" {
				$printername = "HP LaserJet 3390"
				$driverpath = Join-Path $driversdistrib 'Printers3050hppasc01.inf'
			}
			"hp.+153[0,6]" {
				$printername = "HP LaserJet M1530 MFP"
				$driverpath = Join-Path $driversdistrib 'Printers1530hpc1530c.inf'
			}
			"hp.+1522" {
				$printername = "HP LaserJet M1522 MFP"
				$driverpath = Join-Path $driversdistrib 'Printers1522hppcp608.inf'
			}
			"M2035dn" {
				$printername = "Kyocera ECOSYS M2035dn KX"
				$driverpath = Join-Path $driversdistrib 'Printers2035dnhppasc01.inf'
			}			
			"xerox.+3615" {
				$printername = "Xerox WorkCentre 3615"
				$driverpath = Join-Path $driversdistrib 'Scannersxx3615x2GPROX.inf'
			}
			"xerox.+650[0,5]DN" {
				$printername = "Xerox Phaser 6600DN"
				$driverpath = Join-Path $driversdistrib 'Scannersxx6505xrxmozi.inf'
			}
		}

		Write-Host "Добавляется порт IP принтера $printerName"
		Add-PrinterPort $printername $printersource

		Write-Host "Добавляется драйвер принтера $printername"
		Add-PrinterDriver $printername  $driverpath

		Write-Host "Добавляется сканер принтера $printername"
		Add-Scanner $printersource $printername
	}
}
function Add-PrinterPort ($printersource) {
	&cscript C:WindowsSystem32Printing_Admin_Scriptsru-RUprnport.vbs `
	-a -r $printersource -h $printersource -o RAW -n 9100 | Out-Null
}
function Add-PrinterDriver ($printerName, $driverpath) {
	$folder = Split-Path $driverpath
	cscript C:WindowsSystem32Printing_Admin_Scriptsru-RUprndrvr.vbs `
	-a -m $printerName -e Get-Platform -h $folder -i $driverpath
}
function Add-Scanner ($ipaddress, $printername) {
	switch -regex ($printername) {
		"1530" {
			Push-Location (Join-Path $driversdistrib 'Scanners1536scan')
			if ($(Get-Platform) -eq "Windows x64") {
				.hppniscan64.exe -f "hppasc16.inf" -m "vid_03f0&pid_012a&IP_SCAN" -a $ipAddress -n 1
			} else {
				.hppniscan01.exe -f "hppasc16.inf" -m "vid_03f0&pid_012a&IP_SCAN" -a $ipAddress -n 1
			}
			Pop-Location
		}
		"(305d)|(3390)" {
			Push-Location (Join-Path $driversdistrib 'Scanners3055scan')
			switch -regex ($printername) {
				"3050" {
					.hppniscan01.exe -f "hppasc01.inf" -m "vid_03f0&pid_3217&IP_SCAN" -a $ipAddress -n 1
				}
				"3052" {
					.hppniscan01.exe -f "hppasc01.inf" -m "vid_03f0&pid_3317&IP_SCAN" -a $ipAddress -n 1
				}
				"3055" {
					.hppniscan01.exe -f "hppasc01.inf" -m "vid_03f0&pid_3417&IP_SCAN" -a $ipAddress -n 1
				}
				"3390" {
					.hppniscan01.exe -f "hppasc01.inf" -m "vid_03f0&pid_3517&IP_SCAN" -a $ipAddress -n 1
				}
			}
			Pop-Location
		}
		"1522" {
			Push-Location (Join-Path $driversdistrib 'Scanners1522scan')
			if ($(Get-Platform) -eq "Windows x64") {
				.hppniscan64.exe -f "hppasc08.inf" -m "vid_03f0&pid_4517&IP_SCAN" -a $ipAddress -n 1
			} else {
				.hppniscan01.exe -f "hppasc08.inf" -m "vid_03f0&pid_4517&IP_SCAN" -a $ipAddress -n 1
			}
			Pop-Location
		}
		"M2035dn" {
			Push-Location (Join-Path $driversdistrib 'Scanners2035dnscan')
			if ($(Get-Platform) -eq "Windows x64") {
				.devconx64.exe /r install $destkmwiadrv.inf "KM_WC_ECOSYS_M2035dn_N_WIA"
			} else {
				.devcon.exe /r install $destkmwiadrv.inf "KM_WC_ECOSYS_M2035dn_N_WIA"
			}
			Pop-Location

			$twain = Get-WMIObject -Class Win32_Product -Filter 'Name = "Kyocera TWAIN Driver"'
			if (!($twain)) {
				Push-Location (Join-Path $driversdistrib 'Scanners2035dnscanTWAIN')
				.setup.exe /S /v /qn
				Pop-Location
			}

			$scanclass = 'HKLM:SYSTEMCurrentControlSetControlClass{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}'
			$item = (Get-ChildItem $scanclass | Where-Object Name -match "d{4}$" | Select -Last 1).PSChildName
			New-ItemProperty "$scanclass$itemDeviceData" -Name "ScannerAddress" -Value $ipAddress | Out-Null
			Get-ChildItem  $scanclass | ForEach-Object -Begin {
				$count = 0
				Add-Type -As System.Web
				$pass = [System.Web.Security.Membership]::GeneratePassword(12,2)
				$scanitem = @{}
				$filelist = @()
			} -Process {
				$path = $_.Name -replace 'HKEY_LOCAL_MACHINE', 'HKLM:'
				$prop = Get-ItemProperty $path
				if ($prop.Vendor -eq 'Kyocera') {
					$count ++
					$twfilename = "KM_TWAIN$count`.INI"
					$devicedata = Get-ItemProperty "$pathDeviceData"
					$cont = @{'Unit'='0';'ScannerAddress'=$devicedata.ScannerAddress; 'SSL'='0'}
					$auth = @{'Auth'='0';'UserName'=''; 'Account'='0'; 'ID'='';'Password'=$pass}
					$twcont = @{'Contents'=$cont; 'Authentication'=$auth}
					Out-IniFile -inputobject $twcont -FilePath "$env:temp$twfilename"
					$filelist += , "$env:temp$twfilename"

					$devicename = $devicedata.'Model Name' + " #$count"
					$modelname = $devicedata.'Model Name'
					$scanreg = @{'Name'=$devicename;'Model'=$modelname;'DefFile'=$twfilename;'LastScan'='';'ScanList'='';'Pos'=($count-1)}
					$scanitem.Add("Scanner$count", $scanreg)
				}
			} -End {
				$regfilename = 'RegList.ini'
				$settings = @{'Type'='4'; 'DefaultUse'=$count;'RegNum'=$count;}
				$reglist = @{'Setting'=$settings}
				$reglist += $scanitem
				Out-IniFile -inputobject $reglist -FilePath "$env:temp$regfilename"
				$filelist += , "$env:temp$regfilename"
			}
			Get-ChildItem $env:systemdriveusers -Directory -Recurse -Include 'appdata' -Force | ForEach-Object {
				$kyodir = $_.FullName + "RoamingKyoceraKM_TWAIN"
				If (!(Test-Path $kyodir)) {
					New-Item -Type Directory -Path $kyodir
				} else {
					Remove-Item "$kyodir*" -Recurse
				}
				$filelist | ForEach-Object {
					Copy-Item $_ $kyodir -Force | Out-Null
				}
			}
		}
		"6505" {
			Push-Location (Join-Path $driversdistrib 'Scannersxx6505')
			if ($(Get-Platform) -eq "Windows x64") {
				.devconx64.exe /r install $destxrsmoim.inf "NON_PNP&WorkCentre6505"
			} else {
				.devcon.exe /r install $destxrsmoim.inf "NON_PNP&WorkCentre6505"
			}
			Pop-Location

			Get-Process "AIOScanSettings" | Stop-Process -Force

			&reg.exe add "hklmSOFTWAREXeroxWorkCentre 6505TwainDriver" /v "EnableEnhancedBW" /t REG_DWORD /d 1 /f
			&reg.exe add "hklmSOFTWAREXeroxWorkCentre 6505TwainDriver" /v "IP Address" /t REG_SZ /d $ipAddress /f
		}
		"3615" {
			Push-Location (Join-Path $driversdistrib 'Scannersxx3615')
			if ($(Get-Platform) -eq "Windows x64") {
				.devconx64.exe /r install $destxrszdim.inf "NON_PNP&WorkCentre3615"
			} else {
				.devcon.exe /r install $destxrszdim.inf "NON_PNP&WorkCentre3615"
			}
			Pop-Location

			Get-Process "AIOScanSettings" | Stop-Process -Force

			&reg.exe add "hklmSOFTWAREXeroxWorkCentre 3615TwainDriver" /v "EnableEnhancedBW" /t REG_DWORD /d 1 /f
			&reg.exe add "hklmSOFTWAREXeroxWorkCentre 3615TwainDriver" /v "ISO_B_Series" /t REG_DWORD /d 1 /f
			&reg.exe add "hklmSOFTWAREXeroxWorkCentre 3615TwainDriver" /v "IP Address" /t REG_SZ /d $ipAddress /f
		}
	}
}
function Get-IPaddress {
	$ipWmiObject = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "IPEnabled = 'True'"
	$ipWmiObject.IPAddress -match "^192.([0-9]{1,3}.){2}[0-9]{1,3}$"
}
function Get-Platform {
	if ([System.Environment]::Is64BitOperatingSystem) {
		"Windows x64"
	} else {
		"Windows NT x86"
	}
}
function Out-IniFile($inputobject, $filepath) {
	# .Example
	# $Category1 = @{'Key1'='Value1';'Key2'='Value2'}
	# $Category2 = @{'Key1'='Value1';'Key2'='Value2'}
	# $NewINIContent = @{'Category1'=$Category1;'Category2'=$Category2}
	# Out-IniFile -inputobject $NewINIContent -FilePath 'C:MyNewFile.INI'

	$outfile = New-Item -ItemType File -Path $filepath -Force
	foreach ($i in $inputobject.keys) {
		Add-Content -Path $outfile -Value "[$i]"
		Foreach ($j in ($inputobject[$i].keys | Sort-Object)) {
			Add-Content -Path $outfile -Value "$j=$($inputobject[$i][$j])"
		}
		Add-Content -Path $outfile -Value ''
	}
}
function Invoke-SNMPget {
	param (
		[string]$sIP,
		$sOIDs,
		[string]$Community = "public",
		[int]$UDPport = 161,
		[int]$TimeOut=30
		)
	$vList = New-Object 'System.Collections.Generic.List[Lextm.SharpSnmpLib.Variable]'
	foreach ($sOID in $sOIDs) {
		$oid = New-Object Lextm.SharpSnmpLib.ObjectIdentifier ($sOID)
		$vList.Add($oid)
	}
	$ip = [System.Net.IPAddress]::Parse($sIP)
	$svr = New-Object System.Net.IpEndPoint ($ip, 161)
	$ver = [Lextm.SharpSnmpLib.VersionCode]::V1

	try {
		$msg = [Lextm.SharpSnmpLib.Messaging.Messenger]::Get($ver, $svr, $Community, $vList, $TimeOut)
	} catch {
		return $null
	}

	$res = @()
	foreach ($var in $msg) {
		$line = "" | Select OID, Data
		$line.OID = $var.Id.ToString()
		$line.Data = $var.Data.ToString()
		$res += $line
	}
	$res
}

. Main

На этом на сегодня всё, надеюсь мои заметки помогут вам забыть о проблемах с сетевыми принтерами и освободят время для изучения PowerShell.
Спасибо за внимание тем, кто дочитал до этого момента ;-)

Автор: rbobot

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js