Skip to content

VMware: finding VM snapshots via SQL query

Snapshots are reasonable good. Just click «Snapshot» and you’re saved. Once then you forgotten to remove snapshot. What happens next? It grows. No. It Grows. And also makes datastore response time grow. If snapshot was created on heavy loaded VM which is database server for example, snapshot removal can take up to several hours to complete. This can bring additional problems. The best way to avoid them is to prevent them.

There are two ways to find VMs with snapshots. First one is using Powershell PowerCLI script. It well described on the internets:

Add-PSSnapin VMware.VimAutomation.Core
Connect-VIServer vcenter.domain.local
Get-VM | Get-Snapshot

Scripting is flexible and easy. You can generate report and send it via e-mail. No matter if script runs for several minutes. But as for me this matters if it runs longer. This made me to do some research on vCenter database. Resulting query made me wonder. SQL executed in less than one second and returned the same results as Powershell script, which was running for 10 minutes! Query returns table with the following columns: VM Name, Snapshot name, Description, Snapshot Size, Creation time and Username.

So this is the query:

SELECT DISTINCT
VPX_ENTITY.NAME,
VPX_SNAPSHOT.SNAPSHOT_NAME,
CAST(VPX_SNAPSHOT.SNAPSHOT_DESC AS NVARCHAR(MAX)) AS Description,
SUM(CAST(CAST(VPX_VM_FLE_FILE_INFO.FILE_SIZE AS DECIMAL(18, 0)) / 1073741824 AS DECIMAL(9, 2))) AS FileSize,
VPX_SNAPSHOT.CREATE_TIME,
VPX_TASK.USERNAME
FROM dbo.VPX_SNAPSHOT
INNER JOIN dbo.VPX_ENTITY
ON VPX_SNAPSHOT.VM_ID = VPX_ENTITY.ID
INNER JOIN dbo.VPX_VM_FLE_FILE_INFO
ON VPX_SNAPSHOT.VM_ID = VPX_VM_FLE_FILE_INFO.VM_ID
INNER JOIN dbo.VPX_TASK
ON VPX_SNAPSHOT.VM_ID = VPX_TASK.VM_ID
WHERE VPX_VM_FLE_FILE_INFO.TYPE = ‘diskExtent’
AND VPX_VM_FLE_FILE_INFO.NAME LIKE ‘%-delta.vmdk’
AND VPX_TASK.COMPLETE_TIME BETWEEN DATEADD(mi, -1, VPX_SNAPSHOT.CREATE_TIME) AND DATEADD(mi, 1, VPX_SNAPSHOT.CREATE_TIME)
AND VPX_TASK.NAME = ‘vim.VirtualMachine.createSnapshot’
GROUP BY VPX_SNAPSHOT.SNAPSHOT_NAME,
VPX_ENTITY.NAME,
CAST(VPX_SNAPSHOT.SNAPSHOT_DESC AS NVARCHAR(MAX)),
VPX_SNAPSHOT.CREATE_TIME,
VPX_TASK.USERNAME
ORDER BY VPX_ENTITY.NAME

Фонарик для Android

У многих есть хобби: кто-то бегает, кто-то прыгает. А я вот фонарик для Android’а написал:

  • сам выключается через 5 минут
  • показывает, сколько осталось до выключения
  • занимает 250Кб
  • без надоедливой рекламы

Устанавливается традиционно через Play Market.

Monitoring VMware Horizon View pool status

I have a VMware Horizon View virtual desktop automated pool which configuration basis is:

  • floating user assignment
  • composer linked clone
  • persona management
  • delete VM after user logoff

Configuration brings virtual desktops to recompose every night after user logoff. And I should say everything works just fine till now although I didn’t believe it would when it was in testing environment. Yes, I had some problems which were related to configuration mistakes, but none of them related to VMware.

After almost 2 years of non-interruptable servicing it finally broken. Desktop rocomposing was very slow, it almost stopped. The issue described on VMware community relates to VSA (Volume Storage Accelerator), implemented in VMware View starting from version 5.1 and which is not good in my configuration. Issuie resolved simply by disabling VSA and restarting ESXi hypervisors.

This event made me thinking of how to monitor pool state. I suggested the dashboard values shoud be monitored:

  • Prepared for use
  • Connected
  • Available

As VMware does not provide any well known way to export these values from dashboard, it needed some investigation. View stores virtual desktop properties in LDAP directory on View connection broker server and summary of connected clients in Windows performance counters. After some research I constructed query to get these amounts. As I wanted to monitor using Zabbix, I needed a .vbs-script that runs via Zabbix Agent by corresponding «UserParameter». Configuring Zabbix is not the problem I met, it discribed on the Internets. The whole point is .vbs-script. Well, it is:

