Raporên rojane li ser tenduristiya makîneyên virtual ku R û PowerShell bikar tînin

Raporên rojane li ser tenduristiya makîneyên virtual ku R û PowerShell bikar tînin

entry

Paş nîvro. Ev nîv sal e ku em skrîptek dimeşînin (an jî komek senaryoyan) ku raporên li ser rewşa makîneyên virtual (û ne tenê) diafirîne. Min biryar da ku ez ezmûna afirandina xwe û kodê bixwe parve bikim. Ez ji bo rexneyê hêvî dikim û dibe ku ev materyal ji bo kesek kêrhatî be.

Damezrandina hewcedariyê

Me gelek makîneyên virtual hene (nêzîkî 1500 VM-yên ku li ser 3 vNavendan hatine belav kirin). Yên nû têne afirandin û yên kevn pir caran têne jêbirin. Ji bo domandina rêzê, çend qadên xwerû li vCenter hatin zêdekirin da ku VM-yan li Binepergalan dabeş bikin, destnîşan bikin ka ew ceribandin in, û ji hêla kê ve û kengê hatine afirandin. Faktora mirovî rê li ber vê yekê girt ku zêdetirî nîvê makîneyan zeviyên vala hiştin, ku ev kar tevlihev kir. Her şeş mehan carekê, kesek ditirsiya û dest bi xebatê li ser nûvekirina van daneyan kir, lê encam piştî hefte û nîvek nema têkildar bû.
Bila ez tavilê zelal bikim ku her kes fêm dike ku divê ji bo afirandina makîneyan, pêvajoyek ji bo afirandina wan, hwd. wate ya vê çîye. Û di heman demê de, her kes bi tundî vê pêvajoyê dişopîne û her tişt di rê de ye. Mixabin, ev ne li vir e, lê ev ne mijara gotarê ye :)

Bi gelemperî, biryar hate girtin ku kontrolkirina rastdariya dagirtina qadan otomatîk bike.
Me biryar da ku nameyek rojane bi navnîşek makîneyên ku bi xeletî hatine dagirtin ji hemî endezyarên berpirsiyar û serokên wan re dê destpêkek baş be.

Di vê nuqteyê de, yek ji hevkarên min berê di PowerShell de skrîptek bicîh kiribû, ku her roj, li gorî nexşeyek, agahdariya li ser hemî makîneyên hemî vCenter berhev dikir û 3 belgeyên csv (her yek ji bo vCentera xwe) çêdikir, ku li ser têne barkirin. dîskek hevpar. Biryar hat dayîn ku em vê skrîptê wekî bingeh bigirin û wê bi kontrolên bi karanîna zimanê R-yê, ku hin ezmûna me pê re hebû, temam bikin.

Di pêvajoya qedandinê de, çareseriyê bi nameyê agahdarî, databasek bi tabloyek sereke û dîrokî (li ser vê paşê bêtir), û her weha analîzek têketinên vSphere peyda kir da ku afirînerên rastîn ên vm û dema afirandina wan bibîne.

IDE RStudio Desktop û PowerShell ISE ji bo pêşkeftinê hatin bikar anîn.

Nivîsar ji makîneyek virtual ya Windows-ê ya birêkûpêk tê destpêkirin.

Danasîna mantiqa giştî.

Mantiqa giştî ya senaryoyan wiha ye.

  • Em daneyan li ser makîneyên virtual bi karanîna skrîptek PowerShell, ku em bi R-yê jê re dibêjin, berhev dikin, û encamê di yek csv de berhev dikin. Têkiliya berevajî ya di navbera zimanan de bi heman rengî tê kirin. (mimkûn bû ku daneyan rasterast ji R-ê berbi PowerShell-ê di forma guhêrbaran de bikişîne, lê ev dijwar e, û hebûna csv-yên navîn debugkirin û parvekirina encamên navîn bi kesek re hêsantir dike).
  • Bi karanîna R, em ji bo qadên ku em nirxên wan kontrol dikin parametreyên derbasdar ava dikin. - Em belgeyek peyvan diafirînin ku dê nirxên van qadan ji bo nameya agahdariyê têxin nav xwe, ku dê bibe bersiva pirsên hevkaran "Na, lê divê ez çawa vê yekê dagirim?"
  • Em daneyên ji bo hemî VM-yên ji csv-yê bi karanîna R-yê bar dikin, çarçoveyek daneyê diafirînin, qadên nepêwist jê dikin û belgeyek xlsx-a agahdarî diafirînin ku dê agahdariya kurteya hemî VM-an hebe, ku em li çavkaniyek hevpar bar dikin.
  • Em hemî kontrolên ji bo rastbûna dagirtina zeviyan li ser dataframe ji bo hemî VM-yan bicîh dikin û tabloyek ku tenê VM-yên bi qadên xelet dagirtî hene (û tenê van qadan) diafirînin.
  • Em navnîşa encam a VM-an dişînin ji nivîsarek din a PowerShell re, ku dê li têketinên vCenter-ê ji bo bûyerên çêkirina VM-ê binihêre, ku dê rê bide me ku em dema texmînkirî ya afirandina VM-ê û afirînerê armanc destnîşan bikin. Ev ji bo wê yekê ye ku kes qebûl neke ew otomobîla kê ye. Ev skrîpt zû naxebite, nemaze heke gelek têketin hebin, ji ber vê yekê em tenê li 2 hefteyên paşîn mêze dikin, û di heman demê de karûbarek bikar tînin ku dihêle hûn di heman demê de li ser çend VM-yan agahdariyan bigerin. Skrîpta nimûne li ser vê mekanîzmayê şîroveyên berfireh dihewîne. Em encamê li csv zêde dikin, ku em dîsa di R bar dikin.
  • Em belgeyek xlsx-ê bi rengek xweşik çêdikin ku tê de qadên bi xeletî dagirtî dê bi sor werin ronî kirin, fîlter dê li hin stûnan werin sepandin, û stûnên din ên ku afirînerên armanc û dema çêkirina VM-ê vedihewîne dê were destnîşan kirin.
  • Em e-nameyek çêdikin, li wir em belgeyek ku nirxên zeviyê yên derbasdar vedibêje, û her weha tabloyek bi qadên bi xelet dagirtî ve girêdidin. Di nivîsê de em jimareya giştî ya VM-yên ku bi xeletî hatine afirandin, girêdanek bi çavkaniyek hevpar û wêneyek motîvasyonê destnîşan dikin. Ger VM-yên bi xelet dagirtî tune ne, em nameyek din bi wêneyek motîvasyona dilxweştir dişînin.
  • Em daneyên ji bo hemî VM-yên di databasa SQL Server-ê de tomar dikin, mekanîzmaya bicîhkirî ya tabloyên dîrokî li ber çavan digirin (mekanîzmayek pir balkêş - li ser wê bêtir paşê)

Bi rastî nivîsar

Pelê koda R ya sereke

# Путь к рабочей директории (нужно для корректной работы через виндовый планировщик заданий)
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")

Skrîpta ji bo bidestxistina navnîşek vm di PowerShell de

# Данные для подключения и другие переменные
$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
}

Nivîsarek PowerShell ku ji têketin afirînerên makîneyên virtual û dîroka afirandina wan derdixe.

# Путь к файлу, из которого будем доставать список 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"

Pirtûkxane hêjayî baldariyek taybetî ye xlsx, ya ku ev gengaz kir ku pêveka nameyê bi zelalî were format kirin (wek ku rêveberî hez dike), û ne tenê tabloyek CSV.

Hilberîna belgeyek xlsx ya xweşik bi navnîşek makîneyên ku bi xeletî hatine dagirtin

# Создаём новую книгу
# Возможные значения : "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)

Hilber tiştek bi vî rengî xuya dike:

Raporên rojane li ser tenduristiya makîneyên virtual ku R û PowerShell bikar tînin

