How can I use "IF" statement to determine the amount of free disk space to add to a VMDK? - windows

The script I am using is below. We are upgrading our 1500 VDI's from Windows 10 1809 to 1909 and we want to automate the process as much as possible since this will be a process that we will have to do regularly with each new version Windows puts out. We are using SCCM (System Center Configuration Manager). The script works perfect for extending disk space for multiple machines. The .csv file it is importing only contains a list of virtual machines the script is to expand disk space on. I want to use an "if" statement to determine if the amount of free space is below 30GB and, if so, to add the needed disk space to bring it up to 30GB free space. Example: "if" free disk space is -lt 30GB, Set-HardDisk -CapacityGB (the difference to make 30GB free space available), "if" free space is -eq to 30GB, do nothing. I have researched Google and this site for anything remotely similar and wasn't able to find what I need. All help accomplishing this is appreciated.
##Task Change Disk Size
##Variable clear
$csvobjects = #()
$cskobject = #()
$network = #()
$isalive = #()
##Import VM name(s)
$csvobjects = Import-CSV -path "C:\Temp\ExpandHDDiskList.csv"
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
connect-viserver -server anyserver.com -User anyuser#anyserver.com
foreach ($csvobject in $csvobjects){
##Variable clear
$network = #()
$isalive = #()
##Pre-change data gathering
$beforechange = (GET-VM -Name $csvobject.vmname | FT -auto CapacityGB|out-string)
##Stop VM
GET-VM -Name $csvobject.vmname | Get-HardDisk -Name 'Hard disk 1' | Set-HardDisk -CapacityGB 75 -Confirm:$false
start-sleep -s 60
# Variable specifying the drive you want to extend
$drive_letter = "C"
# Script to get the partition sizes and then resize the volume
$size = (Get-PartitionSupportedSize -DriveLetter $drive_letter)
Resize-Partition -DriveLetter $drive_letter -Size $size.SizeMax
}

You can use Get-VMGuest to get the free space within the guest VM.
Set the target amount of free space in a variable. 30GB (GB = 1024^3)
$gb = 1024 * 1024 * 1024
$space = 30 * $gb
Get the free space from the VM using Get-VMGuest
$vm = Get-VMGuest $csvobject.vmname
Now, assuming a single hard disk in the machine, determine if the free space is less than 30GB. If it is, increase the hard disk size so that there is 30GB of free space. The calculation takes the capacity of the disk and adds on the required free space (30GB) and then subtracts the current free space. This is all done in bytes so convert it into GB and round it to a whole number to avoid weird disk sizes:
if ($vm.Disks[0].FreeSpace -lt $space) {
Get-HardDisk $vm.Vm | Select -first 1 | Set-HardDisk -CapacityGB ([math]::round(($vm.Disks[0].Capacity + $space - $vm.Disks[0].FreeSpace) / $gb))
}
Take care when running, particularly if you have machines with multiple hard disks.
Assuming Windows VMs, you don't need to stop the VM. You can resize the filesystem remotely using Invoke-Command or Invoke-VMScript.

With PowerShell 5 or newer you can replace
$gb = 1024 * 1024 * 1024
with
1GB
And replace
$space = 30 * $gb
with
30GB
So, the entire script would look like this
$vm = Get-VMGuest $csvobject.vmname
if ($vm.Disks[0].FreeSpace -lt 30GB) {
Get-HardDisk $vm.Vm | Select -first 1 | Set-HardDisk -CapacityGB ([math]::round(($vm.Disks[0].Capacity + 30GB - $vm.Disks[0].FreeSpace) / 1GB))}

Related

PowerShell update variable while script is running

How do i update a variable in PowerShell while the script is running state?
I have a situation where the script monitors the size of a disk continuously and compares it with a number in a text file on a shared drive (say Z:\quota\software-share-size.txt). If the number in text file is greater than disk size it monitors, then it sends out an email to expand the disk to new size as mentioned in text file. But once the script starts, its not pulling in the new number from file and i dont want to stop and start the script to load new content from the text file. Help please
Maybe this can help you :
while($true)
{
#Here i pull my disk (C:) infomations (i use localhost for my computer, but you can use an IP or a file with multiple IP)
$diskinfo = Get-WmiObject Win32_LogicalDisk -ComputerName localhost | where {$_.DeviceId -eq 'C:'}
#Here you pull only the freespace value with Gb format (default is byte)
$freespace = $diskinfo.freespace/1Gb
$freespace = [int]$freespace
#here you pull the "limit number" off your file, must be in Gb and only the number is written in the file.
$limit=Get-Content -Path "B:\Dev\filewithsizeingo.txt"
$limit = [int]$limit
if ($freespace -gt $limit) #The free diskspace is greater than the limit
{
Write-Host "Diskfreespace is Above Limit" -f Green
}
elseif ($freespace -lt $limit) #The free diskspace is inferior than the limit
{
Write-Host "Free diskspace below limit" -f Red
#break
#code mail sending
}
Start-Sleep 1
}
Because it's a loop, you can modify the filewithsizeingo.txt without stoping the script, and the script will refresh the free diskspace and limit value at each loop.
In the elseif statement, you can insert a break and code the sending of the email (which I do not know yet), dont forget the break or it will send a mail every second.
I hope it helps, or at least it gave you fresh's ideas (i'm a beginner with powershell, the code CAN be improved).