Counter = WScript.Arguments.Item(0)
Result = 0
Set strADsPath = GetObject("LDAP://127.0.0.1:389/OU=Servers,DC=vdi,DC=vmware,DC=int")
' Available
if Counter = "Available" then
 for each strADsPathObject in strADsPath
 if strADsPathObject.[pae-VmState] = "READY" then Result = Result + 1 end if
 if strADsPathObject.[pae-DirtyForNewSessions] = 1 then Result = Result - 1 end if
 next
end if
' Connected
if Counter = "Connected" then
 Set objWMIService = GetObject("winmgmts:\\.\ROOT\CIMV2")
 Set WMIItems = objWMIService.ExecQuery("SELECT AllSessions FROM Win32_PerfRawData_VMwareVDM_VMwareVDM")
 For Each WMIItem in WMIItems
 Result = WMIItem.AllSessions
 Next
end if
' Prepared for Use
if Counter = "Prepared" then
 for each strADsPathObject in strADsPath
 if strADsPathObject.[pae-VmState] = "READY" then Result = Result + 1 end if
 next
end if
strADsPath = Nothing
WScript.Echo Result

Run the script using cmd with the wollowing command:

cscript /nologo vdistats.vbs [Available|Connected|Prepared]

Script result has some variance in comparison with dashboard data, especially when pool meets errors. This refers to the data calculation method as it’s not clear how to calculate from LDAP. Anyway, if you find greater way to automate monitoring, please comment!

Powershell: importing module

How do I usually import an AD powershell module? I think the same way as you do:

Import-Module -Name ActiveDirectory -ErrorAction SilentlyContinue

How do I import another one in a script body a slightly wiser way using a custom function to determine if module exists in a system or is already loaded?

Function ImportModule($modulename) {
 if(-not(Get-Module $modulename)) {
 if(Get-Module -ListAvailable | Where-Object { $_.name -eq $modulename }) {
 Import-Module -Name $modulename
 } else {
 "Module $modulename not found. Exiting.";Exit
 }
 } else {
 "Module $modulename already loaded"
 }
 }
 ImportModule ActiveDirectory

Powershell: сортировка и нумерация фотографий с двух камер

Подготавливая фотографии после съемки на несколько камер к передаче заказчику, однажды впервые задумываешься: а ведь файлы сортируются в программе-просмотрщике не по порядку. Не в том порядке, в котором производилась съемка. И как заказчик будет на это реагировать? Скорее всего, положительного впечатления ему это не добавит. Как заставить просмотрщик отсортировать кучу фотографий с разных камер по времени съемки, прописанному камерой внутри файлов?

Для решения этой задачи я написал некую утилиту. Пусть она будет называться JPGexifsorter. Работает она следующим образом. Утилита считывает время съемки каждого фото, сортирует по возрастанию и копирует в новую папку, рядом с выбранной, переименовывая каждую фотографию. Если в исходной папке было 1200 файлов IMG_3034.JPG, IMG_3078.jpg и т.д., то в конечной папке будет 1200 файлов с именами 0001.jpg, 0002.jpg, … 1200.jpg.

exifsofter

Что бы воспользоваться JPGexifsorter, на компьютере должен быть установлен Windows 7, Powershell и .NET. В общем, если на компьютере Windows 7, то беспокоиться не о чем. Итак, что нужно сделать:

  1. «Пуск» -> набрать «Powershell» -> правой кнопкой нажать на «Windows PowerShell» и выбрать «Запустить от имени администратора».
  2. В появившейся консоли набрать команду: Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted и согласиться с предупреждением.
  3. Скачать JPGexifsorter по этой ссылке и распаковать в любую папку.
  4. Запустить JPGexifsorter.cmd

Можно сделать еще так:

  1. Открыть вложенный в архив файл JPGexifsorter.reg в блокноте
  2. Исправить путь, по которому находится JPGexifsorter.ps1
  3. Импортировать .reg-файл в реестр.
  4. Нажать правой кнопкой мыши на папке с фотографиями и выбрать пункт «Sort with JPGexifsorter».

Есть другие способы пронумеровать снимки в том порядке, в котором производилась съемка. Например, в Adobe Lightroom, или используя комбинации из других программ (например, Exifier + Total Commander). Но способ с этой утилитой лично для меня более удобен.

SCCM 2012: Clients can’t be auto approved

