Awọn ijabọ ojoojumọ lori ilera ti awọn ẹrọ foju nipa lilo R ati PowerShell

Awọn ijabọ ojoojumọ lori ilera ti awọn ẹrọ foju nipa lilo R ati PowerShell

Ifihan

E kaasan. Fun idaji ọdun kan ni bayi a ti nṣiṣẹ iwe afọwọkọ kan (tabi dipo ṣeto awọn iwe afọwọkọ) ti o ṣe agbejade awọn ijabọ lori ipo awọn ẹrọ foju (kii ṣe nikan). Mo pinnu lati pin iriri ẹda mi ati koodu funrararẹ. Mo nireti fun ibawi ati pe ohun elo yii le wulo fun ẹnikan.

Ibiyi ti nilo

A ni ọpọlọpọ awọn ẹrọ foju (bii 1500 VM ti o pin kaakiri 3 vCenters). Awọn tuntun ti ṣẹda ati awọn ti atijọ ti paarẹ ni igbagbogbo. Lati ṣetọju aṣẹ, ọpọlọpọ awọn aaye aṣa ni a ṣafikun si vCenter lati pin awọn VM si Awọn eto Subsystem, tọka boya wọn jẹ awọn idanwo, ati nipasẹ tani ati nigba ti a ṣẹda wọn. Awọn ifosiwewe eniyan yori si otitọ pe diẹ sii ju idaji awọn ẹrọ naa ni a fi silẹ pẹlu awọn aaye òfo, eyiti o ṣe idiju iṣẹ naa. Lẹẹkan ni gbogbo oṣu mẹfa, ẹnikan yọ jade o bẹrẹ si ṣiṣẹ lori mimu dojuiwọn data yii, ṣugbọn abajade ti dawọ lati ṣe pataki lẹhin ọsẹ kan ati idaji.
Jẹ ki n ṣalaye lẹsẹkẹsẹ pe gbogbo eniyan loye pe awọn ohun elo gbọdọ wa fun ẹda awọn ẹrọ, ilana fun ẹda wọn, ati bẹbẹ lọ. ati bẹbẹ lọ. Ati ni akoko kanna, gbogbo eniyan tẹle ilana yii ati pe ohun gbogbo wa ni ibere. Laanu, eyi kii ṣe ọran nibi, ṣugbọn eyi kii ṣe koko-ọrọ ti nkan naa :)

Ni gbogbogbo, a ṣe ipinnu lati ṣe adaṣe adaṣe deede ti kikun ni awọn aaye.
A pinnu pe lẹta ojoojumọ kan pẹlu atokọ ti awọn ẹrọ ti ko tọ si gbogbo awọn ẹlẹrọ ti o ni iduro ati awọn ọga wọn yoo jẹ ibẹrẹ ti o dara.

Ni aaye yii, ọkan ninu awọn ẹlẹgbẹ mi ti ṣe imuse iwe afọwọkọ kan tẹlẹ ni PowerShell, eyiti lojoojumọ, ni ibamu si iṣeto kan, gba alaye lori gbogbo awọn ẹrọ ti gbogbo awọn vCenters ati ipilẹṣẹ awọn iwe aṣẹ csv 3 (kọọkan fun vCenter tirẹ), eyiti a gbe si disk ti o wọpọ. O pinnu lati mu iwe afọwọkọ yii gẹgẹbi ipilẹ ati ṣe afikun rẹ pẹlu awọn sọwedowo nipa lilo ede R, pẹlu eyiti a ni iriri diẹ.

Ninu ilana ti ipari, ojutu ti gba alaye nipasẹ meeli, data data pẹlu tabili akọkọ ati itan-akọọlẹ (diẹ sii lori eyi nigbamii), ati itupalẹ awọn akọọlẹ vSphere lati wa awọn olupilẹṣẹ gangan ti vm ati akoko ti ẹda wọn.

Ojú-iṣẹ IDE RStudio ati PowerShell ISE ni a lo fun idagbasoke.

A ṣe ifilọlẹ iwe afọwọkọ lati ẹrọ foju Windows deede.

Apejuwe ti gbogboogbo kannaa.