How to write a powershell script to know disk is basic or dynamic?

I have to check whether a given node contains any dynamic disk or not and get the list of dynamic disk using Power Shell script. I am not supposed to use diskpart command. Any other solutions other than diskpart will be appreciated.
https://social.technet.microsoft.com/Forums/windowsserver/en-US/cd7c0327-3fe9-45fc-a177-5a9927d468f3/does-the-getdisk-funtion-only-return-basic-disks?forum=winserverpowershell
Get-WmiObject Win32_DiskPartition -filter "Type='Logical Disk Manager'" | Select-Object *
you may use also diskpart utility, which is easily scriptable (I worked with it in Python)
the idea is that when you perform diskpart and then list disk,
output will be like:
Disk ### Status Size Free Dyn Gpt
-------- ------------- ------- ------- --- ---
Disk 0 Online 476 GB 0 B *
So you'll see all dynamic disks marked with asterisk under "Dyn"

Fastest way to count ad users in PowerShell?

I've been looking for the fastest way to count the number of ad users in powershell, aswell as the number of enabled and disabled users, but the queries are very long (~100k users, 1-2 min per query) and my powershell ISE usually crashes after one or two requests (it's for a reporting job)
So my question is how can I optimize these queries :
$CountADUsers = (get-aduser –filter * -server $myserver).count.Count
$CountADUsersEnabled = (get-aduser -filter * -server $myserver | where {$_.enabled -eq "True"}).count
$CountADUsersNotEnabled = $CountADUsers - $CountADUsersEnabled
Thanks in advance guys
You don't need to run Get-AdUser twice. You can save it to variable and just filter it:
$allUsers = get-aduser –filter * -server $myserver
$CountADUsers = $allUsers.count
$CountADUsersEnabled = ($allUsers | where {$_.enabled -eq "True"}).count
Also, it won't be helpful in that case, but please remember that using -Filter * and then Where-Object is not very effective as you can just use:
Get-ADUser -Filter {enabled -eq "True"}
Another hint: ISE shouldn't be used for running scripts as it sometimes behave in strange ways (especially when you run out of memory on your machine). You should use powershell.exe instead.
Edit: to improve even more you could try to choose only the attributes you need using
$t = $allusers |select userprincipalname,enabled
And then use Where-Object to filter. For comparison:
Measure-command {($allusers | where {$_.enabled -eq "True"}).count}
took two minutes when
Measure-command {($t | where {$_.enabled -eq "True"}).count}
took two seconds (but selecting takes about 2 mins so the overall time is more or less the same). However, this strongly depends on the scenario. I'll leave it to you so you can find the best solution for your case. Remember, Measure-Command is your very good friend for this!

Powershell Command to determine the Free Space of a Cluster Shared Volumes on a Remote Windows Server

I am looking for a powershell command that will pull the free space of a Cluster Shared Volume as it does not have a logical drive letter on a remote system. The Following is the Command I use on Logical Drives so you can see an example of the output I am Looking for. I am looking for just a numeric value of available megabytes.
Get-WMIObject -computer server -filter "DeviceID = 'C:'" Win32_LogicalDisk |
ForEach-Object {[math]::truncate($_.freespace / 1MB)}
Thanks in advance for your Help!
You can't determine the free space of a Cluster Shared Volume (CSV) on a per-host basis. CSVs are cluster-shared resources, so you need to use cluster tools for obtaining information about them:
$cluster = 'Cluster Name'
$volume = 'Cluster Shared Volume Name'
Import-Module failoverclusters
Get-ClusterSharedVolume -Name $volume -Cluster $cluster `
| select -Expand SharedVolumeInfo `
| select #{n='FreeSpace';e={($_.Partition.Size - $_.Partition.UsedSpace)/1MB}}

Extract hostnames from Perfmon blg with Powershell

I'm writing a script which will automate the extraction of data from .blg Perfmon logs.
I've worked out the primary Import-Counter commands I will need to use to get the data out, but am trying to parametrise this so that I can do it for each machine in the log file (without having to open the log up in Perfmon, which can take 15 minutes or sometimes more, and is the reason I'm writing this script), and find out what each hostname is.
The script I have does the job, but it still takes a minute to return the data I want, and I wondered if there was a simpler way to do this, as I'm not too familiar with Powershell?
Here's what I have:
$counters = Import-Counter -Path $log_path$logfile -ListSet * | Select-Object paths -ExpandProperty paths
$svrs = #()
# for each line in the list of counters, extract the name of the server and add it to the array
foreach ($line in $counters) {
$svrs += $line.split("\")[2]
}
# remove duplicates and sort the list of servers
$sorted_svrs = $svrs | sort -unique
foreach ($svr in $sorted_svrs) {
Write-Host $svr
}
I'm just printing the names for the moment, but they'll go into an array in the proper script, and then I'll run my Import-Counter block with each of these hosts parametrised in.
Just wondered if there was a better way of doing this?
$sorted_svrs=Import-Counter "$log_path$logfile" -Counter "\\*\physicaldisk(_total)\% disk time" | %{$_.countersamples.path.split("\")[2]} | sort -Unique

Resources