Di derbarê sazkirina nexşerêya Windows-ê de nuwazeyek balkêş jî hebû. Ne gengaz bû ku meriv maf û mîhengên rast bibîne da ku her tişt wekî ku divê dest pê bike. Wekî encamek, pirtûkxaneya R hate dîtin, ku bi xwe peywirek diafirîne da ku skrîptek R bide destpêkirin û pelê têketinê jî ji bîr nake. Hingê hûn dikarin peywirê bi destan rast bikin.

Parçeyek koda R ya bi du mînakan ku di Bernameya Windows-ê de peywirek diafirîne

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)

Di derbarê databasê de cuda

Piştî sazkirina senaryoyê, pirsgirêkên din dest pê kirin. Mînakî, min dixwest ez tarîxa ku VM hatî jêbirin bibînim, lê têketinên di vCenter de jixwe qewirandin. Ji ber ku skrîpt her roj pelan li peldankekê dixe û wê paqij nake (dema ku em bi bîr tînin em wê bi destên xwe paqij dikin), hûn dikarin li pelên kevn bigerin û pelê yekem ku ev VM tê de tune ye bibînin. Lê ev ne xweş e.

Min xwest databaseke dîrokî çêkim.

Karbidestiya MS SQL SERVER - tabloya demkî ya guhertoya pergalê - hat rizgarkirinê. Bi gelemperî wekî tabloyên demkî (ne demkî) tê wergerandin.

Hûn dikarin bi berfirehî li ser bixwînin belgeyên fermî yên Microsoft.

Bi kurtasî, em tabloyek çêdikin, dibêjin ku em ê bi guhertokirinê re hebin, û SQL Server di vê tabloyê de 2 stûnên demjimêra tarîxê yên din diafirîne (roja ku tomar hatî çêkirin û dîroka qedandina tomarê) û tabloyek din a ku tê de tê guhertin dê bêne nivîsandin. Wekî encamek, em agahdariya nûjen werdigirin û, bi navgîniya pirsên hêsan, ku mînakên wan di belgeyê de têne dayîn, em dikarin çerxa jiyana makîneyek virtual ya taybetî, an jî rewşa hemî VM-yan di xalek diyar de bibînin. li dema xwe.

Ji perspektîfek performansê, danûstandina nivîsandina li ser tabloya sereke dê biqede heya ku danûstendina nivîsandina tabloya demkî biqede. Ewan. li ser tabloyên bi hejmareke mezin a operasyonên nivîsandinê, divê ev fonksiyon bi hişyarî were bicîh kirin, lê di rewşa me de ew tiştek bi rastî xweş e.

Ji bo ku mekanîzma bi rengek rast bixebite, min neçar ma ku kodek piçûk di R-yê de zêde bikim ku dê tabloya nû bi daneyên hemî VM-yê re bi ya ku di databasê de hatî hilanîn re bide ber hev û tenê rêzikên guhertî jê re binivîsîne. Kod ne bi taybetî jîr e; ew pirtûkxaneya compareDF bikar tîne, lê ez ê li jêr jî pêşkêşî bikim.

Koda R ji bo nivîsandina daneyan li databasekê

# Подцепляем пакеты
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)

Tevahî

Di encama pêkanîna senaryoyê de, di nava çend mehan de rêkûpêk hat vegerandin û parastin. Carinan VM-yên ku bi xeletî hatine dagirtin xuya dibin, lê skrîpt wekî bîranînek baş xizmet dike û VM-ya hindik 2 roj li pey hev dikeve navnîşê.

Ji bo analîzkirina daneyên dîrokî jî zemîn hat çêkirin.

Eşkere ye ku pir ji vê yekê ne li ser çokê, lê bi nermalava pispor dikare were bicîh kirin, lê peywir balkêş bû û, meriv dikare bibêje, vebijarkî bû.

R careke din xwe nîşan da ku zimanek gerdûnî ya hêja ye, ku ne tenê ji bo çareserkirina pirsgirêkên statîstîkî bêkêmasî ye, lê di heman demê de di navbera çavkaniyên daneya din de wekî "qatek" hêja jî tevdigere.

Raporên rojane li ser tenduristiya makîneyên virtual ku R û PowerShell bikar tînin

Source: www.habr.com

Add a comment