Warbixinnada maalinlaha ah ee ku saabsan caafimaadka mashiinnada farsamada gacanta ee isticmaalaya R iyo PowerShell

Warbixinnada maalinlaha ah ee ku saabsan caafimaadka mashiinnada farsamada gacanta ee isticmaalaya R iyo PowerShell

entry

Galab wanaagsan. Muddo nus sano ah hadda waxaan wadnay qoraal (ama halkii qoraallo) kuwaas oo soo saara warbixinno ku saabsan heerka mashiinnada farsamada (oo aan ahayn oo keliya). Waxaan go'aansaday inaan la wadaago waayo-aragnimadayda abuurista iyo koodka laftiisa. Waxaan rajeynayaa dhaleeceyn iyo in qalabkani uu noqon karo mid waxtar u leh qof.

Sameynta baahida

Waxaan haynaa mashiino fara badan (qiyaastii 1500 VMs oo loo qaybiyay 3 vCenters). Kuwo cusub ayaa la abuuraa kuwa horena marar badan ayaa la tirtiraa. Si loo ilaaliyo nidaamka, dhawr goobood oo caado ah ayaa lagu daray vCenter si loo qaybiyo VM-yada nidaamyo-hoosaadyo, oo tilmaamaya inay yihiin kuwo imtixaan, iyo cidda iyo goorta la abuuray. Arrinta bani'aadamku waxay keentay xaqiiqda ah in in ka badan kala badh mashiinnada ay ka tageen meelo bannaan, taas oo adkeynaysa shaqada. Lixdii biloodba hal mar, qof ayaa xanaaqay oo bilaabay inuu ka shaqeeyo cusboonaysiinta xogtan, laakiin natiijadu waxay joojisay inay khusayso toddobaad iyo badh ka dib.
Aan isla markiiba caddeeyo in qof kastaa fahmayo in ay tahay inay jiraan codsiyo abuurista mashiinnada, habka loo sameeyo, iwm. iyo wixi la mida. Isla mar ahaantaana, qof kastaa wuxuu si adag u raacayaa habkan wax walbana waa hagaagsan yihiin. Nasiib darro, tani maaha arrin halkan, laakiin tani maaha mawduuca maqaalka :)

Guud ahaan, go'aanka waxaa la sameeyay in si otomaatig ah loo hubiyo saxnaanta buuxinta goobaha.
Waxaan go'aansanay in warqad maalinle ah oo ay ku jiraan liis ay ku qoran yihiin mashiinno si khaldan loo buuxiyey dhammaan injineerada mas'uulka ka ah iyo madaxdooda ay noqoto bilow wanaagsan.

Halkaa marka ay marayso, mid ka mid ah asxaabteyda ayaa horay u hirgeliyay qoraal ku jira PowerShell, kaas oo maalin kasta, sida ku cad jadwalka, ururiyay macluumaadka dhammaan mashiinnada dhammaan vCenters oo uu soo saaray 3 dukumeenti csv ah (mid kasta oo u gaar ah vCenter), kuwaas oo la soo geliyay disk caadi ah. Waxaa la go'aamiyay in qoraalkan loo qaato saldhig oo lagu kabo hubinta iyadoo la adeegsanayo luqadda R, oo aan khibrad u lahayn.

Geedi socodka dhammaystirka, xalku wuxuu helay macluumaadka boostada, xog-ururin leh miis taariikhi ah iyo miis taariikhi ah (wax badan oo tan dambe ah), iyo sidoo kale falanqaynta vSphere logs si loo helo abuurayaasha dhabta ah ee vm iyo waqtiga abuurkooda.

IDE RStudio Desktop iyo PowerShell ISE ayaa loo isticmaalay horumarinta.

Qoraalka waxaa laga bilaabay mashiinka farsamada ee Windows caadiga ah.

Sharaxaada macquulka guud.