Что бы System Center Configuration Manager 2012 имел возможность полноценно общаться со своими клиентами, они должны иметь статус Approved в консоли управления. Конфигурируется это так: «Administration» -> «Site Configuration» -> «Sites» -> «Site» -> «Hierarchy Settings (в верхней ленте)» -> «Client Approval and Conflicting Records». Скорее всего у вас не будет проблем, если SCCM настроен на работу по HTTPS. В том случае, если сайт работает по HTTP, компьютеры после установки клиента не получают статус Approved, даже если установлено «Automatically approve computers in trusted domains». Как минимум, в результате этого на рабочие станции не будет установлен System Center Endpoint Protection (если включена опция установки антивируса в параметрах агента). Решается это добавлением на сервер SCCM функции Windows Authentication в IIS: «Server Manager» -> «Roles» -> «Web Server (IIS)» -> «*Правый клик*» -> «Add Role Services» -> «Security» -> «Windows Authentication».

Спасибы:
http://blogs.technet.com/b/configurationmgr/archive/2010/01/20/how-it-works-automatic-client-approval-in-configuration-manager-2007.aspx
http://bassemawad.com/?p=630

Exchange 2010: automatic welcome message for a new user

If you need to send a welcome message to every new Exchange user, you are in the right place and I will explain why. A wiser method to do this is «Exchange Cmdlet Extension Agent». At the moment I wrote this article there was no comprehensive solution for this task on the Internets. The main problem I met is that user mailbox can be created using two cmdlets: new-mailbox and enable-mailbox. First one works well, but when you try to do the same scripting with Enable-Mailbox cmdlet, everything fails. If you are new to powershell scripting, just use my script, it should work fine. If you faced the same problem already and didn’t find solution then you should understand what really happens in that Exchange server while reading the script.

Basic steps to configure welcome message on Exchange 2010 server:

1. Place the following script on every Exchange server in your Exchange organization (except Transport server role) in to the following folder: «C:\Program Files\Microsoft\Exchange Server\V14\Bin\CmdletExtensionAgents\ScriptingAgentConfig.xml». Please be attentive to not start step 2 before working version of the script is in the folder.

<?xml version="1.0" encoding="utf-8" ?>
<Configuration version="1.0">
<Feature Name="WelcomeEmail" Cmdlets="New-Mailbox,Enable-Mailbox">
<ApiCall Name="OnComplete">
if($succeeded) {
 # Waiting for synchronization after mailbox has been created.
 Set-ADServerSettings -ViewEntireForest $true
 Start-Sleep -s 10
 # New-Mailbox triggered. Taking SamAccountName parameter.
 if ($provisioningHandler.UserSpecifiedParameters.Contains("SamAccountName") -eq $true) {
 $UsrSamAccountName = $provisioningHandler.UserSpecifiedParameters["SamAccountName"]
 $UsrAlias = (Get-Mailbox -Filter {SamAccountName -eq $UsrSamAccountName}).Alias.ToString()
 }
 # Enable-Mailbox triggered. Taking Identity parameter, this is the only one avalaible in this case.
 if ($provisioningHandler.UserSpecifiedParameters.Contains("Identity") -eq $true) {
 $UsrIdentity = $provisioningHandler.UserSpecifiedParameters["Identity"].ToString()
 $UsrAlias = (Get-Mailbox -Identity $UsrIdentity).Alias.ToString()
 }
 # Defining variables.
 $UsrAddr = (Get-Mailbox -Filter {Alias -eq $UsrAlias}).PrimarySmtpAddress.ToString()
 $UsrOU = (Get-Mailbox -Filter {Alias -eq $UsrAlias}).OrganizationalUnit
 # Sending email notification to the user in specific OU.
 if ($UsrOU -match "DOMAIN.LOCAL/OrganizationalUnit") {
 $UsrMsg = [string](Get-Content ("c:\scripts\WelcomeMessage.html"))
Send-MailMessage -SmtpServer "MAILER.DOMAIN.LOCAL" -To "$UsrAddr" -From "welcome@DOMAIN.LOCAL" -Subject "Welcome to our company!" -Body $UsrMsg -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF8)
 }
 # Clearing variables. Each one in its own line in order to prevent error messages from being shown on EMC.
 if ($UsrAlias) { Remove-Variable UsrAlias }
 if ($UsrAddr) { Remove-Variable UsrAddr }
 if ($UsrOU) { Remove-Variable UsrOU }
 if ($UsrMsg) { Remove-Variable UsrMsg }
 if ($UsrIdentity) { Remove-Variable UsrIdentity }
 if ($UsrSamAccountName) { Remove-Variable UsrSamAccountName }
}
</ApiCall>
</Feature>
</Configuration>

This script assumes that welcome message body is placed in «c:\scripts\WelcomeMessage.html» on every Hub Transport server. Don’t forget to edit parameters marked with red.

2. Enable Scriptng Agent extension on the Exchange infrastructure.

Enable-CmdletExtensionAgent "Scripting Agent"

