This commit is contained in:
Zack Meier
2026-04-15 15:42:41 -05:00
parent 74edcc4d9a
commit 03dba08135
146 changed files with 9119 additions and 1 deletions
@@ -0,0 +1,484 @@
function New-ITDVMwareVMSnapshotTaskV3Prd {
[CmdletBinding()]
Param (
[int]
$Id,
[PSCredential]
$SharePointCredential
)
begin {
$UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeRestMethodParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
}
If ($SharePointCredential) {
$InvokeRestMethodParams += @{Credential = $SharePointCredential }
}
Else {
$InvokeRestMethodParams += @{UseDefaultCredentials = $true }
}
$RequestDigest = Invoke-RestMethod @InvokeRestMethodParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeRestMethodParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
}
If ($SharePointCredential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
$List = Invoke-RestMethod @InvokeRestMethodParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000' + '&$select=ID,Title,DateTime,Duration,Author/Name,Author/Title,Author/EMail,NotifyEmail&$expand=Author/Id'
$InvokeRestMethodParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
}
If ($SharePointCredential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
$ListItems = ((Invoke-RestMethod @InvokeRestMethodParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
}
process {
$SPListItem = $ListItems | Where-object Id -eq $Id
$VMName = $SPListItem.Title
$SnapTime = [DateTime]$SPListItem.DateTime
$NotifyEmail = $SPListItem.Author.Email
If ($SPListItem.NotifyEmail) { $NotifyEmail = $NotifyEmail + ';' + $SPListItem.NotifyEmail }
try {
$SnapName = "AutoSnap_" + $SPListItem.ID
$SnapExpireDateTime = $SnapTime.AddDays($SPListItem.Duration)
If ($SnapExpireDateTime.DayOfWeek -eq "Saturday" -or $SnapExpireDateTime.DayOfWeek -eq "Sunday") {
$SnapExpireDateTime = $SnapExpireDateTime.AddDays(2)
}
$SnapDeleteDateTime = $SnapExpireDateTime.AddDays(2)
$SnapDescription = [PSCustomObject]@{
Number = $Id;
AutoExpire = $SnapExpireDateTime.ToLocalTime();
AutoDelete = $SnapDeleteDateTime.ToLocalTime();
} | ConvertTo-Json
$snapMemory = $false
$snapQuiesce = $false
Write-Warning $VMName
Write-Warning $SnapName
Write-Warning ("SharePoint: " + $SnapTime)
If ($SnapTime -lt (Get-Date)) {
$SnapTime = (Get-Date).AddSeconds(30)
}
Write-Warning ("PowerShell: " + $SnapTime)
$VM = Get-VM -Name $VMName | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
If (@($VM).count -eq 2) { $VM = Get-VM -Name $VMName -Server ($global:DefaultVIServers | Sort-Object Name | Select-Object -First 1).Name }
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
# prep for SharePoint Record status update
$UrlItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($Id)"
$InvokeRestMethodParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
#Credential = $SharePointCredential
}
If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
# actual creation of vCenter task
$si = Get-View ServiceInstance -Server $VIServer
$scheduledTaskManager = Get-View $si.Content.ScheduledTaskManager -Server $VIServer
$spec = New-Object VMware.Vim.ScheduledTaskSpec
$spec.Name = $SnapName, $VMname -join '_'
$spec.Description = "$SnapDescription"
$spec.Enabled = $true
$spec.Notification = $NotifyEmail
$spec.Scheduler = New-Object VMware.Vim.OnceTaskScheduler
$spec.Scheduler.runat = $SnapTime
$spec.Action = New-Object VMware.Vim.MethodAction
$spec.Action.Name = "CreateSnapshot_Task"
@($SnapName, $SnapDescription, $SnapMemory, $SnapQuiesce) | ForEach-Object {
$arg = New-Object VMware.Vim.MethodActionArgument
$arg.Value = $_
$spec.Action.Argument += $arg
}
$scheduledTaskManager.CreateObjectScheduledTask($vm.ExtensionData.MoRef, $spec)
Start-Sleep -Seconds 3
}
catch {
write-error "vCenter Snapshot Scheduled Task Creation failed default message"
write-error $error[1]
Send-MailMessage -From "vmware@nd.gov" -To "zmeier@nd.gov" -Subject "VMware-Snapshot Schedule Failed Default Message - $SnapName" -Body "$SnapName`n$SnapDescription" -SmtpServer apprelay1.nd.gov
$Status = "Errored"
exit
}
# update SharePoint record status
If ($Status -ne "Errored") { $Status = "Scheduled" }
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
Status = $Status;
}
$body = $SetRecord | ConvertTo-Json
$InvokeRestMethodParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
}
If ($SharePointCredential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
Invoke-RestMethod @InvokeRestMethodParams
$postParams = [PSCustomObject]@{
AutomationName = "Infra-VMware";
Action = 'Provisioning';
Units = 5;
Platform = 'PowerShell-VMware-SnapshotNew';
}
Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json)
}
end {
}
}
function Update-ITDVMwareVMSnapshotTaskStatusV3Prd {
[CmdletBinding()]
Param (
[int]
$Id,
[PSCredential]
$SharePointCredential
)
If ($SharePointCredential) {
$SnapshotList = Get-ITDVMwareSharePointSnapshotRequestList -Credential $SharePointCredential
}
Else {
$SnapshotList = Get-ITDVMwareSharePointSnapshotRequestList
}
If($Id)
{
$ListToUpdate = $SnapshotList | Where-Object { $_.Status -eq "Scheduled" -and $_.Id -eq $Id}
}
Else
{
$ListToUpdate = $SnapshotList | Where-Object { $_.Status -eq "Scheduled" } | Sort-Object DateTime
}
ForEach ($SPRecord in $ListToUpdate) {
$VM = $null
$Taken = $null
$VMName = $null
$Duration = $null
$Id = $null
$VMSnapshot = $null
$Task = $null
If ( (($SPRecord.DateTime) -as [datetime]).ToLocalTime() -lt (Get-Date) ) {
# If datetime has passed
$VMName = $SPRecord.Title
$VM = Get-VM -Name $VMName | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
$Duration = $SPRecord.Duration
$Id = $SPRecord.Id
switch ($Duration) {
{ $Duration -ge 1 -and $Duration -le 7 } {
Write-Verbose "Duration = Snapshot"
#$VMSnapshots = $VM | Get-Snapshot | Where-Object Description -like "AutoSnap_$Id*"
$VMSnapshots = $VM | Get-Snapshot | Where-Object {($_.Description | ConvertFrom-Json).Number -eq $Id}
If (@($VMSnapshots).count -eq 1) {
Write-Verbose "Exactly one snapshot match found"
$Taken = $true
$VMSnapshot = $VMSnapshots
#$Task = ((Get-View ((Get-View ScheduledTaskManager).ScheduledTask)).info | where-object Description -like "AutoSnap_$Id*")
$Task = (Get-View (Get-View ScheduledTaskManager).ScheduledTask).info | Where-Object Name -like ("AutoSnap_$id" + '_' + $VMName)
}
else {
if (@($VMSnapshots).count -gt 1) {
Write-Error "More than one snapshot match found, abort"
Exit
}
else {
$Taken = $false
Write-Verbose "Snapshot Id #$Id match not found on $VMName"
Write-Error "Snapshot $Id for $VMName not found."
}
}
}
{ $Duration -ge 8 } {
Write-Verbose "Duration = Clone"
$VMClones = Get-VM | Where-Object Name -eq ($VMName + "_AutoClone_" + $Id)
If (@($VMClones).count -eq 1) {
Write-Verbose "Exactly one clone match found"
$Taken = $true
$VMClone = $VMClones
#$Task = ((Get-View ((Get-View ScheduledTaskManager).ScheduledTask)).info | where-object Name -like "AutoClone_$Id*")
$Task = (Get-View (Get-View ScheduledTaskManager).ScheduledTask).info | Where-Object Name -like ("AutoClone_$id" + '_' + $VMName)
############################## REVIEW
}
else {
if (@($VMClones).count -gt 1) {
Write-Error "More than one VM clone match found, abort"
Exit
}
else {
$Taken = $false
Write-Verbose "Clone Id #$Id match not found for $VMName"
Write-Error "Clone $Id for $VMName not found."
}
}
}
Default {
Write-Error "Duration less than zero."
}
}
Write-Verbose "Updating SharePoint fields named Status and SnapshotTaken"
$UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeRestMethodParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
}
If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
$RequestDigest = Invoke-RestMethod @InvokeRestMethodParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeRestMethodParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
}
If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
$List = Invoke-RestMethod @InvokeRestMethodParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000'
$InvokeRestMethodParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
}
If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
$ListItems = ((Invoke-RestMethod @InvokeRestMethodParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
$UrlItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($Id)"
$InvokeRestMethodParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
}
If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
#Status = 'Taken';
Status = If ($Taken -eq $true) { 'Taken' } Else { 'Errored' };
SnapshotTaken = $Task.PrevRunTime.ToLocalTime();
AutoExpire = ($Task.Description | ConvertFrom-Json).AutoExpire
AutoDelete = ($Task.Description | ConvertFrom-Json).AutoDelete
}
$body = $SetRecord | ConvertTo-Json
$InvokeRestMethodParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
}
If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } }
Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } }
Invoke-RestMethod @InvokeRestMethodParams
}
}
$postParams = [PSCustomObject]@{
AutomationName = "Infra-VMware";
Action = 'Provisioning';
Units = 1;
Platform = 'PowerShell-VMware-SnapshotUpdateStatus';
}
Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json)
}
function New-ITDVMwareVMCloneTaskV3Prd {
[CmdletBinding()]
Param
(
[Parameter(Mandatory = $true)]
[int[]]
$Id,
[VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.VmfsDatastoreImpl]
$Destination,
[PSCredential]
$SharePointCredential,
[PSCredential]
$vCenterCredential
)
begin {
$ConnectITDvCenterParams = @{ }
If ($vCenterCredential) { $ConnectITDvCenterParams += @{Credential = $vCenterCredential } }
Connect-ITDvCenter @ConnectITDvCenterParams
$GetITDVMwareSharePointSnapshotRequestList = @{ }
If ($SharePointCredential) { $GetITDVMwareSharePointSnapshotRequestList += @{Credential = $SharePointCredential } }
$List = Get-ITDVMwareSharePointSnapshotRequestList @GetITDVMwareSharePointSnapshotRequestList
}
process {
ForEach ($i in $ID) {
try {
$Request = $List | where-object ID -eq $i
$VMName = $Request.Title
$Duration = $Request.Duration
$CloneTime = [DateTime]$Request.DateTime.ToLocalTime()
If ($CloneTime -lt (Get-Date)) {
$CloneTime = (Get-Date).AddSeconds(30)
}
$CloneExpireDateTime = $CloneTime.AddDays($Duration)
$CloneDeleteDateTime = $CloneExpireDateTime.AddDays(2)
#$CloneDescription = ("AutoClone_" + $Request.ID + "`r" + "AutoExpire_$CloneExpireDateTime" + "`r" + "AutoDelete_$CloneDeleteDateTime")
$CloneDescription = [PSCustomObject]@{
Number = $Id;
AutoExpire = $CloneExpireDateTime.ToLocalTime();
AutoDelete = $CloneDeleteDateTime.ToLocalTime();
} | ConvertTo-Json
$CloneVMName = ($VMName + "_AutoClone_" + $i)
$VM = Get-VM -Name $VMName | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$Folder = Get-Folder -Name "_Clone Request" -Server $VIServer
$Datastore = $VM | Get-Datastore
$DatastoreCluster = $VM | Get-DatastoreCluster
If (!($Destination)) { $Destination = Get-Datastore -Server $VIServer -Name *TEMPL* }
# If DSCluster, clone to cluster
# doesn't fit go to TEMPL
# doesn't fit, error
# If dedicated lun, clone to TEMPL
# doesn't fit, error
If (($Destination.FreeSpaceGB * 0.90) -lt $VM.UsedSpaceGB) {
# Not enough free space, error
Write-Error ("Not enough free space on " + $Destination.Name)
}
else {
$ma = New-Object VMware.Vim.MethodAction
$ma.Argument = $null
$ma.Name = "CloneVM_Task"
$ar1 = New-Object VMware.Vim.MethodActionArgument
$ar1.Value = $vm.Folder.ExtensionData.MoRef
$ma.Argument += $ar1
$ar2 = New-Object VMware.Vim.MethodActionArgument
$ar2.Value = $CloneVMName
$ma.Argument += $ar2
$ar3 = New-Object VMware.Vim.MethodActionArgument
$vmSpec = New-Object VMware.Vim.VirtualMachineCloneSpec
$vmSpec.Location = New-Object VMware.Vim.VirtualMachineRelocateSpec
#$vmSpec.Location.Datastore = $vm.ExtensionData.Datastore[0]
#$vmSpec.Location.Datastore = (Get-Datastore -Name "*TEMPL*" -Server $VIServer).ExtensionData.MoRef
$vmSpec.Location.Datastore = (Get-Datastore -Name $Destination.Name -Server $VIServer).ExtensionData.MoRef
$vmSpec.Location.Pool = (Get-ResourcePool -VM $VM).ExtensionData.MoRef
$vmSpec.Location.Folder = $Folder.ExtensionData.MoRef
$vmSpec.Config = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmSpec.Template = $false
$vmSpec.PowerOn = $false
$ar3.Value = $vmSpec
$ma.Argument += $ar3
<#
# Run at 21:00 every day
$dTScheduler = New-Object VMware.Vim.DailyTaskScheduler
$dTScheduler.Hour = 14
$dTScheduler.Minute = 39
$dTScheduler.Interval = 1
#>
$dTScheduler = New-Object VMware.Vim.OnceTaskScheduler
$dTScheduler.runat = $CloneTime
$tSpec = New-Object VMware.Vim.ScheduledTaskSpec
$tSpec.Action = $ma
$tSpec.Description = $CloneDescription
$tSpec.Enabled = $TRUE
$tSpec.Name = "AutoClone_" + $Request.ID + "_$VMName"
$tSpec.Notification = $Request.Author.EMail
$tSpec.Scheduler = $dTScheduler
$stMgr = Get-View ScheduledTaskManager -Server $VIServer
$stMgr.CreateScheduledTask($vm.ExtensionData.MoRef, $tSpec)
}
}
catch {
write-error "vCenter Clone Scheduled Task Creation failed"
write-error $error[1]
#Send-MailMessage -From "vmware@nd.gov" -To "zmeier@nd.gov" -Subject "VMware-Snapshot Schedule Failed - $SnapName" -Body "$SnapName`n$SnapDescription" -SmtpServer apprelay1.nd.gov
$Status = "Errored"
exit
}
}
}
end {
}
}
@@ -0,0 +1,34 @@
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[object] $WebhookData
)
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'VRLEq2Yi7yzWW8fpKNCPB5gUcnHfr9sdhXC53y7gWf5BDtHAKpueFYU4L3N9ZxCWy63znqPGh3AJ2bn43uP7GjzfLcgqYLQRkirMXTKqtHssnNGBrew3gxXkr3mZA3NV7DszpR3kjiLgi3FpRPgUWus') {
Write-Verbose "Header has required data"
}
Else {
Write-Error "Header missing required data"
exit;
}
$InputParams = (ConvertFrom-Json -InputObject $WebhookData.RequestBody)
$vCenterCredential = Get-AutomationPSCredential -Name 'VMware Auto'
$SharePointCredential = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite'
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -ParticipateInCeip $false -Confirm:$false
try {
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
New-ITDVMwareVMSnapshotTaskV3Prd -Id $InputParams.ID
Disconnect-VIServer -Server * -Confirm:$false -ErrorAction SilentlyContinue
}
catch {
}
}
Else {
Write-Error "Runbook must be started from webhook"
}