Imọye gbogbogbo ti awọn iwe afọwọkọ jẹ atẹle yii.

  • A gba data lori awọn ẹrọ foju nipa lilo iwe afọwọkọ PowerShell, eyiti a pe nipasẹ R, ati pe a ṣajọpọ abajade sinu csv kan. Ibaraṣepọ iyipada laarin awọn ede ni a ṣe bakanna. (o ṣee ṣe lati wakọ data taara lati R si PowerShell ni irisi awọn oniyipada, ṣugbọn eyi nira, ati nini csvs agbedemeji jẹ ki o rọrun lati ṣatunṣe ati pin awọn abajade agbedemeji pẹlu ẹnikan).
  • Lilo R, a ṣe agbekalẹ awọn aye to wulo fun awọn aaye ti awọn iye wọn n ṣayẹwo. - A n ṣẹda iwe ọrọ kan ti yoo ni awọn iye ti awọn aaye wọnyi fun fifi sii sinu lẹta alaye, eyiti yoo jẹ idahun si awọn ibeere ti awọn ẹlẹgbẹ “Bẹẹkọ, ṣugbọn bawo ni MO ṣe le kun eyi?”
  • A fifuye data fun gbogbo awọn VM lati csv lilo R, ṣẹda dataframe, yọ awọn kobojumu aaye ati ki o ṣẹda ohun alaye xlsx iwe ti yoo ni awọn Lakotan alaye fun gbogbo VMs, eyi ti a po si a pín awọn oluşewadi.
  • A lo gbogbo awọn sọwedowo fun pipe ti kikun ni awọn aaye si dataframe fun gbogbo awọn VM ati ṣẹda tabili ti o ni awọn VM nikan pẹlu awọn aaye ti ko tọ (ati awọn aaye wọnyi nikan).
  • A firanṣẹ atokọ abajade ti awọn VM si iwe afọwọkọ PowerShell miiran, eyiti yoo wo awọn akọọlẹ vCenter fun awọn iṣẹlẹ ẹda VM, eyiti yoo gba wa laaye lati tọka akoko ifoju ti ẹda ti VM ati olupilẹṣẹ ti a pinnu. Eyi jẹ fun ọran nigbati ko si ẹnikan ti o jẹwọ ọkọ ayọkẹlẹ ti o jẹ. Iwe afọwọkọ yii ko ṣiṣẹ ni iyara, paapaa ti ọpọlọpọ awọn akọọlẹ ba wa, nitorinaa a wo nikan ni awọn ọsẹ 2 to kọja, ati tun lo ṣiṣan iṣẹ ti o fun ọ laaye lati wa alaye lori ọpọlọpọ awọn VM ni nigbakannaa. Iwe afọwọkọ apẹẹrẹ ni awọn asọye alaye lori ẹrọ yii. A ṣafikun abajade sinu csv kan, eyiti a tun gbe sinu R.
  • A ṣe agbekalẹ iwe xlsx ti o ni ẹwa ninu eyiti awọn aaye ti ko tọ yoo jẹ afihan ni pupa, awọn asẹ yoo lo si diẹ ninu awọn ọwọn, ati awọn ọwọn afikun ti o ni awọn olupilẹṣẹ ti a pinnu ati akoko ẹda ti VM yoo jẹ itọkasi.
  • A ṣe agbekalẹ imeeli kan, nibiti a ti so iwe-ipamọ kan ti n ṣalaye awọn iye aaye ti o wulo, bakanna bi tabili pẹlu ti ko tọ ni awọn aaye. Ninu ọrọ naa a tọka nọmba lapapọ ti awọn VM ti a ṣẹda ti ko tọ, ọna asopọ si orisun ti o pin ati aworan iwuri. Ti ko ba si awọn VM ti ko tọ, a firanṣẹ lẹta miiran pẹlu aworan iwuri ti o ni idunnu.
  • A ṣe igbasilẹ data fun gbogbo awọn VM ninu aaye data SQL Server, ni akiyesi ilana imuse ti awọn tabili itan (eroja ti o nifẹ pupọ - nipa eyiti diẹ sii nigbamii)

Nitootọ awọn iwe afọwọkọ

Faili R koodu akọkọ