Macnaha guud ee qoraalladu waa sidan soo socota.

  • Waxaan ku uruurineynaa xogta mashiinnada farsamada gacanta anagoo adeegsanayna qoraalka PowerShell, kaasoo aan ugu yeerno R, oo aan ku darsano natiijada hal csv. Is dhexgalka ka dhexeeya luqadaha ayaa loo sameeyaa si la mid ah. (waxaa suurtagal ahayd in si toos ah xogta looga wado R loona gudbiyo PowerShell qaab doorsoomayaal, laakiin tani way adag tahay, iyo haysashada csvs dhexdhexaad ah waxay sahlaysaa in la saxo oo lala wadaago natiijooyinka dhexe qof).
  • Isticmaalka R, waxaan u sameynaa cabbirro sax ah meelaha aan qiimahooda hubineyno. - Waxaan abuureynaa dukumeenti kelmad oo ka koobnaan doona qiyamka goobahan si loo geliyo warqadda macluumaadka, taas oo noqon doonta jawaabta su'aalaha asxaabta "Maya, laakiin sidee baan tan u buuxiyaa?"
  • Waxaan ka soo rarnaa xogta dhammaan VM-yada csv annagoo adeegsanayna R, abuurna qaab-dhismeed xogeed, ka saarna meelaha aan loo baahnayn oo aan abuurno xog xlsx dukumeenti ka koobnaan doona macluumaadka kooban ee dhammaan VM-yada, kaas oo aan ku shubno kheyraadka la wadaago.
  • Waxaan codsanaa dhammaan jeegaga saxnaanta buuxinta goobaha xogta qaab-dhismeedka dhammaan VM-yada waxaanan abuurnaa miis ka kooban VM-yada oo keliya oo leh goobo aan sax ahayn (iyo meelahan oo keliya).
  • Waxaan u direynaa liiska natiijada VM-yada qoraal kale oo PowerShell ah, kaas oo eegi doona vCenter logs ee dhacdooyinka abuurista VM, taas oo noo ogolaan doonta inaan muujino waqtiga la qiyaasay ee abuurista VM iyo abuuraha loogu talagalay. Tani waa kiiska marka qofna uusan qiran gaariga uu yahay. Qoraalkani si dhakhso ah uma shaqeeyo, gaar ahaan haddii ay jiraan qoraallo badan, markaa waxaan eegnaa kaliya 2 toddobaad ee ugu dambeeyay, sidoo kale waxaan isticmaalnaa qulqulka shaqada kaas oo kuu ogolaanaya inaad raadiso macluumaadka dhowr VM isla waqti isku mid ah. Qoraalka tusaalaha waxa uu ka kooban yahay faallooyin faahfaahsan oo ku saabsan habkan. Waxaan natiijada ku darnaa csv, kaas oo aan mar kale ku shubnay R.
  • Waxaan soo saareynaa dukumeenti xlsx si qurux badan loo qaabeeyey kaas oo meelaha aan saxda ahayn lagu muujin doono casaan, filtarrada waxaa lagu dabaqi doonaa tiirarka qaar, iyo tiirar dheeraad ah oo ay ku jiraan abuurayaasha loogu talagalay iyo waqtiga abuuritaanka VM ayaa la tilmaami doonaa.
  • Waxaan soo saareynaa iimayl, halkaas oo aan ku soo lifaaqno dukumeenti qeexaya qiyamka goobta saxda ah, iyo sidoo kale miis ay si khaldan u buuxiyeen goobo. Qoraalka waxaan ku muujineynaa tirada guud ee VM-yada sida khaldan loo abuuray, isku xirka kheyraadka la wadaago iyo sawir dhiirigelin leh. Haddii aysan jirin VM-yada si khaldan loo buuxiyay, waxaan u dirnaa warqad kale oo leh sawir dhiirigelineed oo farxad leh.
  • Waxaan ku duubnaa xogta dhammaan VM-yada kaydka SQL Server-ka, anagoo tixgelinayna habka la hirgaliyay ee miisaska taariikhiga ah (hab aad u xiiso badan - kaas oo ka sii dambeeya)

Dhab ahaantii qoraallada

Faylka koodhka ugu weyn ee R

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

Qoraalka si aad u hesho liiska vm ee 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
}

Qoraal PowerShell ah oo ka soo saara diiwaannada hal-abuurka mashiinnada farsamada iyo taariikhda la abuuray

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

Maktabadu waxay mudan tahay fiiro gaar ah xlsx, taas oo suurtogal ka dhigtay in lifaaqa xarafka si cad loo habeeyey (sida maamulku jecel yahay), oo aan ahayn kaliya miiska CSV.

Soo saarista dukumeenti xlsx qurux badan oo ay ku jiraan liis ay si khaldan u buuxiyeen mishiinada

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

Wax-soo-saarku wuxuu u eg yahay sidan:

Warbixinnada maalinlaha ah ee ku saabsan caafimaadka mashiinnada farsamada gacanta ee isticmaalaya R iyo PowerShell

