#powershell
#powershell
Вопрос:
В настоящее время я использую приведенный ниже сценарий PS, чтобы проверить, установлены ли в системе исправления MS за последние месяцы. Сценарий настроен на проверку $env:COMPUTERNAME.mbsa
и Patch_NA.txt
файла и отправку результата в $env:COMPUTERNAME.csv
файл.
Теперь мне нужно изменить этот скрипт, чтобы также извлекать информацию с других POS
устройств в том же месте ( C:UsersCambridgeSecurityScans
) и отправлять результаты в $env:COMPUTERNAME.csv file
. POS
Устройства перечислены следующим образом:
172.26.210.1.mbsa
172.26.210.2.mbsa
172.26.210.3.mbsa
и так далее.
IP
Диапазон во всех наших местоположениях (последний октет) равен 1 - 60
. Есть идеи о том, как я могу это настроить?
Сценарий:
$logname = "C:tempPatchVerify$env:COMPUTERNAME.csv"
[xml]$x=type "C:UsersCambridgeSecurityScans$env:COMPUTERNAME.mbsa"
#This list is created based on a text file that is provided.
$montlyPatches = type "C:TempPatchVerifyPatches_NA.txt"|
foreach{if ($_ -mat"-KB(? <KB>d )"){$matches.KB}}
$patchesNotInstalled=$x.SecScan.check | where {$_.id -eq 500} |foreach{`
$_.detail.updatedata|where {$_.isinstalled -eq "false"}}|Select -expandProperty KBID
$patchesInstalled =$x.SecScan.check | where {$_.id -eq 500} |foreach{`
$_.detail.updatedata|where {$_.isinstalled -eq "true"}}|Select -expandProperty KBID
"Store,Patch,Present"> $logname
$store = "$env:COMPUTERNAME"
foreach ($patch in $montlyPatches)
{
$result = "Unknown"
if ( $patchesInstalled -contains $patch)
{
$result = "YES"
}
if ( $patchesNotInstalled -contains $patch)
{
$result = "NO"
}
"$store,KB$($patch),$result" >>$logname
}
Комментарии:
1. Значит, вам просто нужно выполнить ту же процедуру для файлов, названных в честь IP-адреса каждого устройства, с расширением .mbsa? Вы уже пробовали что-нибудь с этой целью? Какие проблемы у вас возникли с тем, что вы пробовали?
2. Да, это примерно так. Я еще ничего не пробовал, просто начал смотреть на это.
3. Я бы посоветовал вам преобразовать эту часть в функцию, указав в качестве параметра либо полный путь, либо имя файла. Затем вы могли бы запустить цикл ForEach, чтобы довольно легко управлять POS-устройствами. Почему бы вам не попробовать и не сообщить нам, если у вас возникнут проблемы.
4. Спасибо. Я все еще новичок в PS, возможно, вы можете привести мне и пример?
Ответ №1:
В Интернете можно найти много информации о создании функций, но простым примером может быть:
Function Check-Patches{
Param($FileName)
$logname = "C:tempPatchVerify$FileName.csv"
[xml]$x=type "C:UsersCambridgeSecurityScans$FileName.mbsa"
The rest of your existing code goes here...
}
Check-Patches "$env:ComputerName"
For($i=1;$i -le 60;$i ){
Check-Patches "172.26.210.$i"
}
Если вам нужно, чтобы я что-то в этом разбил, дайте мне знать, и я перейду к дальнейшим объяснениям, но из того, что у вас уже есть, похоже, что вы неплохо разбираетесь в теории PowerShell и вам просто нужно знать, какие ресурсы доступны.
Редактировать: я обновил свой пример, чтобы лучше соответствовать вашему сценарию, заставив его принять имя файла, а затем применить это имя файла к переменным $logname и $ x внутри функции.
Сбой…
Сначала мы объявляем, что создаем функцию, используя Function
ключевое слово. Далее следует имя функции, которую вы будете использовать позже для ее вызова, и открывающая фигурная скобка для запуска scriptblock, который составляет фактическую функцию.
Далее идет строка параметров, которая в данном случае очень проста, объявляя только одну переменную в качестве входных данных. В качестве альтернативы это можно было бы сделать как Function Check-Patches ($FileName){
, но когда вы начинаете знакомиться с более продвинутыми функциями, это только сбивает с толку, поэтому я рекомендую придерживаться размещения параметров внутри scriptblock функции. Это первое, что вам нужно внутри вашей функции в большинстве случаев, исключая любую справку, которую вы бы написали для функции.
Затем мы обновили строки для $logname
и [xml]$x
, которые используют $FileName, который функция получает в качестве входных данных.
После этого появляется весь ваш код, который анализирует журналы исправлений и выводит данные в ваш CSV, а также закрывающая фигурная скобка, которая завершает блок сценариев, и функция.
Затем мы вызываем его для имени компьютера и запускаем цикл For . Цикл For выполняет все значения от 1 до 60, и для каждого цикла он использует это число в качестве последнего октета имени файла для ввода в функцию и проверки этих файлов.
Несколько комментариев к остальной части вашего кода. $monthlypatches =
может быть изменено на = type | ?{$_ -match "-KB(? <KB>d )"}|%{$matches.KB}
так, чтобы результаты фильтровались перед циклом ForEach, что может сократить время.
В строках $patchesInstalled и $patchesNotInstalled вам не нужна обратная метка в конце этой строки. Естественно, у вас может быть разрыв строки после начала скриптового блока для цикла ForEach. Наличие его там может быть трудно увидеть позже, если сценарий сломается, и если после него что-то есть (включая пробел), сценарий может сломаться и выдать ошибки, которые трудно отследить.
Наконец, вы дважды перебираете $ x, а затем $monthlyPatches один раз и выполняете множество отдельных записей в файл журнала. Я бы предложил создать массив, заполнить его пользовательскими объектами, которые имеют 3 свойства (сохранить, исправить и представить), а затем вывести это в конце функции. Это немного меняет ситуацию, но затем ваша функция выводит объект, который вы могли бы передать в Export-CSV, или, возможно, позже вы могли бы захотеть, чтобы он делал что-то еще, но, по крайней мере, тогда у вас это было бы. Чтобы сделать это, я бы запустил $ x через коммутатор, чтобы проверить, установлены ли вещи, затем я бы очистил массив, установив для всех monthlypatches, которых еще нет в этом массиве, значение Unknown. Это было бы что-то вроде:
Function Check-Patches{
Param($FileName)
$logname = "C:tempPatchVerify$FileName.csv"
[xml]$x=type "C:UsersCambridgeSecurityScans$FileName.mbsa"
$PatchStatus = @()
#This list is created based on a text file that is provided.
$monthlyPatches = GC "C:TempPatchVerifyPatches_NA.txt"|?{$_ -match "-KB(? <KB>d )"} | %{$matches.KB}
#Create objects for all the patches in the updatelog that were in the monthly list.
Switch($x.SecScan.Check|?{$_.KBID -in $monthlyPatches -and $_.id -eq 500}){
{$_.detail.updatedata.isinstalled -eq "true"}{$PatchStatus =[PSCustomObject][Ordered]@{Store=$FileName;Patch=$_.KBID;Present="YES"};Continue}
{$_.detail.updatedata.isinstalled -eq "false"}{$PatchStatus =[PSCustomObject][Ordered]@{Store=$FileName;Patch=$_.KBID;Present="NO"};Continue}
}
#Populate all of the monthly patches that weren't found on the machine as installed or failed
$monthlyPatches | ?{$_ -notin $PatchStatus.Patch} | %{$PatchStatus = [PSCustomObject][Ordered]@{Store=$FileName;Patch=$_;Present="Unknown"}}
#Output results
$PatchStatus
}
#Check patches on current computer
Check-Patches "$env:ComputerName"|Export-Csv "C:tempPatchVerify$env:ComputerName.csv" -NoTypeInformation
#Check patches on POS Devices
For($i=1;$i -le 60;$i ){
Check-Patches "172.26.210.$i"|Export-Csv "C:tempPatchVerify172.26.210.$i.csv" -NoTypeInformation
}
Комментарии:
1. Спасибо, я настрою это и попробую.
2. Когда у вас будет секунда, можете ли вы прерваться:
3. Я его настроил, но он не записывает информацию в файл журнала.
4. Обновленный ответ, объяснение и предложение альтернативы.
5. Доброе утро и спасибо за разбивку. Я просто попытался запустить то, что у вас есть выше, и это не удается.