# Путь к рабочей директории (нужно для корректной работы через виндовый планировщик заданий)
setwd("C:ScriptsgetVm")
#### Подгружаем необходимые пакеты ####
library(tidyverse)
library(xlsx)
library(mailR)
library(rmarkdown)
##### Определяем пути к исходным файлам и другие переменные #####
source(file = "const.R", local = T, encoding = "utf-8")
# Проверяем существование файла со всеми ВМ и удаляем, если есть.
if (file.exists(filenameVmCreationRules)) {file.remove(filenameVmCreationRules)}
#### Создаём вордовский документ с допустимыми полями
render("VM_name_rules.Rmd",
output_format = word_document(),
output_file = filenameVmCreationRules)
# Проверяем существование файла со всеми ВМ и удаляем, если есть
if (file.exists(allVmXlsxPath)) {file.remove(allVmXlsxPath)}
#### Забираем данные по всем машинам через PowerShell скрипт. На выходе получим csv.
system(paste0("powershell -File ", getVmPsPath))
# Полный df
fullXslx_df <- allVmXlsxPath %>% 
read.csv2(stringsAsFactors = FALSE)
# Проверяем корректность заполненных полей
full_df <- fullXslx_df %>%
mutate(
# Сначала убираем все лишние пробелы и табуляции, потом учитываем разделитель запятую, потом проверяем вхождение в допустимые значения,
isSubsystemCorrect = Subsystem %>% 
gsub("[[:space:]]", "", .) %>% 
str_split(., ",") %>% 
map(function(x) (all(x %in% AllowedValues$Subsystem))) %>%
as.logical(),
isOwnerCorrect = Owner %in% AllowedValues$Owner,
isCategoryCorrect = Category %in% AllowedValues$Category,
isCreatorCorrect = (!is.na(Creator) & Creator != ''),
isCreation.DateCorrect = map(Creation.Date, IsDate)
)
# Проверяем существование файла со всеми ВМ и удаляем, если есть.
if (file.exists(filenameAll)) {file.remove(filenameAll)}
#### Формируем xslx файл с отчётом ####
# Общие данные на отдельный лист
full_df %>% write.xlsx(file=filenameAll,
sheetName=names[1],
col.names=TRUE,
row.names=FALSE,
append=FALSE)
#### Формируем xslx файл с неправильно заполненными полями ####
# Формируем df
incorrect_df <- full_df %>%
select(VM.Name, 
IP.s, 
Owner,
Subsystem,
Creator,
Category,
Creation.Date,
isOwnerCorrect, 
isSubsystemCorrect, 
isCategoryCorrect,
isCreatorCorrect,
vCenter.Name) %>%
filter(isSubsystemCorrect == F | 
isOwnerCorrect == F |
isCategoryCorrect == F |
isCreatorCorrect == F)
# Проверяем существование файла со всеми ВМ и удаляем, если есть.
if (file.exists(filenameIncVM)) {file.remove(filenameIncVM)}
# Сохраняем список VM с незаполненными полями в csv
incorrect_df %>%
select(VM.Name) %>%
write_csv2(path = filenameIncVM, append = FALSE)
# Фильтруем для вставки в почту
incorrect_df_filtered <- incorrect_df %>% 
select(VM.Name, 
IP.s, 
Owner, 
Subsystem, 
Category,
Creator,
vCenter.Name,
Creation.Date
)
# Считаем количество строк
numberOfRows <- nrow(incorrect_df)
#### Начало условия ####
# Дальше либо у нас есть неправильно заполненные поля, либо нет.
# Если есть - запускаем ещё один скрипт
if (numberOfRows > 0) {
# Проверяем существование файла с создателями и удаляем, если есть.
if (file.exists(creatorsFilePath)) {file.remove(creatorsFilePath)}
# Запускаем PowerShell скрипт, который найдёт создателей найденных VM. На выходе получим csv.
system(paste0("powershell -File ", getCreatorsPath))
# Читаем файл с создателями
creators_df <- creatorsFilePath %>%
read.csv2(stringsAsFactors = FALSE)
# Фильтруем для вставки в почту, добавляем данные из таблицы с создателями
incorrect_df_filtered <- incorrect_df_filtered %>% 
select(VM.Name, 
IP.s, 
Owner, 
Subsystem, 
Category,
Creator,
vCenter.Name,
Creation.Date
) %>% 
left_join(creators_df, by = "VM.Name") %>% 
rename(`Предполагаемый создатель` = CreatedBy, 
`Предполагаемая дата создания` = CreatedOn)  
# Формируем тело письма
emailBody <- paste0(
'<html>
<h3>Добрый день, уважаемые коллеги.</h3>
<p>Полную актуальную информацию по виртуальным машинам вы можете посмотреть на диске H: вот тут:<p>
<p>server.ruVM', sourceFileFormat, '</p>
<p>Также во вложении список ВМ с <strong>некорректно заполненными</strong> полями. Всего их <strong>', numberOfRows,'</strong>.</p>
<p>В таблице появилось 2 дополнительные колонки. <strong>Предполагаемый создатель</strong> и <strong>Предполагаемая дата создания</strong>, которые достаются из логов vCenter за последние 2 недели</p>
<p>Просьба создателей машин уточнить данные и заполнить поля корректно. Правила заполнения полей также во вложении</p>
<p><img src="data/meme.jpg"></p>
</html>'
)
# Проверяем существование файла
if (file.exists(filenameIncorrect)) {file.remove(filenameIncorrect)}
# Формируем красивую таблицу с форматами и т.д.
source(file = "email.R", local = T, encoding = "utf-8")
#### Формируем письмо с плохо подписанными машинами ####
send.mail(from = emailParams$from,
to = emailParams$to,
subject = "ВМ с некорректно заполненными полями",
body = emailBody,
encoding = "utf-8",
html = TRUE,
inline = TRUE,
smtp = emailParams$smtpParams,
authenticate = TRUE,
send = TRUE,
attach.files = c(filenameIncorrect, filenameVmCreationRules),
debug = FALSE)
#### Дальше пойдёт блок, если нет проблем с ВМ ####
} else {
# Формируем тело письма
emailBody <- paste0(
'<html>
<h3>Добрый день, уважаемые коллеги</h3>
<p>Полную актуальную информацию по виртуальным машинам вы можете посмотреть на диске H: вот тут:<p>
<p>server.ruVM', sourceFileFormat, '</p>
<p>Также, на текущий момент, все поля ВМ корректно заполнены</p>
<p><img src="data/meme_correct.jpg"></p>
</html>'
)
#### Формируем письмо без плохо заполненных VM ####
send.mail(from = emailParams$from,
to = emailParams$to,
subject = "Сводная информация",
body = emailBody,
encoding = "utf-8",
html = TRUE,
inline = TRUE,
smtp = emailParams$smtpParams,
authenticate = TRUE,
send = TRUE,
debug = FALSE)
}
####### Записываем данные в БД #####
source(file = "DB.R", local = T, encoding = "utf-8")

Iwe afọwọkọ fun gbigba atokọ ti vm ni PowerShell

# Данные для подключения и другие переменные
$vCenterNames = @(
"vcenter01", 
"vcenter02", 
"vcenter03"
)
$vCenterUsername = "myusername"
$vCenterPassword = "mypassword"
$filename = "C:ScriptsgetVmdataallvmall-vm-$(get-date -f yyyy-MM-dd).csv"
$destinationSMB = "server.rumyfolder$vm"
$IP0=""
$IP1=""
$IP2=""
$IP3=""
$IP4=""
$IP5=""
# Подключение ко всем vCenter, что содержатся в переменной. Будет работать, если логин и пароль одинаковые (например, доменные)
Connect-VIServer -Server $vCenterNames -User $vCenterUsername -Password $vCenterPassword
write-host ""
# Создаём функцию с циклом по всем vCenter-ам
function Get-VMinventory {
# В этой переменной будет списко всех ВМ, как объектов
$AllVM = Get-VM | Sort Name
$cnt = $AllVM.Count
$count = 1
# Начинаем цикл по всем ВМ и собираем необходимые параметры каждого объекта
foreach ($vm in $AllVM) {
$StartTime = $(get-date)
$IP0 = $vm.Guest.IPAddress[0]
$IP1 = $vm.Guest.IPAddress[1]
$IP2 = $vm.Guest.IPAddress[2]
$IP3 = $vm.Guest.IPAddress[3]
$IP4 = $vm.Guest.IPAddress[4]
$IP5 = $vm.Guest.IPAddress[5]
If ($IP0 -ne $null) {If ($IP0.Contains(":") -ne 0) {$IP0=""}}
If ($IP1 -ne $null) {If ($IP1.Contains(":") -ne 0) {$IP1=""}}
If ($IP2 -ne $null) {If ($IP2.Contains(":") -ne 0) {$IP2=""}}
If ($IP3 -ne $null) {If ($IP3.Contains(":") -ne 0) {$IP3=""}}
If ($IP4 -ne $null) {If ($IP4.Contains(":") -ne 0) {$IP4=""}}
If ($IP5 -ne $null) {If ($IP5.Contains(":") -ne 0) {$IP5=""}}
$cluster = $vm | Get-Cluster | Select-Object -ExpandProperty name  
$Bootime = $vm.ExtensionData.Runtime.BootTime
$TotalHDDs = $vm.ProvisionedSpaceGB -as [int]
$CreationDate = $vm.CustomFields.Item("CreationDate") -as [string]
$Creator = $vm.CustomFields.Item("Creator") -as [string]
$Category = $vm.CustomFields.Item("Category") -as [string]
$Owner = $vm.CustomFields.Item("Owner") -as [string]
$Subsystem = $vm.CustomFields.Item("Subsystem") -as [string]
$IPS = $vm.CustomFields.Item("IP") -as [string]
$vCPU = $vm.NumCpu
$CorePerSocket = $vm.ExtensionData.config.hardware.NumCoresPerSocket
$Sockets = $vCPU/$CorePerSocket
$Id = $vm.Id.Split('-')[2] -as [int]
# Собираем все параметры в один объект
$Vmresult = New-Object PSObject
$Vmresult | add-member -MemberType NoteProperty -Name "Id" -Value $Id   
$Vmresult | add-member -MemberType NoteProperty -Name "VM Name" -Value $vm.Name  
$Vmresult | add-member -MemberType NoteProperty -Name "Cluster" -Value $cluster  
$Vmresult | add-member -MemberType NoteProperty -Name "Esxi Host" -Value $VM.VMHost  
$Vmresult | add-member -MemberType NoteProperty -Name "IP Address 1" -Value $IP0
$Vmresult | add-member -MemberType NoteProperty -Name "IP Address 2" -Value $IP1
$Vmresult | add-member -MemberType NoteProperty -Name "IP Address 3" -Value $IP2
$Vmresult | add-member -MemberType NoteProperty -Name "IP Address 4" -Value $IP3
$Vmresult | add-member -MemberType NoteProperty -Name "IP Address 5" -Value $IP4
$Vmresult | add-member -MemberType NoteProperty -Name "IP Address 6" -Value $IP5
$Vmresult | add-member -MemberType NoteProperty -Name "vCPU" -Value $vCPU
$Vmresult | Add-Member -MemberType NoteProperty -Name "CPU Sockets" -Value $Sockets
$Vmresult | Add-Member -MemberType NoteProperty -Name "Core per Socket" -Value $CorePerSocket
$Vmresult | add-member -MemberType NoteProperty -Name "RAM (GB)" -Value $vm.MemoryGB
$Vmresult | add-member -MemberType NoteProperty -Name "Total-HDD (GB)" -Value $TotalHDDs
$Vmresult | add-member -MemberType NoteProperty -Name "Power State" -Value $vm.PowerState
$Vmresult | add-member -MemberType NoteProperty -Name "OS" -Value $VM.ExtensionData.summary.config.guestfullname  
$Vmresult | Add-Member -MemberType NoteProperty -Name "Boot Time" -Value $Bootime
$Vmresult | add-member -MemberType NoteProperty -Name "VMTools Status" -Value $vm.ExtensionData.Guest.ToolsStatus  
$Vmresult | add-member -MemberType NoteProperty -Name "VMTools Version" -Value $vm.ExtensionData.Guest.ToolsVersion  
$Vmresult | add-member -MemberType NoteProperty -Name "VMTools Version Status" -Value $vm.ExtensionData.Guest.ToolsVersionStatus  
$Vmresult | add-member -MemberType NoteProperty -Name "VMTools Running Status" -Value $vm.ExtensionData.Guest.ToolsRunningStatus  
$Vmresult | add-member -MemberType NoteProperty -Name "Creation Date" -Value $CreationDate
$Vmresult | add-member -MemberType NoteProperty -Name "Creator" -Value $Creator
$Vmresult | add-member -MemberType NoteProperty -Name "Category" -Value $Category
$Vmresult | add-member -MemberType NoteProperty -Name "Owner" -Value $Owner
$Vmresult | add-member -MemberType NoteProperty -Name "Subsystem" -Value $Subsystem
$Vmresult | add-member -MemberType NoteProperty -Name "IP's" -Value $IPS
$Vmresult | add-member -MemberType NoteProperty -Name "vCenter Name" -Value $vm.Uid.Split('@')[1].Split(':')[0]  
# Считаем общее и оставшееся время выполнения и выводим на экран результаты. Использовалось для тестирования, но по факту оказалось очень удобно.
$elapsedTime = $(get-date) - $StartTime
$totalTime = "{0:HH:mm:ss}" -f ([datetime]($elapsedTime.Ticks*($cnt - $count)))
clear-host
Write-Host "Processing" $count "from" $cnt 
Write-host "Progress:" ([math]::Round($count/$cnt*100, 2)) "%" 
Write-host "You have about " $totalTime "for cofee"
Write-host ""
$count++
# Выводим результат, чтобы цикл "знал" что является результатом выполнения одного прохода
$Vmresult
}
}
# Вызываем получившуюся функцию и сразу выгружаем результат в csv
$allVm = Get-VMinventory | Export-CSV -Path $filename -NoTypeInformation -UseCulture -Force
# Пытаемся выложить полученный файл в нужное нам место и, в случае ошибки, пишем лог.
try
{
Copy-Item $filename -Destination $destinationSMB -Force -ErrorAction SilentlyContinue
}
catch
{
$error | Export-CSV -Path $filename".error" -NoTypeInformation -UseCulture -Force
}

Iwe afọwọkọ PowerShell kan ti o yọ jade lati awọn akọọlẹ awọn olupilẹṣẹ ti awọn ẹrọ foju ati ọjọ ti ẹda wọn

# Путь к файлу, из которого будем доставать список VM
$VMfilePath = "C:ScriptsgetVmcreators_VMcreators_VM_$(get-date -f yyyy-MM-dd).csv"
# Путь к файлу, в который будем записывать результат
$filePath = "C:ScriptsgetVmdatacreatorscreators-$(get-date -f yyyy-MM-dd).csv"
# Создаём вокрфлоу
Workflow GetCreators-Wf
{
# Параметры, которые можно будет передать при вызове скрипта
param([string[]]$VMfilePath)
# Параметры, которые доступны только внутри workflow
$vCenterUsername = "myusername"
$vCenterPassword = "mypassword"
$daysToLook = 14
$start = (get-date).AddDays(-$daysToLook)
$finish = get-date
# Значения, которые будут вписаны в csv для машин, по которым не будет ничего найдено
$UnknownUser = "UNKNOWN"
$UnknownCreatedTime = "0000-00-00"
# Определяем параметры подключения и выводной файл, которые будут доступны во всём скрипте.
$vCenterNames = @(
"vcenter01", 
"vcenter02", 
"vcenter03"
)
# Получаем список VM из csv и загружаем соответствующие объекты
$list = Import-Csv $VMfilePath -UseCulture | select -ExpandProperty VM.Name
# Цикл, который будет выполняться параллельно (по 5 машин за раз)
foreach -parallel ($row in $list)
{
# Это скрипт, который видит только свои переменные и те, которые ему переданы через $Using
InlineScript {
# Время начала выполнения отдельного блока
$StartTime = $(get-date)
Write-Host ""
Write-Host "Processing $Using:row started at $StartTime"
Write-Host ""
# Подключение оборачиваем в переменную, чтобы информация о нём не мешалась в консоли
$con = Connect-VIServer -Server $Using:vCenterNames -User $Using:vCenterUsername -Password $Using:vCenterPassword
# Получаем объект vm
$vm = Get-VM -Name $Using:row
# Ниже 2 одинаковые команды. Одна с фильтром по времени, вторая - без. Можно пользоваться тем,
$Event = $vm | Get-VIEvent -Start $Using:start -Finish $Using:finish -Types Info | Where { $_.Gettype().Name -eq "VmBeingDeployedEvent" -or $_.Gettype().Name -eq "VmCreatedEvent" -or $_.Gettype().Name -eq "VmRegisteredEvent" -or $_.Gettype().Name -eq "VmClonedEvent"}
# $Event = $vm | Get-VIEvent -Types Info | Where { $_.Gettype().Name -eq "VmBeingDeployedEvent" -or $_.Gettype().Name -eq "VmCreatedEvent" -or $_.Gettype().Name -eq "VmRegisteredEvent" -or $_.Gettype().Name -eq "VmClonedEvent"}
# Заполняем параметры в зависимости от того, удалось ли в логах найти что-то
If (($Event | Measure-Object).Count -eq 0){
$User = $Using:UnknownUser
$Created = $Using:UnknownCreatedTime
$CreatedFormat = $Using:UnknownCreatedTime
} Else {
If ($Event.Username -eq "" -or $Event.Username -eq $null) {
$User = $Using:UnknownUser
} Else {
$User = $Event.Username
} # Else
$CreatedFormat = $Event.CreatedTime
# Один из коллег отдельно просил, чтобы время было в таком формате, поэтому дублируем его. А в БД пойдёт нормальный формат.
$Created = $Event.CreatedTime.ToString('yyyy-MM-dd')
} # Else
Write-Host "Creator for $vm is $User. Creating object."
# Создаём объект. Добавляем параметры.
$Vmresult = New-Object PSObject
$Vmresult | add-member -MemberType NoteProperty -Name "VM Name" -Value $vm.Name  
$Vmresult | add-member -MemberType NoteProperty -Name "CreatedBy" -Value $User
$Vmresult | add-member -MemberType NoteProperty -Name "CreatedOn" -Value $CreatedFormat
$Vmresult | add-member -MemberType NoteProperty -Name "CreatedOnFormat" -Value $Created           
# Выводим результаты
$Vmresult
} # Inline
} # ForEach
}
$Creators = GetCreators-Wf $VMfilePath
# Записываем результат в файл
$Creators | select 'VM Name', CreatedBy, CreatedOn | Export-Csv -Path $filePath -NoTypeInformation -UseCulture -Force
Write-Host "CSV generetion finisghed at $(get-date). PROFIT"