Waxa kale oo jirtay dareen xiiso leh oo ku saabsan dejinta jadwalaha Windows. Suurtagal ma ahayn in la helo xuquuqaha iyo goobaha saxda ah si wax walba u bilaabaan sidii la rabay. Natiijo ahaan, maktabadda R ayaa la helay, taas oo lafteedu abuuraysa hawl lagu bilaabayo qoraalka R oo aan xitaa iloobin faylka log. Markaa gacanta ayaad hawsha ku sixi kartaa.

Qayb R code ah oo leh laba tusaale oo hawl ku abuura Jadwalka 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)

Si gooni ah oo ku saabsan xogta xogta

Kadib dejinta qoraalka, arrimo kale ayaa bilaabay inay soo baxaan. Tusaale ahaan, waxaan rabay inaan helo taariikhda markii la tirtiray VM-ka, laakiin diiwaannada vCenter-ka ayaa mar hore daalan. Maadaama qoraalku uu maalin kasta geliyo faylal gal ah oo aanu nadiifin (gacmaheenna ayaan ku nadiifinnaa markaan xasuusanno), waxaad ka eegi kartaa faylalka duugga ah oo aad ka heli kartaa feylka ugu horreeya ee VM-kani aanu joogin. Laakiin taasi ma fiicna.

Waxaan rabay in aan sameeyo kayd taariikhi ah.

Shaqada MS SQL SERVER - miis ku meel gaar ah oo qaabaysan - ayaa soo gurmaday. Inta badan waxaa loo tarjumaa miisas ku meel gaar ah (ma aha ku meel gaar).

Waxaad si faahfaahsan u akhrin kartaa halkan dukumentiyada rasmiga ah ee Microsoft.

Marka la soo koobo, waxaanu samaynaa miis, waxaanu nidhaahnaa waanu yeelan doonaa versioning, iyo SQL Server waxay ku abuurtaa 2 tiir oo dheeraad ah oo taariikhi ah shaxdan (taariikhda diiwaanka la sameeyay iyo taariikhda uu dhacayo) iyo shax dheeraad ah oo isbeddelaya. waa la qori doonaa. Natiijo ahaan, waxaan helnaa macluumaad cusub oo, iyada oo loo marayo su'aalo fudud, tusaalooyin kuwaas oo lagu bixiyo dukumeentiyada, waxaan arki karnaa wareegga nolosha ee mashiinka farsamada gaarka ah, ama xaaladda dhammaan VM-yada meel gaar ah. waqtiga.

Marka laga eego dhinaca waxqabadka, wax kala iibsiga qoraalka ilaa miiska ugu weyn ma dhammaystirmi doono ilaa wax kala beddelashada miiska ku-meel-gaadhka ah la dhammaystiro. Kuwaas. miisaska leh tiro badan oo hawlo qoraal ah, shaqadan waa in si taxadar leh loo hirgeliyaa, laakiin kiiskeena waa wax aad u fiican.

Si farsamadu si sax ah ugu shaqeyso, waa inaan ku daraa kood yar oo R ah oo isbarbar dhigaya miiska cusub iyo xogta dhammaan VM-yada iyo midka lagu kaydiyay kaydka oo ku qor kaliya safafka la beddelay. Koodhku si gaar ah xariif uma aha; wuxuu isticmaalaa maktabadda barbardhiga ah, laakiin sidoo kale hoos ayaan ku soo bandhigi doonaa.

R code si loogu qoro xogta 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)

Wadarta

Natiijadii ka dhalatay hirgelinta qoraalka, nidaamka ayaa dib loo soo celiyay oo la dayactiray dhowr bilood gudahood. Mararka qaarkood VM-yada si khaldan loo buuxiyey ayaa soo muuqda, laakiin qoraalku wuxuu u adeegaa sidii xasuusin wanaagsan oo VM naadir ah ayaa liiska ku soo gala 2 maalmood oo isku xigta.

Shaqo hoose ayaa sidoo kale loo sameeyay falanqaynta xogta taariikhiga ah.

Way caddahay in inta badan tan aan lagu fulin karin jilibka, laakiin leh software khaas ah, laakiin hawshu waxay ahayd mid xiiso leh oo, mid ayaa laga yaabaa in la yiraahdo, ikhtiyaari.

R ayaa mar kale muujisay in ay tahay luuqad caalami ah oo heer sare ah, taas oo ku habboon ma aha oo kaliya xallinta dhibaatooyinka tirakoobka, laakiin sidoo kale waxay u dhaqmaan sidii "lakab" heer sare ah oo u dhexeeya ilaha xogta kale.

Warbixinnada maalinlaha ah ee ku saabsan caafimaadka mashiinnada farsamada gacanta ee isticmaalaya R iyo PowerShell

Source: www.habr.com

Add a comment