Imibiko yansuku zonke ngempilo yemishini ebonakalayo esebenzisa i-R ne-PowerShell

Imibiko yansuku zonke ngempilo yemishini ebonakalayo esebenzisa i-R ne-PowerShell

entry

Sawubona. Sekuphele isigamu sonyaka sisebenzisa iskripthi (noma kunalokho isethi yeskripthi) esikhiqiza imibiko ngesimo semishini ebonakalayo (hhayi kuphela). Nginqume ukwabelana ngolwazi lwami lokudala kanye nekhodi ngokwayo. Ngithemba ukugxekwa nokuthi lokhu okubalulekile kungase kube usizo kothile.

Ukwakhiwa kwesidingo

Sinemishini eminingi ebonakalayo (cishe ama-VM angu-1500 asatshalaliswa kuma-vCenter angu-3). Ezintsha ziyadalwa futhi ezindala zisuswa kaningi. Ukuze kugcinwe ukuhleleka, izinkambu zangokwezifiso ezimbalwa zengezwe ku-vCenter ukuze kuhlukaniswe ama-VM abe Amasistimu angaphansi, abonise ukuthi awahlolwa yini, adalwa ngubani futhi nini. Isici somuntu saholela eqinisweni lokuthi ngaphezu kwengxenye yemishini yasala namasimu angenalutho, okwenza umsebenzi waba nzima. Kanye njalo ezinyangeni eziyisithupha, othile wayethuka futhi waqala ukusebenzela ekubuyekezeni le datha, kodwa umphumela uyeka ukuba wusizo ngemva kwesonto nesigamu.
Ake ngicacise zisuka nje ukuthi wonke umuntu uyaqonda ukuthi kumele kube nezicelo zokwakhiwa kwemishini, inqubo yokudalwa kwayo, njll. njalo njalo. Futhi ngesikhathi esifanayo, wonke umuntu ulandela ngokuqinile le nqubo futhi yonke into ihlelekile. Ngeshwa, akunjalo lapha, kodwa lokhu akusona isihloko se-athikili :)

Ngokuvamile, isinqumo senziwa uku-automate ukuhlola ukufaneleka kokugcwalisa izinkambu.
Sanquma ukuthi incwadi yansuku zonke enohlu lwemishini egcwaliswe ngokungeyikho kubo bonke onjiniyela abanomthwalo wemfanelo kanye nabaphathi babo izoba isiqalo esihle.

Kuleli qophelo, omunye wozakwethu wayesevele esebenzise iskripthi ku-PowerShell, okuthi nsuku zonke, ngokohlelo, aqoqe imininingwane kuyo yonke imishini yawo wonke ama-vCenters futhi enze imibhalo emi-3 ye-csv (ngayinye nge-vCenter yayo), eyalayishwa idiski evamile. Kunqunywe ukuthi kuthathwe lesi sikripthi njengesisekelo futhi sengezelelwe ngamasheke sisebenzisa ulimi lwe-R, esibe nolwazi oluthile ngalo.

Enqubweni yokuphothulwa, isisombululo sithole ulwazi ngeposi, isizindalwazi esinethebula eliyinhloko nelomlando (okuningi kulokhu kamuva), kanye nokuhlaziywa kwamalogi e-vSphere ukuze kutholwe abadali bangempela be-vm kanye nesikhathi sokudalwa kwabo.

I-IDE RStudio Desktop kanye ne-PowerShell ISE zisetshenziselwa ukuthuthukiswa.

Umbhalo wethulwa emshinini ojwayelekile weWindows.

Incazelo yengqondo evamile.