Ile-ikawe naa yẹ akiyesi pataki xlsx, eyi ti o ṣe o ṣee ṣe lati ṣe awọn asomọ si awọn lẹta kedere kika (bi isakoso fẹran), ki o si ko o kan kan CSV tabili.

Ṣiṣẹda iwe xlsx ẹlẹwa kan pẹlu atokọ ti awọn ẹrọ ti ko tọ

# Создаём новую книгу
# Возможные значения : "xls" и "xlsx"
wb<-createWorkbook(type="xlsx")
# Стили для имён рядов и колонок в таблицах
TABLE_ROWNAMES_STYLE <- CellStyle(wb) + Font(wb, isBold=TRUE)
TABLE_COLNAMES_STYLE <- CellStyle(wb) + Font(wb, isBold=TRUE) +
Alignment(wrapText=TRUE, horizontal="ALIGN_CENTER") +
Border(color="black", position=c("TOP", "BOTTOM"), 
pen=c("BORDER_THIN", "BORDER_THICK"))
# Создаём новый лист
sheet <- createSheet(wb, sheetName = names[2])
# Добавляем таблицу
addDataFrame(incorrect_df_filtered, 
sheet, startRow=1, startColumn=1,  row.names=FALSE, byrow=FALSE,
colnamesStyle = TABLE_COLNAMES_STYLE,
rownamesStyle = TABLE_ROWNAMES_STYLE)
# Меняем ширину, чтобы форматирование было автоматическим
autoSizeColumn(sheet = sheet, colIndex=c(1:ncol(incorrect_df)))
# Добавляем фильтры
addAutoFilter(sheet, cellRange = "C1:G1")
# Определяем стиль
fo2 <- Fill(foregroundColor="red")
cs2 <- CellStyle(wb, 
fill = fo2, 
dataFormat = DataFormat("@"))
# Находим ряды с неверно заполненным полем Владельца и применяем к ним определённый стиль
rowsOwner <- getRows(sheet, rowIndex = (which(!incorrect_df$isOwnerCorrect) + 1))
cellsOwner <- getCells(rowsOwner, colIndex = which( colnames(incorrect_df_filtered) == "Owner" )) 
lapply(names(cellsOwner), function(x) setCellStyle(cellsOwner[[x]], cs2))
# Находим ряды с неверно заполненным полем Подсистемы и применяем к ним определённый стиль
rowsSubsystem <- getRows(sheet, rowIndex = (which(!incorrect_df$isSubsystemCorrect) + 1))
cellsSubsystem <- getCells(rowsSubsystem, colIndex = which( colnames(incorrect_df_filtered) == "Subsystem" )) 
lapply(names(cellsSubsystem), function(x) setCellStyle(cellsSubsystem[[x]], cs2))
# Аналогично по Категории
rowsCategory <- getRows(sheet, rowIndex = (which(!incorrect_df$isCategoryCorrect) + 1))
cellsCategory <- getCells(rowsCategory, colIndex = which( colnames(incorrect_df_filtered) == "Category" )) 
lapply(names(cellsCategory), function(x) setCellStyle(cellsCategory[[x]], cs2))
# Создатель
rowsCreator <- getRows(sheet, rowIndex = (which(!incorrect_df$isCreatorCorrect) + 1))
cellsCreator <- getCells(rowsCreator, colIndex = which( colnames(incorrect_df_filtered) == "Creator" )) 
lapply(names(cellsCreator), function(x) setCellStyle(cellsCreator[[x]], cs2))
# Сохраняем файл
saveWorkbook(wb, filenameIncorrect)

Ijade naa dabi iru eyi:

Awọn ijabọ ojoojumọ lori ilera ti awọn ẹrọ foju nipa lilo R ati PowerShell

Nuance ti o nifẹ si tun wa nipa siseto oluṣeto Windows. Ko ṣee ṣe lati wa awọn ẹtọ ati eto ti o tọ ki ohun gbogbo yoo bẹrẹ bi o ti yẹ. Bi abajade, a rii ile-ikawe R, eyiti funrararẹ ṣẹda iṣẹ-ṣiṣe lati ṣe ifilọlẹ iwe afọwọkọ R ati paapaa ko gbagbe nipa faili log. Lẹhinna o le ṣe atunṣe iṣẹ naa pẹlu ọwọ.

Nkan ti koodu R pẹlu awọn apẹẹrẹ meji ti o ṣẹda iṣẹ-ṣiṣe ni Iṣeto Windows

library(taskscheduleR)
myscript <- file.path(getwd(), "all_vm.R")
## запускаем скрипт через 62 секунды
taskscheduler_create(taskname = "getAllVm", rscript = myscript, 
schedule = "ONCE", starttime = format(Sys.time() + 62, "%H:%M"))
## запускаем скрипт каждый день в 09:10
taskscheduler_create(taskname = "getAllVmDaily", rscript = myscript, 
schedule = "WEEKLY", 
days = c("MON", "TUE", "WED", "THU", "FRI"),
starttime = "02:00")
## удаляем задачи
taskscheduler_delete(taskname = "getAllVm")
taskscheduler_delete(taskname = "getAllVmDaily")
# Смотрим логи (последние 4 строчки)
tail(readLines("all_vm.log"), sep ="n", n = 4)

Lọtọ nipa awọn database

Lẹhin ti ṣeto iwe afọwọkọ, awọn ọran miiran bẹrẹ si han. Fun apẹẹrẹ, Mo fẹ lati wa ọjọ nigbati VM ti paarẹ, ṣugbọn awọn akọọlẹ vCenter ti pari tẹlẹ. Niwọn igba ti iwe afọwọkọ fi awọn faili sinu folda ni gbogbo ọjọ ati pe ko sọ di mimọ (a sọ di mimọ pẹlu ọwọ wa nigba ti a ba ranti), o le wo nipasẹ awọn faili atijọ ati rii faili akọkọ ninu eyiti VM yii ko wa. Ṣugbọn iyẹn ko dara.

Mo fe lati ṣẹda kan itan database.

Iṣẹ ṣiṣe ti MS SQL SERVER - tabili akoko ti o ni ẹya eto - wa si igbala. O maa n tumọ bi awọn tabili igba diẹ (kii ṣe igba diẹ).

O le ka ni apejuwe awọn ni osise Microsoft iwe aṣẹ.

Ni kukuru, a ṣẹda tabili kan, sọ pe a yoo ni pẹlu ikede, ati SQL Server ṣẹda awọn ọwọn ọjọ akoko 2 afikun ni tabili yii (ọjọ ti a ṣẹda igbasilẹ naa ati ọjọ ipari ti igbasilẹ) ati tabili afikun sinu eyiti o yipada yoo kọ. Bi abajade, a gba alaye imudojuiwọn ati, nipasẹ awọn ibeere ti o rọrun, awọn apẹẹrẹ eyiti a fun ni ninu iwe, a le rii boya igbesi aye ti ẹrọ foju kan pato, tabi ipo ti gbogbo awọn VM ni aaye kan ni asiko.

Lati irisi iṣẹ kan, idunadura kikọ si tabili akọkọ kii yoo pari titi idunadura kikọ si tabili igba diẹ ti pari. Awon. lori awọn tabili pẹlu nọmba nla ti awọn iṣẹ kikọ, iṣẹ ṣiṣe yẹ ki o ṣe imuse pẹlu iṣọra, ṣugbọn ninu ọran wa o jẹ ohun ti o tutu pupọ.

Ni ibere fun ẹrọ naa lati ṣiṣẹ ni deede, Mo ni lati ṣafikun koodu kekere kan ni R ti yoo ṣe afiwe tabili tuntun pẹlu data fun gbogbo awọn VM pẹlu eyiti o fipamọ sinu aaye data ki o kọ awọn ori ila ti o yipada nikan si. Awọn koodu ti wa ni ko paapa onilàkaye;

R koodu fun kikọ data to a database

