-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathGet-VMDiskSpace.ps1
340 lines (272 loc) · 12.1 KB
/
Get-VMDiskSpace.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
<#
.SYNOPSIS
Gather guest OS partition details from a VMware vSphere environment
.DESCRIPTION
This script/function will return individual partition space details for VMware guests operating systems.
The script/function is geared towards the virtualization administrator that may not have the necessary guest OS credentials or
privileges to query partion level disk space details across a heterogeneous guest environment.
This script/function pulls the information that is provided by VMware Tools, within the each guest OS. As such, VMware Tools
must be installed to query this level of detail via the vSphere API.
Pipeline input is supported, so you can use it similar to 'Get-DataCenter DC01 | Get-VM | .\Get-VMDiskSpace'.
The native input format that is required is that of a VI virtual machine (see .INPUTS). Any string values provided will be
checked and then an attempt to convert it to the proper type will be made.
Also included in the output are 'DatastoreList','VMXPath' and 'DatastoreMapping' properties. Since there is no easy/reliable
way to correlate: guest partition --> .VMDK --> datastore, the 'DatastoreList' represents all datastores that the guest has
a current .VMDK on. The 'DatastoreMapping' property contains an actual mapping of which .VMDK is sitting on which datastore.
The 'VMXPath' property contains the datastore mapping and path to where the .VMX file is located for a partiular guest.
search in a larger environment.
This script/function will also create a log directory named 'Get-VMDiskSpaceLogs' in the same directory where the script is ran from.
Sample output:
Name : WINSERVER01
Cluster : CLUS1
VMHost : prdesxi02.corp.domain
Partition : C:\
CapacityInGB : 50
SpaceUsedInGB : 24
SpaceFreeInGB : 26
PercentFree : 51
DatastoreList : nas01_sata_nonrepl_nfs1, nas01_sata_nonrepl_nfs2
VMXPath : [nas01_sata_nonrepl_nfs2] WINSERVER01/WINSERVER01.vmx
DatastoreMapping : [nas01_sata_nonrepl_nfs2] WINSERVER01/WINSERVER01.vmdk, [nas01_sata_nonrepl_nfs1] WINSERVER01/WINSERVER01_1.vmdk
Name : WINSERVER01
Cluster : CLUS1
VMHost : prdesxi02.corp.domain
Partition : E:\
CapacityInGB : 50
SpaceUsedInGB : 26
SpaceFreeInGB : 24
PercentFree : 47
DatastoreList : nas01_sata_nonrepl_nfs1, nas01_sata_nonrepl_nfs2
VMXPath : [nas01_sata_nonrepl_nfs2] WINSERVER01/WINSERVER01.vmx
DatastoreMapping : [nas01_sata_nonrepl_nfs2] WINSERVER01/WINSERVER01.vmdk, [nas01_sata_nonrepl_nfs1] WINSERVER01/WINSERVER01_1.vmdk
.PARAMETER Name
Display name of VMware Guest/s
.PARAMETER VIServer
FQDN of vCenter Server (VI Server)
.INPUTS
System.String
VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl
.OUTPUTS
System.Management.Automation.PSCustomObject
.EXAMPLE
.\Get-VMDiskSpace -Name WINSRV01,WINSRV02,REDHAT01 | Format-Table -AutoSize
.EXAMPLE
.\Get-VMDiskSpace -Name VM01,VM02 -VIServer vcenter01.company.com -Verbose | Out-GridView
.EXAMPLE
Get-Cluster CLUS01 | Get-VM | .\Get-VMDiskSpace | Export-Csv C:\VI_CLUS01_DiskSpaceReport.csv -NoTypeInformation
.EXAMPLE
.\Get-VMDiskSpace -Name (Get-VM VM01,VM02,VM03) | Out-GridView
.NOTES
Author: Kevin Kirkpatrick
Last Update: 20141223
Last Update Notes:
- Added 'DatastoreList', 'VMXPath' & 'DatastoreMapping' properties to output
- Added logging
#TAG:PUBLIC
GitHub: https://github.com/vScripter
Twitter: @vScripter
Email: [email protected]
[-------------------------------------DISCLAIMER-------------------------------------]
All script are provided as-is with no implicit
warranty or support. It's always considered a best practice
to test scripts in a DEV/TEST environment, before running them
in production. In other words, I will not be held accountable
if one of my scripts is responsible for an RGE (Resume Generating Event).
If you have questions or issues, please reach out/report them on
my GitHub page. Thanks for your support!
[-------------------------------------DISCLAIMER-------------------------------------]
.LINK
https://github.com/vScripter
#>
#Requires -Version 3
[cmdletbinding(DefaultParameterSetName = "Default")]
param (
[parameter(Mandatory = $true,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true)]
[alias('VM', 'Guest')]
$Name,
[parameter(Mandatory = $false,
Position = 1)]
[string]$VIServer
)
BEGIN {
<#
- define functions
- call/set variables
- setup logging
- Check if the VMware.VimAutomation.Core PSSnapin had been added; if not, attempt to add it
- Connect to the provided vCenter Server, if none if provided, check to see if a connection has already been established
#>
function Get-ScriptDirectory {
if ($hostinvocation -ne $null) {
Split-Path $hostinvocation.MyCommand.path
} else {
Split-Path $script:MyInvocation.MyCommand.Path
}
} # end function Get-ScriptDirectory
function TimeStamp {
$dtLogTimeStamp = Get-Date -Format ("[yyyy-MM-dd HH:mm:ss] ")
$dtLogTimeStamp
} # end function TimeStamp
$dtScriptStart = Get-Date
$dtLogFileName = (Get-Date).ToString("yyyyMMddHHmmss")
$scriptPath = Get-ScriptDirectory
$logDirectory = "$scriptPath\Get-VMDiskSpaceLogs"
$log = "$logDirectory\Get-VMDiskSpace_$dtLogFileName.log"
if (-not (Test-Path -Path $logDirectory)) {
try {
New-Item -ItemType Directory -Path $scriptPath -Name 'Get-VMDiskSpaceLogs' | Out-Null
} catch {
Write-Warning -Message "Error creating log directory '$logDirectory'"
Write-Warning -Message 'Exiting script'
Exit
} # end try/catch
} # end if/else Test-Path
Write-Output "======== Get-VMDiskSpace - Started - $(TimeStamp) ========" >> $log
$colFinalResults = @()
Write-Verbose -Message 'Checking for VMware.VimAutomation.Core PSSnapin'
if ((Get-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction 'SilentlyContinue').Name -eq $null) {
try {
Add-PSSnapin VMware.VimAutomation.Core -ErrorAction 'Stop'
} catch {
Write-Warning -Message "Error adding VMware PSSnapin: $_"
Write-Warning -Message 'Exiting script'
Write-Output "$(TimeStamp) Error: adding PSSnapin - $_" >> $log
Write-Output "$(TimeStamp) Error: Exiting script" >> $log
Exit
} # try/catch
} else {
Write-Verbose -Message "VMware.VimAutomation.Core PSSnapin is already added; continuing..."
} # end if/else
Write-Verbose -Message 'Connecting to vCenter Server'
if ($VIServer) {
try {
$VIServer = Connect-VIServer -Server $VIServer
} catch {
Write-Warning -Message 'Error connecting to vCenter'
Write-Warning -Message 'Exiting script'
Write-Output "$(TimeStamp) Error: connecting to vCenter - $_" >> $log
Write-Output "$(TimeStamp) Error: Exiting script" >> $log
Exit
} # end try/catch
} elseif (($global:defaultviserver).Name -eq $null) {
Write-Warning -Message 'No default vCenter connection. Connect to vCenter or specify a vCenter Server name and try again.'
Write-Warning -Message 'Exiting script'
Write-Output "$(TimeStamp) Error: No default vCenter connection. Connect to vCenter or specify a vCenter server name and try again" >> $log
Write-Output "$(TimeStamp) Error: Exiting script" >> $log
Exit
} else {
$VIServer = $global:defaultviserver
} # end if/else
}# BEGIN
PROCESS {
try {
foreach ($vm in $Name) {
# call/set variables and varialbe types
$objGuestDisk = @()
$vmDetail = $null
$diskInfo = $null
[int]$diskCapacity = $null
[int]$diskSpaceUsed = $null
[int]$diskSpaceFree = $null
[int]$diskPercentFree = $null
$vmCurrentDatastores = $null
$dsName = $null
$dsMap = $null
$vmVMXPath = $null
$vmHostDetail = $null
<#
- Validate VM type; if strings were passed, convert the type from [System.String] to [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl] by using Get-VM
- use foreach to interate through the array of guest names passed
- ignore guests that are powered off
- collect data on current datastores that each partition could potentially reside on
- store detail in a custom object and add each iteration to the $colFinalResults array
#>
Write-Verbose -Message 'Validating VM Type'
if (($vm).GetType().Fullname -ne 'VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl') {
try {
$vm = Get-VM -Name $vm -ErrorAction 'Stop'
} catch {
Write-Warning -Message "Error converting $vm to a proper VI object type"
Write-Output "$(TimeStamp) Error: converting input to a proper VI object type" >> $log
} # end try/catch
} else {
Write-Verbose -Message 'VM Type is correct or has been converted correctly; continuing...'
} # end if/else
Write-Verbose -Message "Gathering VM details on $($vm.Name)"
Write-Output "$(TimeStamp) Info: Gatering VM details on $($vm.Name)" >> $log
if ($vm.PowerState -eq 'PoweredOff') {
Write-Warning -Message "$($vm.Name) is Powered Off"
Write-Output "$(TimeStamp) Warning: $($vm.Name) is Powered Off " >> $log
} else {
$vmDetail = $vm.ExtensionData
Write-Verbose -Message "Gathering current datastores on $($vm.Name)"
$vmCurrentDatastores = $vmDetail.Config.DatastoreUrl.Name
foreach ($datastore in $vmCurrentDatastores) {
$dsName += "$datastore, "
} # end foreach $datastore
<# In regex, '$' indicates the last charater in a string or before '\n' at the end of a line or string; '.' is wildcard for any single charater except for '\n';
"..$" = remove the last two charaters of the string, which would be a comma and one space, in this scenario. #>
$dsName = $dsName -replace "..$"
Write-Verbose -Message "Gathering .VMDK <--> Datastore mappings for $($vm.Name)"
$vmDatastoreMap = ($vmDetail.layoutex.file | Where-Object { $_.name -like '*.vmdk' -and $_.name -notlike '*flat*' }).Name
foreach ($mapping in $vmDatastoreMap) {
$dsMap += "$mapping, "
} # end foreach $mapping
$dsMap = $dsMap -replace "..$"
Write-Verbose -Message "Gathering .VMX path for $($vm.Name)"
$vmVMXPath = $vmDetail.summary.config.vmpathname
Write-Verbose -Message "Gathering VM Host details for $($vm.Name)"
try {
$vmHostDetail = Get-VMHost -Id ($vmDetail.Summary.Runtime.Host) -ErrorAction 'Stop'
} catch {
Write-Warning -Message "Error gathering host details"
Write-Output "$(TimeStamp) Error: gathering host details - $_" >> $log
} # end try/catch
Write-Verbose -Message "Gathering partition details on $($vm.Name)"
$diskInfo = $vmDetail.Guest.Disk
foreach ($disk in $diskInfo) {
if ($disk.Capacity -eq 0) {
Write-Warning -Message "Disk capacity is zero; zeroing all values for the $($disk.Diskpath) partition on $($vm.name)"
$diskCapacity = 0
$diskSpaceUsed = 0
$diskSpaceFree = 0
$diskPercentFree = 0
} else {
$diskCapacity = $disk.Capacity / 1GB
$diskSpaceUsed = ($disk.Capacity - $disk.FreeSpace) / 1GB
$diskSpaceFree = $disk.FreeSpace / 1GB
$diskPercentFree = ($disk.FreeSpace / $disk.Capacity) * 100
} # end if/else
$objGuestDisk = [PSCustomObject] @{
Name = $vm.Name
Cluster = $vmHostDetail.Parent
VMHost = $vmHostDetail.Name
Partition = $disk.DiskPath
CapacityInGB = $diskCapacity
SpaceUsedInGB = $diskSpaceUsed
SpaceFreeInGB = $diskSpaceFree
PercentFree = $diskPercentFree
DatastoreList = $dsName
VMXPath = $vmVMXPath
DatastoreMapping = $dsMap
} # end $objGuest
$colFinalResults += $objGuestDisk
} # end foreach $disk
} # end foreach $vm
} # end if/else
} catch {
Write-Warning -Message "Error Gathering Details on $vm - $_"
Write-Output "$(TimeStamp) Error: Gathering Details on $vm - $_" >> $log
} # end try/catch
}# end PROCESS
END {
Write-Verbose -Message 'Done'
$colFinalResults
$dtScriptEnd = Get-Date
$dtRuntime = $dtScriptEnd - $dtScriptStart
Write-Output "======== Total Runtime: $($dtRunTime.Hours) Hours, $($dtRuntime.Minutes) Minutes, $($dtRuntime.Seconds) Seconds ========" >> $log
Write-Output "======== Get-VMDiskSpace - Completed - $(TimeStamp) ========" >> $log
}# end END