I-logic evamile yemibhalo imi kanje.

  • Siqoqa idatha emishinini ebonakalayo sisebenzisa umbhalo we-PowerShell, esiwubiza ngo-R, bese sihlanganisa umphumela ube yi-csv eyodwa. Ukusebenzisana okuphambene phakathi kwezilimi kwenziwa ngendlela efanayo. (bekukwazi ukushayela idatha ngokuqondile ukusuka ku-R kuya ku-PowerShell ngendlela yezinto eziguquguqukayo, kodwa lokhu kunzima, futhi ukuba nama-csv aphakathi kwenza kube lula ukulungisa iphutha nokwabelana ngemiphumela ephakathi nomunye umuntu).
  • Sisebenzisa u-R, sakha amapharamitha avumelekile ezinkambu esiwahlolayo amanani azo. - Sakha umbhalo wamagama ozoqukatha amanani ale mikhakha ukuze afakwe encwadini yolwazi, okuzoba yimpendulo yemibuzo yozakwethu ethi "Cha, kodwa kufanele ngikugcwalise kanjani lokhu?"
  • Silayisha idatha yawo wonke ama-VM kusuka ku-csv sisebenzisa i-R, sakha uhlaka lwedatha, sikhipha izinkambu ezingadingekile futhi sakha idokhumenti yolwazi ye-xlsx ezoqukatha ulwazi olufingqiwe lwawo wonke ama-VM, esiwulayisha esisetshenziswa okwabelwana ngaso.
  • Sisebenzisa wonke amasheke okuthola ukunemba kokugcwalisa izinkambu kufreyimu yedatha yawo wonke ama-VM futhi sakha ithebula eliqukethe kuphela ama-VM anezinkambu ezigcwaliswe ngokungalungile (futhi lezi zinkambu kuphela).
  • Sithumela uhlu oluwumphumela lwama-VM kwesinye iskripthi se-PowerShell, esizobheka amalogi e-vCenter emicimbi yokudalwa kwe-VM, okuzosivumela ukuthi sibonise isikhathi esilinganiselwe sokudalwa kwe-VM nomdali ohlosiwe. Lokhu kwenzeka uma kungekho ovumayo ukuthi ngekabani imoto. Lesi script asisebenzi ngokushesha, ikakhulukazi uma kukhona izingodo eziningi, ngakho-ke sibheka kuphela emasontweni angu-2 okugcina, futhi sisebenzisa ukuhamba komsebenzi okukuvumela ukuthi useshe ulwazi kuma-VM amaningana ngesikhathi esisodwa. Umbhalo oyisibonelo uqukethe ukuphawula okuningiliziwe ngale nqubo. Sengeza umphumela ku-csv, esiphinde siyilayishe ku-R.
  • Senza idokhumenti ye-xlsx eyakheke kahle lapho izinkambu ezigcwaliswe ngokungalungile zizogqanyiswa ngokubomvu, izihlungi zizosetshenziswa kwamanye amakholomu, futhi amakholomu engeziwe aqukethe abadali abahlosiwe kanye nesikhathi sokudalwa kwe-VM kuzokhonjiswa.
  • Senza i-imeyili, lapho sinamathisela khona idokhumenti echaza amanani enkundla avumelekile, kanye nethebula elinezinkambu ezigcwaliswe ngokungalungile. Embhalweni sibonisa isamba senani lama-VM adalwe ngokungalungile, isixhumanisi esisetshenziswa okwabelwana ngaso kanye nesithombe esikhuthazayo. Uma engekho ama-VM agcwaliswe ngokungalungile, sithumela enye incwadi enesithombe esikhuthazayo.
  • Sirekhoda idatha yawo wonke ama-VM kusizindalwazi Seseva ye-SQL, sicabangela indlela esetshenzisiwe yamathebula omlando (indlela ethakazelisa kakhulu - mayelana nayo kamuva)

Empeleni imibhalo

Ifayela lekhodi elingu-R eliyinhloko

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

Iskripthi sokuthola uhlu lwe-vm ku-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
}

Iskripthi se-PowerShell esikhipha kulogi abadali bemishini ebonakalayo kanye nedethi yokudalwa kwayo

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

Umtapo wolwazi udinga ukunakwa okukhethekile xlsx, okwenze kwaba nokwenzeka ukwenza okunamathiselwe kuhlamvu kufomethwe ngokucacile (njengoba kuthandwa abaphathi), hhayi nje ithebula le-CSV.

Ikhiqiza idokhumenti enhle ye-xlsx enohlu lwemishini egcwaliswe ngokungalungile

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

Okukhiphayo kubukeka kanjena:

Imibiko yansuku zonke ngempilo yemishini ebonakalayo esebenzisa i-R ne-PowerShell

Kuphinde kwaba ne-nuance ethokozisayo mayelana nokusetha isihleli seWindows. Kwakungenakwenzeka ukuthola amalungelo nezilungiselelo ezifanele ukuze yonke into iqale njengoba kufanele. Ngenxa yalokho, umtapo wezincwadi we-R watholakala, wona ngokwawo udala umsebenzi wokuqalisa iskripthi sika-R futhi ungakhohlwa ngisho nefayela lokungena. Ngemva kwalokho ungakwazi ukulungisa umsebenzi mathupha.

Ucezu lwekhodi engu-R enezibonelo ezimbili ezidala umsebenzi ku-Windows Scheduler

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)

Ngokuhlukene mayelana nesizindalwazi

Ngemva kokusetha iskripthi, ezinye izinkinga zaqala ukuvela. Isibonelo, bengifuna ukuthola usuku okwasuswa ngalo i-VM, kodwa izingodo ku-vCenter zase zigugile kakade. Njengoba iskripthi sibeka amafayela kufolda nsuku zonke futhi singayihlanzi (siyihlanza ngezandla zethu lapho sikhumbula), ungabheka kumafayela amadala futhi uthole ifayela lokuqala lapho le VM ingekho khona. Kodwa lokho akulungile.

Bengifuna ukwakha isizindalwazi somlando.

Ukusebenza kwe-MS SQL SERVER - ithebula lesikhashana eliguqulelwe kusistimu - kwaba usizo. Ngokuvamile lihunyushwa ngokuthi amathebula esikhashana (hhayi esikhashana).

Ungafunda ngokuningiliziwe ku imibhalo esemthethweni ye-Microsoft.

Ngamafuphi, sakha itafula, sithi sizoba nalo ngokuhunyushwa, futhi i-SQL Server idala amakholomu esikhathi engeziwe angu-2 kuleli thebula (usuku irekhodi eladalwa ngalo kanye nosuku lokuphelelwa yisikhathi kwerekhodi) kanye netafula elingeziwe lapho izinguquko zishintsha khona. kuzobhalwa. Ngenxa yalokho, sithola ulwazi lwakamuva futhi, ngemibuzo elula, izibonelo zazo ezinikezwe emibhalweni, singabona noma umjikelezo wempilo womshini othile we-virtual, noma isimo sawo wonke ama-VM endaweni ethile. ngesikhathi.

Ngokombono wokusebenza, ukubhala kwethebula elikhulu ngeke kuqedwe kuze kuqedwe ukubhalwa kwethebula lesikhashana. Labo. ematafuleni anenani elikhulu lemisebenzi yokubhala, lokhu kusebenza kufanele kusetshenziswe ngokuqapha, kodwa esimweni sethu kuyinto epholile ngempela.

Ukuze umshini usebenze kahle, kwadingeka ngengeze ucezu oluncane lwekhodi ku-R oluzoqhathanisa ithebula elisha nedatha yawo wonke ama-VM nalelo eligcinwe kusizindalwazi bese ngibhala imigqa eshintshiwe kuphela kulo. Ikhodi ayihlakaniphe kakhulu; isebenzisa umtapo wolwazi wokuqhathanisa weDF, kodwa futhi ngizoyethula ngezansi.

Ikhodi engu-R yokubhala idatha kusizindalwazi

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

Inani

Njengomphumela wokusetshenziswa kombhalo, ukuhleleka kwabuyiselwa futhi kwagcinwa phakathi nezinyanga ezimbalwa. Kwesinye isikhathi ama-VM agcwaliswe ngokungalungile avela, kodwa iskripthi sisebenza njengesikhumbuzo esihle futhi i-VM engavamile ingena ohlwini izinsuku ezi-2 zilandelana.

Kwenziwa futhi umsebenzi wokuhlaziya idatha yomlando.

Kuyacaca ukuthi okuningi kwalokhu kungasetshenziswa hhayi emadolweni, kodwa ngesofthiwe ekhethekile, kodwa umsebenzi wawuthakazelisa futhi, omunye angase athi, ozikhethela.

I-R isiphinde yazibonakalisa njengolimi oluhle kakhulu lwendawo yonke, olungaphelele nje ekuxazululeni izinkinga zezibalo, kodwa futhi lusebenza “njengesendlalelo” esihle kakhulu phakathi kweminye imithombo yedatha.

Imibiko yansuku zonke ngempilo yemishini ebonakalayo esebenzisa i-R ne-PowerShell

Source: www.habr.com

Engeza amazwana