# Подцепляем пакеты
library(odbc)
library(compareDF)
# Формируем коннект
con <- dbConnect(odbc(),
Driver = "ODBC Driver 13 for SQL Server",
Server = DBParams$server,
Database = DBParams$database,
UID = DBParams$UID,
PWD = DBParams$PWD,
Port = 1433)
#### Проверяем есть ли таблица. Если нет - создаём. ####
if (!dbExistsTable(con, DBParams$TblName)) {
#### Создаём таблицу ####
create <- dbSendStatement(
con,
paste0(
'CREATE TABLE ',
DBParams$TblName,
'(
[Id] [int] NOT NULL PRIMARY KEY CLUSTERED,
[VM.Name] [varchar](255) NULL,
[Cluster] [varchar](255) NULL,
[Esxi.Host] [varchar](255) NULL,
[IP.Address.1] [varchar](255) NULL,
[IP.Address.2] [varchar](255) NULL,
[IP.Address.3] [varchar](255) NULL,
[IP.Address.4] [varchar](255) NULL,
[IP.Address.5] [varchar](255) NULL,
[IP.Address.6] [varchar](255) NULL,
[vCPU] [int] NULL,
[CPU.Sockets] [int] NULL,
[Core.per.Socket] [int] NULL,
[RAM..GB.] [int] NULL,
[Total.HDD..GB.] [int] NULL,
[Power.State] [varchar](255) NULL,
[OS] [varchar](255) NULL,
[Boot.Time] [varchar](255) NULL,
[VMTools.Status] [varchar](255) NULL,
[VMTools.Version] [int] NULL,
[VMTools.Version.Status] [varchar](255) NULL,
[VMTools.Running.Status] [varchar](255) NULL,
[Creation.Date] [varchar](255) NULL,
[Creator] [varchar](255) NULL,
[Category] [varchar](255) NULL,
[Owner] [varchar](255) NULL,
[Subsystem] [varchar](255) NULL,
[IP.s] [varchar](255) NULL,
[vCenter.Name] [varchar](255) NULL,
DateFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL,
DateTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (DateFrom, DateTo)
) ON [PRIMARY]
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = ', DBParams$TblHistName,'));'
)
)
# Отправляем подготовленный запрос
dbClearResult(create)
} # if
#### Начало работы с таблицей ####
# Обозначаем таблицу, с которой будем работать
allVM_db_con <- tbl(con, DBParams$TblName) 
#### Сравниваем таблицы ####
# Собираем данные с таблицы (убираем служебные временные поля)
allVM_db <- allVM_db_con %>% 
select(c(-"DateTo", -"DateFrom")) %>% 
collect()
# Создаём таблицу со сравнением объектов. Сравниваем по Id
# Удалённые объекты там будут помечены через -, созданные через +, изменённые через - и +
ctable_VM <- fullXslx_df %>% 
compare_df(allVM_db, 
c("Id"))
#### Удаление строк ####
# Выдираем Id виртуалок, записи о которых надо удалить 
remove_Id <- ctable_VM$comparison_df %>% 
filter(chng_type == "-") %>%
select(Id)
# Проверяем, что есть записи (если записей нет - и удалять ничего не нужно)
if (remove_Id %>% nrow() > 0) {
# Конструируем шаблон для запроса на удаление данных
delete <- dbSendStatement(con, 
paste0('
DELETE 
FROM ',
DBParams$TblName,
' WHERE "Id"=?
') # paste
) # send
# Создаём запрос на удаление данных
dbBind(delete, remove_Id)
# Отправляем подготовленный запрос
dbClearResult(delete)
} # if
#### Добавление строк ####
# Выделяем таблицу, содержащую строки, которые нужно добавить.
allVM_add <- ctable_VM$comparison_df %>% 
filter(chng_type == "+") %>% 
select(-chng_type)
# Проверяем, есть ли строки, которые нужно добавить и добавляем (если нет - не добавляем)
if (allVM_add %>% nrow() > 0) {
# Пишем таблицу со всеми необходимыми данными
dbWriteTable(con,
DBParams$TblName,
allVM_add,
overwrite = FALSE,
append = TRUE)
} # if
#### Не забываем сделать дисконнект ####
dbDisconnect(con)

Lapapọ

Bi abajade imuse ti iwe afọwọkọ, aṣẹ ti tun pada ati ṣetọju laarin awọn oṣu diẹ. Nigba miiran awọn VM ti ko tọ han, ṣugbọn iwe afọwọkọ naa jẹ olurannileti ti o dara ati pe VM toje n wọle sinu atokọ fun awọn ọjọ 2 ni ọna kan.

A tun ṣe iṣẹ-ilẹ fun itupalẹ data itan.

O han gbangba pe pupọ ninu eyi le ṣe imuse kii ṣe lori orokun, ṣugbọn pẹlu sọfitiwia amọja, ṣugbọn iṣẹ-ṣiṣe naa jẹ ohun ti o nifẹ ati, ọkan le sọ, yiyan.

R ti tun fi ara rẹ han lati jẹ ede agbaye ti o dara julọ, eyiti o jẹ pipe kii ṣe fun ipinnu awọn iṣoro iṣiro nikan, ṣugbọn tun ṣe bi "Layer" ti o dara julọ laarin awọn orisun data miiran.

Awọn ijabọ ojoojumọ lori ilera ti awọn ẹrọ foju nipa lilo R ati PowerShell

orisun: www.habr.com

Fi ọrọìwòye kun