3. Restart every Exchange Management Console/Shell that already runs.

4. Try to create/enable a new mailbox user. This should do the trick.

Windows Server 2012 WSUS: Downloaded 0 Mb

As a result of 2-day struggling with WSUS 4.0 on Windows Server 2012, which was not able to download any approved updates from Microsoft Windows Update site and always showed 0Mb downloaded, I figured out that this was because of faulty GPO settings. As I tried to migrate from an older version of WSUS with a clean reinstall, I missed that there was the GPO which targeted to old WSUS server. After WSUS 4.0 server was excluded from that GPO, updates started to download well. Before that I tried to clean .NET install, clean WSUS folders, modify proxy server settings, etc. and nothing worked. Anyway GPO did the trick, so please be attentive. By the way, this is the error specified in «C:\Program Files\Update Services\LogFiles\SoftwareDistribution.log»: «Content file download failed. Reason: Value does not fall within the expected range», so if you find the same log records, this may be your case.

VMware: datastores and hosts monitoring with Zabbix

Какая система мониторинга не использовалась бы, необходимо получать данные из наблюдаемой системы. VMware могла оказать огромную услугу, если бы писала показатели инфраструктуры в виндовые «Performance Counters», тогда любой мониторинг не вызывал бы проблем, но на данный момент это кажется фантастикой. Фантастикой, потому что создается впечатление, что генеральная линия компании заключается в том, что бы не признавать существование никаких других продуктов вокруг себя (впрочем, у VMware и так все хорошо, зачем им кого-то признавать). Вывод такой сделан на основании того, что, если флагман VMware vCenter и имеет довольно удобные апплеты vSphere PowerCLI (которые скорее являются инструментом управления, чем мониторинга), то другие продукты (а, в частности, VMware View), не имеют средств выгрузки полезных (именно полезных) показателей во внешние системы вовсе. О мониторинге View я еще заведу разговор позже, там целая история, а вот начну все же с мониторинга vCenter.

Моей конечной целью является мониторинг свободного места на Datastores и состояния хостов ESXi. Исходя из найденной информации, самым простым и в то же время НЕ элегантным решением стала связка Zabbix и vCenter с использованием powershell-скрипта с апплетами vSphere PowerCLI для выгрузки. И тем не менее, данный способ вполне адекватно работает и не вызывает нареканий. Итак, обо всем по порядку:

1. Создаем локальную учетную запись на сервере vCenter. Необходимо, что бы эта учетная запись имела доступ к параметрам vCenter. Самые смелые могут дать этой учетной записи права локального администратора.

2. Создаем в «планировщике задач» задание, запускаемое от имени учетной записи п. 1, которое при запуске системы с отсрочкой в 15 минут единожды выполняет следующий powershell-скрипт:

Add-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue
Connect-VIServer vCenter.domain.local > $nul
$Storages = @(
"storage-1"
"storage-2"
)
$Hosts = @(
"esxi-1.domain.local"
"esxi-2.domain.local"
)
while (1 -gt 0) {
 $Storages | % {
 $("$([math]::Round((Get-Datastore $_).FreeSpaceGb,2))").Replace("`,","`.") | out-file "C:\Zabbix\vmware\$_"
 }
 $Hosts | % {
 (Get-VMHost $_).ConnectionState | out-file "c:\zabbix-agent\monitoring\$_"
 }
 Start-Sleep -s 180
}

Скрипт работает как Windows-служба и раз в три минуты создает в папке «c:\zabbix-agent\monitoring» файлы с именами хранилищ / хостов, в которые записываются полученные значения.

3. Редактируем конфигурацию Zabbix-агента. Нужно добавить следующую строчку:

UserParameter=vcentermonitor[*],c:\windows\cmd.exe /c type c:\zabbix-agent\monitoring\$1

После чего перезапускаем службу агента.

4. В самом Zabbix в хосте с vCenter добавляем «элементы данных» следующего вида: vcentermonitor[storage-1]. Этот «элемент данных» будет собирать информацию о свободном месте на хранилище.

Таким образом можно мониторить любой параметр, который получится достать через Powershell PowerCLI. Для примера, при использовании DRS можно выгружать количество виртуалок на хосте, объем свободной RAM и т.п. Постоянно запущенный скрипт Powershell через некоторое время может начать пожирать память (у меня такого эффекта не наблюдалось), в таком случае можно настроить периодический его перезапуск. Как бы то ни было, такой запуск скрипта лучше, чем ежеменутный запуск агентом Zabbix, если вы понимаете, о чем я.

Active Directory: get user password expiration date

Узнать дату истечения пользовательского пароля можно так:

(Get-ADUser USERNAME -Properties PasswordLastSet).PasswordLastSet + $(Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge