This commit is contained in:
Zack Meier
2026-04-15 15:45:50 -05:00
commit 1d304511b8
613 changed files with 140998 additions and 0 deletions
@@ -0,0 +1,49 @@
trigger:
- main
name: 'ITD.Infra-VMware.Administration'
variables:
major: 2
minor: 0
patch: $(Build.BuildID)
buildVer: $(major).$(minor).$(Build.BuildID)
pool: itdwinautop1
stages:
- stage: Build
jobs:
- job: Build
steps:
- task: PowerShell@2
inputs:
filePath: '$(System.DefaultWorkingDirectory)/Build/build.ps1'
- task: NuGetCommand@2
inputs:
command: 'pack'
packagesToPack: '$(System.DefaultWorkingDirectory)/ITD.Infra-VMware.Administration.nuspec'
versioningScheme: byEnvVar
versionEnvVar: buildVer
buildProperties: 'VERSIONHERE=$(buildVer)'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'NuGetPackage'
publishLocation: 'Container'
- stage: Deploy
jobs:
- job: Deploy
steps:
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'current'
artifactName: 'NuGetPackage'
itemPattern: '**'
targetPath: '$(Pipeline.Workspace)'
- task: NuGetCommand@2
inputs:
command: 'push'
packagesToPush: '$(Pipeline.Workspace)/ITD.Infra-VMware.Administration.$(major).$(minor).$(Build.BuildID).nupkg'
nuGetFeedType: external
publishFeedCredentials: 'ITD_PwshGallery'
@@ -0,0 +1,17 @@
$buildVersion = $env:BUILDVER
$moduleName = 'ITD.Infra-VMware.Administration'
$manifestPath = Join-Path -Path $env:SYSTEM_DEFAULTWORKINGDIRECTORY -ChildPath "$moduleName.psd1"
$modulePath = Join-Path -Path $env:SYSTEM_DEFAULTWORKINGDIRECTORY -ChildPath "$moduleName.psm1"
## Update build version in manifest
$manifestContent = Get-Content -Path $manifestPath -Raw
$manifestContent = $manifestContent -replace '<ModuleVersion>', $buildVersion
## Update functions to export in manifest
Import-Module $modulePath
$funcStrings = (Get-Module ITD.Infra-VMware.Administration).ExportedCommands.Values.Name
$funcStrings = "'$($funcStrings -join "','")'"
$manifestContent = $manifestContent -replace "<FunctionsToExport>", $funcStrings
$manifestContent | Set-Content -Path $manifestPath
@@ -0,0 +1,688 @@
<#
.Synopsis
Changes Portgroup on all NICs on specified VMs
.EXAMPLE
Set-ITDVMwareVMNicPortGroup -Computer itdsrv1.nd.gov -Vlan 1394 -Credential $AdminCred
#>
function Set-ITDVMwareVMNicPortGroup {
[CmdletBinding()]
Param
(
[Parameter(Mandatory = $true)]
[string[]]
$ComputerName,
[Parameter(Mandatory = $true)]
[int]
$Vlan,
[PSCredential]
$Credential
)
Begin {
Connect-ITDvCenter -Credential $Credential
Write-Verbose "Connected to: $global:DefaultVIServers"
If ($global:DefaultVIServers.Count -gt 0) {
Write-Verbose "connected to VI server(s)"
}
Else {
Write-Warning "not connected to any VIservers, stopping script"
break
break
}
$AvailablePortGroup = Get-VirtualPortGroup -WarningAction SilentlyContinue
}
Process {
ForEach ($c in $ComputerName) {
Write-Verbose "[$c]:Start"
$CurrentVM = $null
$CurrentVMs = $null
$Datacenter1 = $null
$Datacenter2 = $null
$DestinationFolder = $null
$CurrentDatacenter = $null
$CurrentVMs = Get-VM -Name $c -ErrorAction SilentlyContinue
If ($CurrentVMs.Count -lt 1) {
Write-Warning "[$c]:VM name not found, please check it and try again ******"
}
Else {
If ($CurrentVMs.Count -gt 2) {
Write-Warning "[$c]:More than two results found, process this VM manually"
}
Else {
If ($CurrentVMs.Count -eq 2) {
Write-Verbose "[$c]:Two results found"
$Datacenter1 = ($CurrentVMs[0] | Get-Datacenter).Name
$Datacenter2 = ($CurrentVMs[1] | Get-Datacenter).Name
Write-Verbose "[$c]:Check for SRM"
If ( ( ($Datacenter1 -eq "Primary Datacenter") -or ($Datacenter2 -eq "Primary Datacenter") ) -and ( ($Datacenter1 -eq "Secondary Datacenter") -or ($Datacenter2 -eq "Secondary Datacenter") ) ) {
Write-Warning "[$c]:One result in both Primary and Secondary Datacenters, assuming SRM and continuing"
If ($Datacenter1 -eq "Primary Datacenter") {
$CurrentVM = $CurrentVMs[0]
}
If ($Datacenter2 -eq "Primary Datacenter") {
$CurrentVM = $CurrentVMs[1]
}
}
Else {
Write-Warning "[$c]:Exactly two results in the same datacenter... Congratulations, you've acheieved the impossible."
break
}
}
Else {
Write-Verbose "[$c]:One match found"
$CurrentVM = $CurrentVMs
}
If ($CurrentVM) {
$CurrentDatacenter = ($CurrentVM | Get-Datacenter).Name
Switch ($CurrentDatacenter) {
"Primary Datacenter" {
$VirtualSwitch = "PDC"
}
"Secondary Datacenter" {
$VirtualSwitch = "SDC"
}
}
$VLANsearch = '_' + $VLAN
$VMVLAN = $AvailablePortGroup | `
Where-Object { $_.Name -Like "*$VLANsearch" -and $_.VirtualSwitch -like "*$VirtualSwitch*" }
$CurrentVM | Get-NetworkAdapter | `
Set-NetworkAdapter -NetworkName $VMVLAN -Confirm:$false -RunAsync
}
}
}
Write-Verbose "[$c]:End Remove"
}
}
End {
}
}
<#
.Synopsis
Creates new distributed virtual port group with name standard
.DESCRIPTION
Long description
.EXAMPLE
New-ITDVMwarePortGroup -CIDR 10.2.60.0/23 -VLAN 1394
.EXAMPLE
New-ITDVMwarePortGroup -CIDR 10.2.60.0/23 -VLAN 1394 -Credential $Credential
#>
function New-ITDVMwarePortGroup {
[CmdletBinding()]
Param
(
[string]
$CIDR,
[int]
$VLAN,
[PSCredential]
$Credential
)
Begin {
Connect-ITDvCenter -Credential $Credential
$BismarckVDSwitch = 'dvSwitch-PDC-Data'
$MandanVDSwitch = 'dvSwitch-SDC-Data'
$IP = $CIDR.split('/')[0]
$Mask = $CIDR.split('/')[1]
$VLANstring = $VLAN.ToString('0000')
}
Process {
#$PGName="dvPG-$CIDR" + "_" + "$VLAN"
$PGName = "dvPG_" + $VLANstring + "_" + $IP + "_" + $Mask
Get-VDSwitch -Name $BismarckVDSwitch | New-VDPortgroup -Name $PGName -NumPorts 1 -VlanId $VLAN
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*" + "_" + $VLAN) } | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -FailoverDetectionPolicy BeaconProbing
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*" + "_" + $VLAN) } | Get-VDPortgroupOverridePolicy | Set-VDPortgroupOverridePolicy -BlockOverrideAllowed $false -ResetPortConfigAtDisconnect $false
Get-VDSwitch -Name $MandanVDSwitch | New-VDPortgroup -Name $PGName -NumPorts 1 -VlanId $VLAN
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*" + "_" + $VLAN) } | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -FailoverDetectionPolicy BeaconProbing
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*" + "_" + $VLAN) } | Get-VDPortgroupOverridePolicy | Set-VDPortgroupOverridePolicy -BlockOverrideAllowed $false -ResetPortConfigAtDisconnect $false
}
End {
}
}
function Find-ITDVMDatastoreClusterMaxAverageDatastoreFreeSpace ($Cluster) {
$MaxDsCFreeSpaceAvgPerDiskGB = $null
$MaxDsCName = $null
$AvailableDsC = Get-DatastoreCluster | Where-Object Name -Like *$Cluster*
$AvailableDsCCount = ($AvailableDsC | Measure-Object).Count
Write-Verbose "Found $AvailableDsCCount datastore clusters matching $Cluster"
ForEach ($d in $AvailableDsC) {
$DsCFreeSpaceInfo = Get-DatastoreCluster -Name $d.Name | Get-Datastore | Select-Object FreeSpaceGB | Measure-Object -Property FreeSpaceGB -Average -Sum
$CurrentDsCFreeSpaceAvgPerDiskGB = $DsCFreeSpaceInfo.Average
# If first in datastore clusters to check
If ($MaxDsCFreeSpaceAvgPerDiskGB -eq $null) {
Write-Verbose "First datastore cluster, default max datastore cluster"
$MaxDsCFreeSpaceAvgPerDiskGB = $CurrentDsCFreeSpaceAvgPerDiskGB
$MaxDsCName = $d.Name
}
# Is current Ds cluster avg free space per datastore is larger than max
If ($CurrentDsCFreeSpaceAvgPerDiskGB -gt $MaxDsCFreeSpaceAvgPerDiskGB) {
Write-Verbose "Current larger than Max"
$MaxDsCFreeSpaceAvgPerDiskGB = $CurrentDsCFreeSpaceAvgPerDiskGB
$MaxDsCName = $d.Name
}
Write-Verbose "CurrentDsCName: $d"
Write-Verbose "CurrentDsCFreeSpaceAvgPerDiskGB = $CurrentDsCFreeSpaceAvgPerDiskGB"
Write-Verbose "MaxDsCFreeSpaceAvgPerDiskGB = $MaxDsCFreeSpaceAvgPerDiskGB"
}
Write-Verbose "Return MaxDsCFreeSpaceName: $MaxDsCName"
return $MaxDsCName
}
<#
.SYNOPSIS
Short description
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
.INPUTS
Inputs to this cmdlet (if any)
.OUTPUTS
Output from this cmdlet (if any)
.NOTES
General notes
.COMPONENT
The component this cmdlet belongs to
.ROLE
The role this cmdlet belongs to
.FUNCTIONALITY
The functionality that best describes this cmdlet
#>
function Get-ITDVMwareSharePointSnapshotRequestList {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
$InvokeWebRequestParams = @{ }
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "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,Status,NotifyEmail&$expand=Author/Id'
$InvokeWebRequestParams += @{
Uri = $URL
Method = "Get"
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
$List = (Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
#$List = (Invoke-WebRequest -Uri $URL -Method Get -UseDefaultCredentials -headers @{ "Accept" = "application/json;odata=verbose" }) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
function Get-ITDVMwareSharePointSnapshotRequestListTst {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
$InvokeWebRequestParams = @{ }
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "https://testshare.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,Status,NotifyEmail&$expand=Author/Id'
$InvokeWebRequestParams += @{
Uri = $URL
Method = "Get"
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
$List = (Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
#$List = (Invoke-WebRequest -Uri $URL -Method Get -UseDefaultCredentials -headers @{ "Accept" = "application/json;odata=verbose" }) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
<#
.SYNOPSIS
Runs Unmap cmds from VMhost to cleanup dirty data blocks on A9K storage
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
.INPUTS
Inputs to this cmdlet (if any)
.OUTPUTS
Output from this cmdlet (if any)
.NOTES
General notes
.COMPONENT
The component this cmdlet belongs to
.ROLE
The role this cmdlet belongs to
.FUNCTIONALITY
The functionality that best describes this cmdlet
#>
function Start-ITDVMwareDatastoreUnmap {
[CmdletBinding()]
param
(
[string[]]
$Datastore,
[PSCredential]
$Credential
)
begin {
$ConnectITDvCenterParams = @{ }
If ($Credential) { $ConnectITDvCenterParams += @{Credential = $Credential } }
Connect-ITDvCenter @ConnectITDvCenterParams
}
process {
$Clusters = Get-Datacenter Secondary*, Primary* | Get-Cluster
ForEach ($Cluster in $Clusters) {
$esxcli = $null
$Datastores = $null
$VMHost = $null
$Datastores = $Cluster | Get-Datastore | Where-Object { $_.Name -notlike "*TEMPL*" -and $_.Name -like "*$Datastore*" -and $_.Name -like "*A9K*" } | Sort-Object Name
$VMHost = $Cluster | Get-VMHost | Where-Object ConnectionState -EQ "Connected" | Select-Object -First 1
$esxcli = Get-EsxCli -VMHost $VMHost
ForEach ($ds in $Datastores) {
$TimeStamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Write-Warning "[$ds]:Start $TimeStamp on $VMHost"
$esxcli.storage.vmfs.unmap($null, $ds, $null)
}
}
}
end {
}
}
<#
.SYNOPSIS
Short description
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
.INPUTS
Inputs to this cmdlet (if any)
.OUTPUTS
Output from this cmdlet (if any)
.NOTES
General notes
.COMPONENT
The component this cmdlet belongs to
.ROLE
The role this cmdlet belongs to
.FUNCTIONALITY
The functionality that best describes this cmdlet
#>
function Remove-ITDVMwareDatastoreStep1 {
[CmdletBinding()]
Param
(
[int[]]
$LunId,
[PSCredential]
$vCenterCredential,
[PSCredential]
$SharePointCredential
)
begin {
$ConnectITDvCenterParams = @{ }
If ($vCenterCredential) { $ConnectITDvCenterParams += @{Credential = $vCenterCredential } }
Connect-ITDvCenter @ConnectITDvCenterParams
$VMwareList = Get-Datastore
$GetITDVMwareSharePointDatastoreRecordParams = @{ }
If ($SharePointCredential) { $GetITDVMwareSharePointDatastoreRecordParams = @{Credential = $SharePointCredential } }
#$SharePointList = Get-ITDVMwareSharePointDatastoreRecord | select *,@{n='Name';e={$_.Title}}
$SharePointList = Get-ITDVMwareSharePointDatastoreRecord @GetITDVMwareSharePointDatastoreRecordParams | Select-Object *, @{n = 'Name'; e = { $_.Title } }
}
process {
$DatastoreRemovalSuccess = @()
$DatastoreRemovalFailure = @()
ForEach ($Id in $LunId) {
$DatastoreID = $null
$Datastore = $null
$Datastores = Get-Datastore | Where-Object Name -Like ("*_" + $Id + "_*")
ForEach ($Datastore in $Datastores) {
$SharePointRecord = $null
$DatastoreHosts = $Datastore | Get-VMHost
$VMHostCanonicalName = (Get-ScsiLun -VmHost ($DatastoreHosts | Select-Object -First 1) | Where-Object RuntimeName -Like "*L$Id*").CanonicalName
$SharePointRecord = ($SharePointList | Where-Object Title -EQ $Datastore.Name)
If ($SharePointRecord.ExtentName -eq $VMHostCanonicalName) {
Write-Verbose ($Datastore.Name + " *** " + $VMHostCanonicalName + " *** CanonicalName accurate in SharePoint, continuing with unmount")
try {
Get-Datastore $Datastore #| Unmount-Datastore
$DatastoreHosts | Select-Object -First 1 | Remove-Datastore $Datastore -Confirm:$false -RunAsync
$DatastoreRemovalSuccess += $Datastore.Name
}
catch {
$DatastoreRemovalFailure += $Datastore.Name
}
}
else {
Write-Error ($Datastore.Name + " *** " + " *** CanonicalName mismatch with SharePoint Record")
}
}
}
}
end {
}
}
<#
.SYNOPSIS
Short description
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
.INPUTS
Inputs to this cmdlet (if any)
.OUTPUTS
Output from this cmdlet (if any)
.NOTES
General notes
.COMPONENT
The component this cmdlet belongs to
.ROLE
The role this cmdlet belongs to
.FUNCTIONALITY
The functionality that best describes this cmdlet
#>
function Remove-ITDVMwareDatastoreStep3 {
[CmdletBinding()]
Param
(
[int[]]
$LunId,
[PSCredential]
$vCenterCredential,
[PSCredential]
$SharePointCredential
)
begin {
$ConnectITDvCenterParams = @{ }
If ($vCenterCredential) { $ConnectITDvCenterParams += @{Credential = $vCenterCredential } }
Connect-ITDvCenter @ConnectITDvCenterParams
$VMwareList = Get-Datastore
$GetITDVMwareSharePointDatastoreRecordParams = @{ }
If ($SharePointCredential) { $GetITDVMwareSharePointDatastoreRecordParams = @{Credential = $SharePointCredential } }
#$SharePointList = Get-ITDVMwareSharePointDatastoreRecord | select *,@{n='Name';e={$_.Title}}
$SharePointList = Get-ITDVMwareSharePointDatastoreRecord @GetITDVMwareSharePointDatastoreRecordParams | Select-Object *, @{n = 'Name'; e = { $_.Title } }
}
process {
$DeviceUidToRemove = @()
ForEach ($Id in $LunId) {
$DeviceUidToRemove += $SharePointList | Where-Object Name -Like "*$Id*" | Select-Object *, @{n = 'HostCluster'; e = { $_.Name.split('_')[0] -replace "VM" } }
}
$DeviceUidToRemove = $DeviceUidToRemove | Sort-Object HostCluster
If (@($DeviceUidToRemove).count -ne @($LunId).count) { Write-Error "LunId and datastore search count mismatch, verify SharePoint manually before continuing" }
else {
#confirmation prompt
Write-Warning "The following SAN volumes will be detached from the VMware hosts. Please confirm this list is correct:"
$DeviceUidToRemove | ForEach-Object { Write-Warning ($_.Name + " *** " + $_.ExtentName) }
Pause
$HostClusters = $DeviceUidToRemove | Group-Object HostCluster
ForEach ($HostCluster in $HostClusters) {
$VMHosts = Get-Cluster $HostCluster.Name | Get-VMHost
ForEach ($DeviceUid in @($DeviceUidToRemove | Where-Object HostCluster -EQ $HostCluster)) {
$removeUID = Get-ScsiLun -VmHost $VMHosts | Where-Object CanonicalName -EQ $DeviceUid | Select-Object -First 1
If ($removeUID) {
foreach ($VMHost in $VMHosts) {
$esxcli = Get-EsxCli -VMHost $VMHost -V2
#$esxcli.storage.core.device.detached.remove.invoke(@{device = $removeUID})
}
}
}
Get-VMHostStorage -VMHost $VMhosts -RescanAllHba -RescanVmfs
}
}
}
end {
}
}
function Get-ITDVMwareAlarmState {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true,
ValueFromPipeline = $true,
ParameterSetName = 'Entity'
)]
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]
$Entity,
[switch]
$Recurse = $false
)
begin {
}
process {
$Entity = Get-Inventory -Id $Entity.Id
if ($Recurse) {
$VMObjects = @($Entity)
$VMObjects += Get-Inventory -Location $Entity
}
else {
$VMObjects = $Entity
}
$VMObjects | Select-Object Name, `
@{N = "Type"; E = { $_.GetType().Name.Replace("Impl", "").Replace("Wrapper", "") } }, `
@{N = "Alarm actions enabled"; E = { $_.ExtensionData.alarmActionsEnabled } }
}
end {
}
}
function Set-ITDVMwareAlarmState {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]
$Entity,
[switch]
$Enabled,
[switch]
$Recurse
)
begin {
$alarmMgr = Get-View AlarmManager
}
process {
if ($Recurse) {
$VMObjects = @($Entity)
$VMObjects += Get-Inventory -Location $Entity
}
else {
$VMObjects = $Entity
}
$VMObjects | ForEach-Object {
$alarmMgr.EnableAlarmActions($_.Extensiondata.MoRef, $Enabled)
}
}
end {
}
}
function Expand-ITDVMwareDatastore {
param (
[string[]]
$LunId
)
$HostsToRescan = @()
ForEach ($Id in $LunId) {
$Datastore = Get-Datastore "*$Id*"
$HostSystem = Get-View -Id ($Datastore.ExtensionData.Host | Select-Object -First 1 | Select-Object -ExpandProperty Key)
$DatastoreSystem = Get-View -Id $HostSystem.ConfigManager.DatastoreSystem
$ExpandOptions = $DatastoreSystem.QueryVmfsDatastoreExpandOptions($Datastore.ExtensionData.MoRef)
$DatastoreSystem.ExpandVmfsDatastore($Datastore.ExtensionData.MoRef, $ExpandOptions.spec)
$HostsToRescan += $Datastore | Get-VMHost | Sort-Object Name
}
}
function New-ITDVMwareHostScratchFolder {
[CmdletBinding()]
param (
[ValidateSet("Bismarck", "Mandan")]
[string]
$Site,
[string]
$VMHost
)
Begin {
}
Process {
switch ($Site) {
"Bismarck" {
$vCenter = "itdvmvc1.nd.gov@443"
$Datacenter = "Primary Datacenter"
$Datastore = "VMALL1_006_FS92_SCRATCH"
}
"Mandan" {
$vCenter = "itdvmvc2.nd.gov@443"
$Datacenter = "Secondary Datacenter"
$Datastore = "VMALL2_007_FS92_SCRATCH"
}
}
New-Item -Path "vmstores:\$vCenter\$Datacenter\$Datastore\scratch" -Name $VMHost -ItemType Directory
}
End {
}
}
function Set-ITDVMwareHostMaintenance {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string[]]
$Name,
[ValidateSet("Enter", "Exit")]
[string]
$Status
)
Begin {
}
Process {
ForEach ($n in $Name) {
$VMHost = $null
$VMHost = Get-VMHost $n
$alarmMgr = Get-View AlarmManager -Server $VIServer
switch ($Status) {
"Enter" {
$VMHost | Set-VMHost -State "Maintenance" -RunAsync
$ViServer = $VMHost.Uid.split('@')[1].split(':')[0]
$alarmMgr.EnableAlarmActions($VMHost.ExtensionData.MoRef, $false)
}
"Exit" {
$VMHost | Set-VMHost -State "Connected" -RunAsync
$ViServer = $VMHost.Uid.split('@')[1].split(':')[0]
$alarmMgr.EnableAlarmActions($VMHost.ExtensionData.MoRef, $true)
}
}
}
Get-VMHost $Name | Select-Object Name, ConnectionState, @{n = 'Alarms'; e = { $_.ExtensionData.AlarmActionsEnabled } }
}
End {
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>ITD.Infra-VMware.Administration</id>
<version>$VERSIONHERE$</version>
<authors>Zack Meier / Don Lange</authors>
<description>Functions for VMware administration</description>
</metadata>
</package>
@@ -0,0 +1,10 @@
@{
RootModule = 'ITD.Infra-VMware.Administration.psm1'
ModuleVersion = '<ModuleVersion>'
GUID = 'b940f358-3867-4785-81d2-4bab53872613'
Author = 'Zack Meier / Don Lange '
CompanyName = 'State of North Dakota'
PowerShellVersion = '5.1'
CompatiblePSEditions = 'Desktop','Core'
FunctionsToExport = @(<FunctionsToExport>)
}
@@ -0,0 +1,23 @@
#Get public and private function definition files.
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue )
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue )
#Dot source the files
Foreach($import in @($Public + $Private))
{
Try
{
. $import.fullname
}
Catch
{
Write-Error -Message "Failed to import function $($import.fullname): $_"
}
}
# Here I might...
# Read in or create an initial config file and variable
# Export Public functions ($Public.BaseName) for WIP modules
# Set variables visible to the module and its functions only
Export-ModuleMember -Function $Public.Basename
@@ -0,0 +1,36 @@
<#
.Synopsis
Connects to ITD's vCenter servers
.DESCRIPTION
Connects to ITD's vCenter servers
.EXAMPLE
Connect-ITDvCenter -Credential $PSCredential
#>
function Connect-ITDvCenter {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
Begin {
Import-Module VMware.VimAutomation.Core
$VIServers = "itdvmvc1.nd.gov", "itdvmvc2.nd.gov"
}
Process {
If ($Global:DefaultVIServers) {
Write-Verbose "VIServers already connected"
}
Else {
If ($Credential) {
Connect-VIServer -Server $VIServers -Credential $Credential | Out-Null
}
Else {
Connect-VIServer -Server $VIServers | Out-Null
}
}
}
End {
}
}
@@ -0,0 +1,57 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Disable-ITDVMwareVMHostFeature {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string[]]
$Name,
[switch]
$LockdownMode,
[switch]
$SSH,
[switch]
$AlarmActions
)
Begin {
}
Process {
$VMHosts = Get-VMHost -Name $Name
ForEach ($VMHost in $VMHosts) {
If ($LockdownMode) {
($VMHost | Get-View).ExitLockdownMode()
}
If ($SSH) {
Get-VMHostService -VMHost $VMHost | Where-Object { $_.key -eq 'TSM-SSH' } | Stop-VMHostService -Confirm:$false | Select-Object VMHost, Key, Label, Running
}
If ($AlarmActions) {
$VIServer = $VMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $VMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($VMHost.ExtensionData.MoRef, $false)
}
}
}
}
End {
}
}
@@ -0,0 +1,23 @@
<#
.Synopsis
Disconnects from ITD's vCenter servers
.DESCRIPTION
Disconnects from ITD's vCenter servers
.EXAMPLE
Disconnect-ITDvCenter
#>
function Disconnect-ITDvCenter {
[CmdletBinding()]
Param
(
)
Begin {
$VIServers = "itdvmvc1.nd.gov", "itdvmvc2.nd.gov"
}
Process {
Disconnect-VIServer -Server $VIServers -Confirm:$false
}
End {
}
}
@@ -0,0 +1,57 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Enable-ITDVMwareVMHostFeature {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string[]]
$Name,
[switch]
$LockdownMode,
[switch]
$AlarmActions,
[switch]
$SSH
)
Begin {
}
Process {
$VMHosts = Get-VMHost -Name $Name
ForEach ($VMHost in $VMHosts) {
If ($LockdownMode) {
($VMHost | Get-View).EnterLockdownMode()
}
If ($SSH) {
Get-VMHostService -VMHost $VMHost | Where-Object { $_.key -eq 'TSM-SSH' } | Start-VMHostService -Confirm:$false | Select-Object VMHost, Key, Label, Running
}
If ($AlarmActions) {
$VIServer = $VMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $VMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false) {
$alarmMgr.EnableAlarmActions($VMHost.ExtensionData.MoRef, $true)
}
}
}
}
End {
}
}
@@ -0,0 +1,33 @@
$PowerBi = Import-Csv -Path D:\Downloads\serverinventory20251002.csv
$SRM = Import-Csv -Path D:\Downloads\itdvmvc1.nd.gov-itdvmvc2.nd.gov-20251002-102657.csv
$VMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -eq "placeholderVm" }
$Result = [System.Collections.ArrayList]@()
foreach ($pbi in $PowerBi) {
Write-Verbose -Message ($pbi.'Host Name') -Verbose
$obj = $null
$obj = [PSCustomObject]@{
PowerBi = $pbi.'Host Name'
Placeholder = $VMs | Where-Object Name -EQ $pbi.'Host Name' | Select-Object -ExpandProperty Name -First 1;
SRM = $SRM | Where-Object "Virtual Machine" -EQ $pbi.'Host Name' | Select-Object -ExpandProperty "Virtual Machine"
CMDB = ((Get-ITDServiceNowRecord -Table cmdb_ci_server -Filter ("name=" + $pbi.'Host Name'.split('.')[0])).name.display_value)
}
$null = $Result.Add($obj)
}
foreach ($VM in $VMs) {
if ($Result | Where-Object Placeholder -EQ $VM.Name) {
#do nothing
}
else {
Write-Verbose -Message ($VM.Name) -Verbose
$obj = [PSCustomObject]@{
PowerBi = $PowerBi | Where-Object 'Host Name' -EQ $pbi.'Host Name'
Placeholder = $VM.Name;
SRM = $SRM | Where-Object "Virtual Machine" -EQ $pbi.'Host Name'
CMDB = ((Get-ITDServiceNowRecord -Table cmdb_ci_server -Filter ("name=" + $pbi.'Host Name'.split('.')[0])).name.display_value);
}
$null = $Result.Add($obj)
}
}
@@ -0,0 +1,58 @@
<#
.SYNOPSIS
Usage report for VMware datastores.
.DESCRIPTION
Usage report for VMware datastores.
.NOTES
Requires VMware PowerCLI module.
Requires connection to vCenter.
.EXAMPLE
Get-ITDVMwareDatastoreReport
Retrieves a report of all datastores in the vCenter.
.EXAMPLE
Get-ITDVMwareDatastoreReport -Name "*78*"
Retrieves a report of all datastores in the vCenter that match the name pattern "*78*".
.PARAMETER Name
The name of the datastore to retrieve. If not specified, all datastores will be returned.
Supports wildcards.
#>
function Get-ITDVMwareDatastoreReport {
[CmdletBinding()]
param (
[string]
$Name
)
begin {
}
process {
if ($PSBoundParameters.ContainsKey('Name')) {
$AllDatastores = Get-Datastore -Name $Name
}
else {
$AllDatastores = Get-Datastore
}
foreach ($Datastore in $AllDatastores) {
$FreeSpaceGB = $Datastore.FreeSpaceGB
$CapacityGB = $Datastore.CapacityGB
$UsedSpaceGB = $CapacityGB - $FreeSpaceGB
$obj = [PSCustomObject]@{
Name = $Datastore.Name;
Datacenter = $Datastore.Datacenter.Name
FreeSpaceGB = $FreeSpaceGB;
UsedSpaceGB = ($CapacityGB - $FreeSpaceGB);
CapacityGB = $CapacityGB;
FreePercent = [math]::round($Datastore.FreeSpaceGB / $Datastore.CapacityGB * 100, 2);
}
#$null = $Result.Add($obj)
Write-Output $obj
}
}
end {
}
}
@@ -0,0 +1,73 @@
# servicenow cmdb ci dr protection
# vcenter placeholder
$AllVMwareVMs = Get-Datacenter | Where-Object {$_.Name -like "*Primary*" -or $_.Name -like "*Secondary*" -or $_.Name -like "*DCN*"} | Get-VM | Where-Object { $_.Name -notlike "vCLS*" } | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Sort-Object Name
$AllVMwarePlaceholders = $AllVMwareVMs | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -eq "placeholderVm" }
$AllCmdbCi = Get-ITDServiceNowRecord -Table cmdb_ci_server -Filter "operational_status!=6^u_nd_dr_protectionLIKEVMware" -IncludeTotalCount | Select-Object @{n = 'CiName'; e = { $_.name.display_value } }, @{n = 'CiFqdn'; e = { $_.fqdn.display_value } }, @{n = 'CiOpStatus'; e = { $_.operational_status.display_value } }, @{n = 'DRProtection'; e = { $_.u_nd_dr_protection.display_value } } | Sort-Object CiName
$ArrayList = [System.Collections.ArrayList]@()
# check for placeholder
ForEach ($Ci in $AllCmdbCi) {
$PlaceholderBool = $null
$VMBool = $null
If($AllVMwareVMs | Where-Object { $_.Name -eq $Ci.CiFqdn }) {
$VMBool = $true
}
else {
$VMBool = $false
}
If ($AllVMwarePlaceholders | Where-Object { $_.Name -eq $Ci.CiFqdn }) {
$PlaceholderBool = $true
}
else {
$PlaceholderBool = $false
}
$obj = [PSCustomObject]@{
CiName = $Ci.CiName
CiFqdn = $Ci.CiFqdn
CiOpStatus = $Ci.CiOpStatus
DRProtection = $Ci.DRProtection
VMExists = $VMBool
Placeholder = $PlaceholderBool
}
$null = $ArrayList.Add($obj)
}
# verify no extra entries in vm list / confirm all vms have cmdb entries
ForEach ($VM in $AllVMwareVMs) {
If (-not ($ArrayList | Where-Object { $_.CiFqdn -eq $VM.Name })) {
#Write-Host "VM $($VM.Name) does not have a corresponding CMDB entry." -ForegroundColor Red
$obj = [PSCustomObject]@{
CiName = $null
CiFqdn = $null
CiOpStatus = $null
DRProtection = $null
VMExists = $VM.Name
PlaceholderExists = $null
}
$null = $ArrayList.Add($obj)
}
}
# verify no extra entries in placeholder list / confirm all placeholders have cmdb entries
ForEach ($Placeholder in $AllVMwarePlaceholders) {
If (-not ($ArrayList | Where-Object { $_.CiFqdn -eq $Placeholder.Name })) {
#Write-Host "Placeholder VM $($Placeholder.Name) does not have a corresponding CMDB entry." -ForegroundColor Red
$obj = [PSCustomObject]@{
CiName = $null
CiFqdn = $Placeholder.Name
CiOpStatus = $null
DRProtection = $null
VMExists = $null
PlaceholderExists = $true
}
$null = $ArrayList.Add($obj)
}
}
$ArrayList | Sort-Object CiFqdn | Format-Table -AutoSize
@@ -0,0 +1,42 @@
<#
.SYNOPSIS
Short description
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
.INPUTS
Inputs to this cmdlet (if any)
.OUTPUTS
Output from this cmdlet (if any)
.NOTES
General notes
.COMPONENT
The component this cmdlet belongs to
.ROLE
The role this cmdlet belongs to
.FUNCTIONALITY
The functionality that best describes this cmdlet
#>
function Get-ITDVMwareVMHAEventList {
[CmdletBinding()]
Param
(
)
begin {
}
process {
$Date = Get-Date
$HAVMrestartold = 5
Get-VIEvent -MaxSamples 100000 -Start ($Date).AddDays(-$HAVMrestartold) -type warning | Where-Object { $_.FullFormattedMessage -match "restarted" } | Select-Object CreatedTime, ObjectName, FullFormattedMessage | Sort-Object CreatedTime -Descending
}
end {
}
}
@@ -0,0 +1,61 @@
<#
.SYNOPSIS
Retrieves HBA (Host Bus Adapter) device information, including WWN (World Wide Name) and WWP (World Wide Port Name), for specified VMware ESXi hosts.
.DESCRIPTION
This function connects to one or more VMware ESXi hosts and gathers detailed information about their HBA devices. The information collected includes the device name, WWN, WWP, and other relevant properties. This is useful for inventory, troubleshooting, or auditing storage connectivity in a VMware environment.
.PARAMETER VMHost
Specifies the ESXi host(s) from which to retrieve HBA information. Accepts one or more host names or objects.
.EXAMPLE
Get-ITDVMwareVMHostHBA -VMHost "esxi01.domain.local"
Retrieves HBA information from the specified ESXi host.
.EXAMPLE
Get-ITDVMwareVMHostHBA
Retrieves HBA information from all connected ESXi hosts.
#>
function Get-ITDVMwareVMHostHBA {
[CmdletBinding()]
param (
[string]
$VMHostName
)
begin {
}
process {
If ($PSBoundParameters.ContainsKey('VMHostName')) {
$AllVMHosts = Get-VMHost -Name $VMHostName
}
Else {
$AllVMHosts = Get-VMHost
}
ForEach ($VMHost in $AllVMHosts) {
$HBAs = $null
$HBAs = Get-VMHostHba -VMHost $VMHost -Type FibreChannel
ForEach ($HBA in $HBAs) {
$wwn = "{0:X}" -f $HBA.NodeWorldWideName
$wwp = "{0:X}" -f $HBA.PortWorldWideName
$obj = [PSCustomObject]@{
'VMHostName' = $VMHost.Name;
'Device' = $HBA.Device;
'Model' = $HBA.Model;
'Status' = $HBA.Status;
'NodeWorldWideName' = (0..7 | ForEach-Object { $wwn.Substring($_ * 2, 2) }) -join ':'
'PortWorldWideName' = (0..7 | ForEach-Object { $wwp.Substring($_ * 2, 2) }) -join ':'
}
Write-Output $obj
}
}
}
end {
}
}
@@ -0,0 +1,41 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Get-ITDVMwareVMHostStatus {
[CmdletBinding()]
param (
[string[]]
$Name
)
Begin {
}
Process {
If ($Name) {
Get-VMHost -Name $Name | Select-Object Name, ConnectionState, `
@{n = 'AlarmActionsEnabled'; e = { $_.ExtensionData.AlarmActionsEnabled } }, `
@{n = "LockdownMode"; e = { $_.ExtensionData.Config.LockdownMode } }, `
@{n = 'TSM-SSH'; e = { ($_ | Get-VMHostService | Where-Object { $_.Key -eq "TSM-SSH" }).Running } }
}
Else {
Get-VMHost | Select-Object Name, ConnectionState, `
@{n = 'AlarmActionsEnabled'; e = { $_.ExtensionData.AlarmActionsEnabled } }, `
@{n = "LockdownMode"; e = { $_.ExtensionData.Config.LockdownMode } }, `
@{n = 'TSM-SSH'; e = { ($_ | Get-VMHostService | Where-Object { $_.Key -eq "TSM-SSH" }).Running } }
}
}
End {
}
}
@@ -0,0 +1,209 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function New-ITDVMNetwork {
[CmdletBinding()]
Param
(
[Parameter(Mandatory = $true)]
[string]
$CIDR,
[Parameter(Mandatory = $true)]
[ValidateLength(3, 4)]
[string]
$VlanId,
[Parameter(Mandatory = $true)]
[ValidateSet("Data-Server", "Data-User")]
[string]
$DataType,
#[PSCredential]
#$SharePointCredential,
[PSCredential]
$vCenterCredential
)
begin {
If ($VlanId -eq "MAC" -or $VlanId -eq "MAG") {
$Hypervisor = "Azure"
}
Else {
$Hypervisor = "VMware"
}
Write-Verbose "Hypervisor $Hypervisor"
#VMware
If ($Hypervisor -eq "VMware") {
$ConnectITDvCenterParams = @{ }
If ($vCenterCredential) { $ConnectITDvCenterParams += @{Credential = $vCenterCredential } }
Connect-ITDvCenter @ConnectITDvCenterParams
switch ($DataType) {
'Data-Server' {
$BismarckVDSwitch = 'dvSwitch-PDC-Data-Server'
$MandanVDSwitch = 'dvSwitch-SDC-Data-Server'
}
'Data-User' {
$BismarckVDSwitch = 'dvSwitch-PDC-Data-User'
$MandanVDSwitch = 'dvSwitch-SDC-Data-User'
}
}
$PortGroupList = Get-VirtualPortGroup
}
<#SharePoint
$InvokeWebRequestParams = $null
If ($SharePointCredential) { $InvokeWebRequestParams += @{Credential = $SharePointCredential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
}
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
#$RequestDigest = Invoke-RestMethod -Uri $UrlContextInfo -Method Post -UseDefaultCredentials
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VM Networks')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
}
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
#$List = Invoke-RestMethod -uri $UrlList -UseDefaultCredentials
$List = Invoke-RestMethod @InvokeWebRequestParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItems = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VM Networks')/items" + '?$top=10000'
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
}
#>
}
process {
try {
<#
If ($SharePointCredential) { $GetITDVMwareSharePointNetworkListParams += @{Credential = $SharePointCredential } }
$NetworkList = Get-ITDVMwareSharePointNetworkList @GetITDVMwareSharePointNetworkListParams
#>
$NetworkId = $CIDR.split('/')[0]
$NetworkMask = $CIDR.split('/')[1]
If ($VlanId -match "^\d+$" -and $VlanId.length -eq 3) {
$VlanId = "0" + $VlanId
}
<# Verify CIDR not already in SharePoint
If (@($NetworkList | Where-Object CIDR -EQ $CIDR)) {
Write-Error "CIDR already exists in SharePoint"
}
#>
# If VMware, do more checks then create port group
If ($Hypervisor -eq "VMware") {
# verify VlanId not already in sharepoint
If (@($NetworkList | Where-Object Vlan_Id -EQ $VlanId)) {
Write-Error "Vlan Id already exists in SharePoint"
Exit
}
# verify Vlan Id not already in vmware portgroup
If (@($PortGrouplist | Where-Object { $_.Name.split('_')[2] -eq $NetworkId })) {
Write-Error "Network_Id already exists in VMware PortGroup name"
Exit
}
If (@($PortGrouplist | Where-Object { $_.Name.split('_')[1] -eq $VlanId } )) {
Write-Error "VlanId already exists in VMware PortGroup name"
Exit
}
# Add new port group to VMware
$PGName = "dvPG_" + $VlanId + "_" + $NetworkId + "_" + $NetworkMask
Get-VDSwitch -Name $BismarckVDSwitch | New-VDPortgroup -Name $PGName -NumPorts 1 -VlanId $VlanId
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*_" + $VlanId + "_*") } | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -FailoverDetectionPolicy BeaconProbing
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*_" + $VlanId + "_*") } | Get-VDPortgroupOverridePolicy | Set-VDPortgroupOverridePolicy -BlockOverrideAllowed $false -ResetPortConfigAtDisconnect $false
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*_" + $VlanId + "_*") } | Get-VDSecurityPolicy | Set-VDSecurityPolicy -MacChanges $false -AllowPromiscuous $false
Get-VDSwitch -Name $MandanVDSwitch | New-VDPortgroup -Name $PGName -NumPorts 1 -VlanId $VlanId
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*_" + $VlanId + "_*") } | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -FailoverDetectionPolicy BeaconProbing
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*_" + $VlanId + "_*") } | Get-VDPortgroupOverridePolicy | Set-VDPortgroupOverridePolicy -BlockOverrideAllowed $false -ResetPortConfigAtDisconnect $false
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortgroup | Where-Object { $_.Name -like ("*_" + $VlanId + "_*") } | Get-VDSecurityPolicy | Set-VDSecurityPolicy -MacChanges $false -AllowPromiscuous $false
}
# Get PA7050 Zone info
If ($Hypervisor -eq "Azure") {
$Secure = "True"
$PA_Zone = "Azure"
$AutoUpdate = $false
}
If ($Hypervisor -eq "VMware") {
#$PAInterface = Get-ITDPAInterface -Number ($VlanId.TrimStart('0'))
#If (@($PAInterface).count -gt 1) {
# Write-Error "More than one PA Interface found"
# exit
#}
#else {
# $Secure = [string]$PAInterface.ZeroTrust
# $PA_Zone = $PAInterface.Zone
# $AutoUpdate = $true
#}
}
<# Add to SharePoint
[PSCustomObject]$NewRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName }
}
$NewRecord += @{Title = ("new_" + $env:USERNAME) }
$NewRecord += @{CIDR = $CIDR }
$NewRecord += @{DataType = $DataType }
$NewRecord += @{Vlan_Id = $VlanId }
$NewRecord += @{PA_Zone = $PA_Zone }
$NewRecord += @{Secure = $Secure }
$NewRecord += @{AutoUpdate = $AutoUpdate }
$InvokeWebRequestParams = @{
Uri = $UrlListItems;
Method = "Post";
Body = $NewRecord | ConvertTo-Json;
ContentType = "application/json;odata=verbose";
Headers = $Header;
UseBasicParsing = $AutoUpdate;
}
If ($SharePointCredential) { $InvokeWebRequestParams += @{Credential = $SharePointCredential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
Invoke-RestMethod @InvokeWebRequestParams
#>
}
catch {
Write-Error $error[0]
}
}
end {
}
}
@@ -0,0 +1,49 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Remove-ITDVMwareCdDriveMedia {
[CmdletBinding()]
Param
(
[string[]]
$ComputerName,
[PSCredential]
$Credential
)
Begin {
Connect-ITDvCenter -Credential $Credential
Write-Verbose "Connected to: $global:DefaultVIServers"
If ($global:DefaultVIServers.Count -gt 0) {
Write-Verbose "connected to VI server(s)"
}
Else {
Write-Warning "not connected to any VIservers, stopping script"
break
break
}
}
Process {
ForEach ($c in $ComputerName) {
$CurrentVM = $null
$CurrentVM = Get-VM -Name $c
$CurrentVM | Get-CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
}
End {
}
}
@@ -0,0 +1,34 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Remove-ITDVMwareOSCustomizationSpecOrphan {
[CmdletBinding()]
param (
[int]
$DaysToKeep = 60
)
begin {
}
process {
$OSCustomizationSpecToRemove = Get-OSCustomizationSpec | Where-Object { $_.Name -like "AutoBuild-*" -and $_.LastUpdate -lt ((Get-Date).AddDays($DaysToKeep)) }
$OSCustomizationSpecToRemove | Remove-OSCustomizationSpec -Confirm:$false
}
end {
}
}
@@ -0,0 +1,76 @@
<#
.SYNOPSIS
A short one-line action-based description, e.g. 'Tests if a function is valid'
.DESCRIPTION
A longer description of the function, its purpose, common use cases, etc.
.NOTES
Information or caveats about the function e.g. 'This function is not supported in Linux'
.LINK
Specify a URI to a help page, this will show when Get-Help -Online is used.
.EXAMPLE
Test-MyTestFunction -Verbose
Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines
#>
function Set-ITDVMwareHostMaintenance {
[CmdletBinding()]
param (
[Parameter(ParameterSetName = 'Enclosure', Mandatory = $true)]
[string]
$EnclosureName,
[Parameter(ParameterSetName = 'Manual', Mandatory = $true)]
[string[]]
$VMHostName,
[ValidateSet('Maintenance', 'Online', 'Connected')]
[string]
$State
)
begin {
}
process {
switch ($PSCmdlet.ParameterSetName) {
'Enclosure' {
Write-Verbose "Setting all VMHosts in enclosure $EnclosureName to $State mode."
try {
$VMHostName = (Get-OVServer | Where-Object Name -like $EnclosureName -ErrorAction Stop).ServerName
}
catch {
Write-Error "Failed to retrieve enclosure $EnclosureName. Error: $_"
throw
}
}
'Manual' {
Write-Verbose "Setting specified VMHosts to $State mode."
}
}
switch ($State) {
'Maintenance' {
Write-Verbose "Setting VMHost $VMHostName to Maintenance mode."
try {
Get-VMHost -Name $VMHostName | Set-VMHost -State Maintenance -Confirm:$false -RunAsync
Disable-ITDVMwareVMHostFeature -Name $VMHostName -AlarmActions
}
catch {
Write-Error "Failed to set VMHost $VMHostName to Maintenance mode. Error: $_"
throw
}
}
'Online' {
Write-Verbose "Setting VMHost $VMHostName to Online mode."
Get-VMHost -Name $VMHostName | Set-VMHost -State Connected -Confirm:$false -RunAsync
Enable-ITDVMwareVMHostFeature -Name $VMHostName -AlarmActions
}
}
}
end {
}
}
@@ -0,0 +1,20 @@
# Introduction
TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.
# Getting Started
TODO: Guide users through getting your code up and running on their own system. In this section you can talk about:
1. Installation process
2. Software dependencies
3. Latest releases
4. API references
# Build and Test
TODO: Describe and show how to build your code and run the tests.
# Contribute
TODO: Explain how other users and developers can contribute to make your code better.
If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files:
- [ASP.NET Core](https://github.com/aspnet/Home)
- [Visual Studio Code](https://github.com/Microsoft/vscode)
- [Chakra Core](https://github.com/Microsoft/ChakraCore)
@@ -0,0 +1,251 @@
function Get-ITDVMwareSharePointNetworkList {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
$InvokeWebRequestParams = @{ }
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "https://share.nd.gov/itd/Computer-Systems/Distributed-Systems/VMWare/_api/lists/getbytitle('VM Networks')/items" + '?$top=10000' + '&$select=ID,Title,Vlan_Id,CIDR,PA_Zone,Secure,AutoUpdate'
$InvokeWebRequestParams += @{
Uri = $URL
Method = "Get"
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true
}
$List = (Invoke-RestMethod @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
#$List = (Invoke-RestMethod -Uri $URL -Method Get -UseDefaultCredentials -headers @{ "Accept" = "application/json;odata=verbose" }) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
function Get-ITDPAInterface {
[CmdletBinding()]
Param (
[string[]]
$Number
)
begin {
#[xml]$RawXmlZones = (Invoke-RestMethod -Uri 'https://itdnettools.nd.gov/rktest/7050zones.py').Content
$RawXmlZones = (Invoke-RestMethod -Uri 'https://itdnettools.nd.gov/rktest/7050zones.py')
$Zones = $RawXmlZones.response.result.zone.entry
$UniversalDenyZones = Get-ITDPAUniversalDenyZone
}
process {
$result = @()
ForEach ($Zone in $Zones) {
#$Interfaces = $Zone.network.layer3.member | ForEach-Object{$_ -replace 'ae1.'}
$Interfaces = $Zone.network.layer3.member | ForEach-Object { $_ -replace "ethernet\d/\d\d." }
If ($Number) {
$Interfaces = (Compare-Object -ReferenceObject $Interfaces -DifferenceObject $Number -ExcludeDifferent -IncludeEqual).InputObject
}
ForEach ($Interface in $Interfaces) {
$obj = [PSCustomObject]@{
Interface = $Interface;
Zone = $Zone.name
ZeroTrust = If (@($UniversalDenyZones) -eq $Zone.Name) { $true }Else { $false };
}
$result += $obj
}
}
}
end {
Write-Output $result
}
}
function Get-ITDPAUniversalDenyZone {
[CmdletBinding()]
Param
(
)
Begin {
$Inbound = (((((Invoke-RestMethod -Uri 'http://itdnettools.nd.gov/rktest/7050denyinbound.py?policy=Universal%20Zone%20Deny%20Inbound') -split '[\r\n]+') | Where-Object { $_ -match "<member>" -and $_ -notmatch "any" -and $_ -notmatch "Deny" }) -replace "<member>") -replace "</member>") -Replace " " | Sort-Object
$Outbound = (((((Invoke-RestMethod -Uri 'http://itdnettools.nd.gov/rktest/7050denyinbound.py?policy=Universal%20Zone%20Deny%20Outbound') -split '[\r\n]+') | Where-Object { $_ -match "<member>" -and $_ -notmatch "any" -and $_ -notmatch "Deny" }) -replace "<member>") -replace "</member>") -Replace " " | Sort-Object
}
Process {
$result = Compare-Object -ReferenceObject $Inbound -DifferenceObject $Outbound -IncludeEqual | Sort-Object InputObject
}
End {
Write-Output ($result | Where-Object SideIndicator -EQ '==').InputObject
}
}
function Set-ITDVMwareSharePointNetworkRecord {
[CmdletBinding()]
Param
(
[string]
$Vlan_Id,
[string]
$PA_Zone,
[ValidateSet("True", "False")]
[string]
$Secure,
[PSCredential]
$Credential
)
Begin {
$UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
}
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
#$RequestDigest = Invoke-RestMethod -Uri $UrlContextInfo -Method Post -UseDefaultCredentials
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VM Networks')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
}
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
#$List = Invoke-RestMethod -uri $UrlList -UseDefaultCredentials
$List = Invoke-RestMethod @InvokeWebRequestParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VM Networks')/items" + '?$top=10000'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
#$ListItems=((Invoke-RestMethod -Uri $UrlListItem -Method Get -UseDefaultCredentials -headers @{ "Accept" = "application/json;odata=verbose" }) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$ListItems = ((Invoke-RestMethod @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
}
Process {
$RecordToModify = $ListItems | Where-Object Vlan_id -EQ $Vlan_Id
If (@($RecordToModify).count -gt 1) {
Write-Warning "More than one result, skipping $Vlan_Id"
}
Else {
$IDtoModify = $RecordToModify.ID
$UrlItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VM Networks')/items($IDtoModify)"
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName }
}
If ($PA_Zone) { $SetRecord += @{PA_Zone = $PA_Zone } }
If ($Secure) { $SetRecord += @{Secure = $Secure } }
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
}
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
Invoke-RestMethod @InvokeWebRequestParams
}
}
End {
}
}
$vCenterCredential = Get-AutomationPSCredential -Name 'VMware Auto'
$SharePointCredential = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite'
$SharePointList = Get-ITDVMwareSharePointNetworkList -Credential $SharePointCredential
$PAInterfaces = Get-ITDPAInterface -ErrorAction SilentlyContinue # | select *, @{n = 'Vlan_Id'; e = { $_.Interface.PadLeft(4, '0') } }
If ($null -eq $PAInterfaces) {
}
Else {
ForEach ($SPItem in $SharePointList) {
Write-Warning ($SPItem.Vlan_Id + ", " + $SPItem.CIDR + " - Start")
$change = $false
If ($SPItem.AutoUpdate -eq $true) {
$SetITDVMwareSharePointVMNetworkParams = $null
$PAItem = $PAInterfaces | Where-Object Interface -EQ ($SPItem.Vlan_Id -as [int])
$SetITDVMwareSharePointVMNetworkParams = @{Vlan_Id = $SPItem.Vlan_Id;
Credential = $SharePointCredential
}
If ($PAItem.ZeroTrust) {
If ($SPItem.Secure -ne $PAItem.ZeroTrust) {
$SetITDVMwareSharePointVMNetworkParams += @{Secure = [bool]$PAItem.ZeroTrust }
$change = $true
}
}
Else {
If ($SPItem.Secure -eq $false) {
# Secure is accurate
}
Else {
$SetITDVMwareSharePointVMNetworkParams += @{Secure = $false }
$change = $true
}
}
If ($SPItem.PA_Zone -ne $PAItem.Zone) {
$SetITDVMwareSharePointVMNetworkParams += @{PA_Zone = $PAItem.Zone }
$change = $true
}
If ($Change -eq $true) {
Write-Warning ("Set VM network metadata: Vlan " + $SPItem.Vlan_Id + ", " + $SPItem.CIDR)
Set-ITDVMwareSharePointNetworkRecord @SetITDVMwareSharePointVMNetworkParams
}
}
}
}
$postParams = [PSCustomObject]@{
AutomationName = "Infra-VMware";
Action = 'Provisioning';
Units = 5;
Platform = 'PowerShell-VMware-NetworkSync';
}
Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json)
@@ -0,0 +1,10 @@
$tenantId = '2dea0464-da51-4a88-bae2-b3db94bc0c54'
$AppId = '60244573-7130-4026-9c6d-47de73f8ca29'
$SecureStringPwd = "sQV8Q~sNLcrDl2RgB32gsSEsDVgdFhNMcBdPoaEX"
#$zm = Get-Credential -username $AppId, ($SecureStringPwd | ConvertTo-SecureString -AsPlainText -Force)
$PSCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AppId, ($SecureStringPwd | ConvertTo-SecureString -AsPlainText -Force)
Connect-AzAccount -ServicePrincipal -Credential $PSCredential -Tenant $tenantId
# laptop
Connect-AzAccount -ServicePrincipal -Credential $IaasAutoAzApp -Tenant $tenantId
@@ -0,0 +1,843 @@
# https://96bdfe01-af80-4575-8f23-e7057184c8f6.webhook.cus.azure-automation.net/webhooks?token=dVIj9zHSJwNeR2Ow8QTOoiSoKaPPux9EVJsQAMiGUPg%3d
<#
$ComputerName = 'itddotfrsql3.nd.gov'
$CPU = 8
$MemoryGB = 32
$OS = 'Windows Server 2019 Datacenter'
$Subnet = '10.21.12.0/22'
$Environment = "Production"
$Platform = "Azure"
$AppName = 'DOT-FacialRec'
$LicensingRestrictions='Microsoft SQL Enterprise'
$Credential = $PrvCred
#>
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[object] $WebhookData
)
<# New-ITDVMwareWindowsVMAA
#>
function New-ITDAzureWindowsVMAA {
[CmdLetBinding()]
Param(
[Parameter(Mandatory = $true)]
[string]
$ComputerName,
[Parameter(Mandatory = $true)]
[int]
$CPU,
[Parameter(Mandatory = $true)]
[int]
$MemoryGB,
#[Parameter(Mandatory = $true)]
#[int]
#$DiskOS,
#[Parameter(Mandatory = $true)]
#[int]
#$DiskData,
[Parameter(Mandatory = $true)]
[string]
$Subnet,
[Parameter(Mandatory = $true)]
[string]
$OS,
[Parameter(Mandatory = $true)]
[string]
$Environment,
[Parameter(Mandatory = $true)]
[string]
$AppName,
[Parameter(Mandatory = $true)]
[string]
$LicensingRestrictions
#[Parameter(Mandatory = $true)]
#[PSCredential]
#$Credential
)
$Body = "
ComputerName=$ComputerName
CPU=$CPU
MemoryGB=$MemoryGB
VlanId=$VlanId
OS=$OS
Environment=$Environment
Datacenter=$Datacenter
LicensingRestrictions=$LicensingRestrictions
AppName=$AppName
RunningOn=$env:computername
RunningAs=$env:username
Credential=$Credential.UserName
"
Send-MailMessage -From "zmauto@nd.gov" -To "zmeier@nd.gov" -SmtpServer apprelay1.nd.gov -Body $Body -Subject "AutoBuildAzure-$ComputerName"
$FQDN = $ComputerName
$tenantId = '2dea0464-da51-4a88-bae2-b3db94bc0c54'
If ($Credential) {
$IaasAuto = $Credential
}
#$IaasAutoAzApp = Get-AutomationPSCredential -Name 'Azure IaaS Service Principal'
Write-Warning "[$FQDN]:Start"
$SPCred = $IaasAuto
$ADCred = $IaasAuto
$PSCred = $IaasAuto
$VMCred = $IaasAuto
$CcmCred = $IaasAuto
#$RadiusCred = $RadiusCred
$RadiusCred = New-Object System.Management.Automation.PSCredential($IaasAuto.username.split('\')[1], ($IaaSAuto.Password))
Clear-DnsClientCache
$HostName = $FQDN.split('.')[0]
# Infoblox
#$InfobloxVlanMetadata = Get-ITDIbVlan -CIDR $Subnet -Credential $RadiusCred # not valid for Azure
#$Cidr = ($InfobloxVlanMetadata.AssignedTo | Out-String).TrimEnd()
$Cidr = $Subnet
[Net.IpAddress]$NetworkId = $Cidr.split('/')[0]
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
$SubnetMaskInt = $CIDR.split('/')[1]
$Int64 = ([convert]::ToInt64(('1' * $SubnetMaskInt + '0' * (32 - $SubnetMaskInt)), 2))
[Net.IPAddress]$SubnetMask = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($Int64 / 16777216)).ToString(),
([math]::Truncate(($Int64 % 16777216) / 65536)).ToString(),
([math]::Truncate(($Int64 % 65536) / 256)).ToString(),
([math]::Truncate($Int64 % 256)).ToString()
$IPSplit = $Subnet.Split('.')
[Net.IPAddress]$DefaultGateway = ($IPSplit[0] + '.' + $IPSplit[1] + '.' + $IPSplit[2] + '.' + (($CIDR.split('/')[0].split('.')[-1] -as [int]) + 1) )
If ($IpAddress) {
If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) {
Write-Warning "DNS record already exists, CIDR Block match"
}
Else {
Write-Error "DNS record already exists, and does not match CIDR Block"
Break
}
}
Else {
New-ITDIbDNSRecordNextAvailableIP -Hostname $FQDN -CIDR $CIDR -Credential $RadiusCred
Start-Sleep -Seconds 5
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) {
Write-Error "IP Address already in use." -ErrorAction Stop
}
}
# Passwordstate
If ($FQDN -like "itdcnd*") {
$PasswordStateList = "Peoplesoft Share PW"
}
Else {
$PasswordStateList = "CSRC"
}
$LocalCredential = New-ITDPassword -Title $FQDN -UserName itdadmin -Description 'Local Administrator' -PasswordList $PasswordStateList -Credential $PSCred
#$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
#$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ($LocalCredential.UserName, ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ('itdadmin', ($LocalCredential.GetNetworkCredential().Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.GetNetworkCredential().Password | ConvertTo-SecureString -AsPlainText -Force))
#$GuestCredential = $GuestCredentialBB
switch ($Environment) {
{ $_ -eq 'Test' -or $_ -eq 'Development' } {
Write-Warning 'Environment is Test or Development'
$EnvShortString = 'tst'
#$VMSizeFilter="*_B*s*"
$VMSizeFilter1 = "*_D[0-9]*s_v3"
$VMSizeFilter2 = "*_E[0-9]*s_v3"
$VMSizeFilter3 = "*_F[0-9]*s_v2"
$Subscription = "npd01"
$VNet = "vnet-npd01-001"
$VNetSubnet = "sn-shared-zerotrust-npd-10.21.8.0_22"
}
'Production' {
Write-Warning 'Environment is Production'
$EnvShortString = 'prd'
#$VMSizeFilter="*_D*s_*"
$VMSizeFilter1 = "*_D[0-9]*s_v3"
$VMSizeFilter2 = "*_E[0-9]*s_v3"
$VMSizeFilter3 = "*_F[0-9]*s_v2"
$Subscription = "prd01"
$VNet = "vnet-prd01-001"
$VnetSubnet = "sn-shared-zerotrust-prd-10.21.12.0_22"
}
'CARES-tst' {
Write-Warning 'Environment is CARES-tst'
$EnvShortString = 'tst'
#$VMSizeFilter="*_D*s_*"
$VMSizeFilter1 = "*_D[0-9]*s_v3"
$VMSizeFilter2 = "*_E[0-9]*s_v3"
$VMSizeFilter3 = "*_F[0-9]*s_v2"
$Subscription = "cares01"
$VNet = "vnet-infra-azurenetworking-cares01-npd"
$VnetSubnet = "sn-shared-zerotrust-npd-10.69.254.0_24"
}
'CARES-prd' {
Write-Warning 'Environment is CARES-prd'
$EnvShortString = 'prd'
#$VMSizeFilter="*_D*s_*"
$VMSizeFilter1 = "*_D[0-9]*s_v3"
$VMSizeFilter2 = "*_E[0-9]*s_v3"
$VMSizeFilter3 = "*_F[0-9]*s_v2"
$Subscription = "cares01"
$VNet = "vnet-infra-azurenetworking-cares01-prd"
$VnetSubnet = "sn-shared-zerotrust-prd-10.69.126.0_24"
}
Default {
Write-Error "Environment failed" -ErrorAction Stop
}
}
switch ($OS) {
"Windows Server 2019 Datacenter" {
$VMOS = "Windows"
$Publisher = "MicrosoftWindowsServer"
$Offer = "WindowsServer"
$sku = "2019-Datacenter"
}
"Windows Server 2022 Datacenter" {
$VMOS = "Windows"
$Publisher = "MicrosoftWindowsServer"
$Offer = "WindowsServer"
$sku = "2022-datacenter"
}
Default { Write-Error "Invalid operating system" -ErrorAction Stop }
}
# finalize VM size
Connect-AzAccount -ServicePrincipal -Credential $IaasAutoAzApp -Tenant $tenantId
$location = "centralus"
$VMSize = Get-AzVMSize -Location $location | `
Where-Object { $_.Name -Like "$VMSizeFilter1" -or $_.Name -Like "$VMSizeFilter2" -or $_.Name -Like "$VMSizeFilter3" } | `
Where-Object { $_.NumberOfCores -ge $CPU -and $_.MemoryInMB -ge ($Memory * 1024) } | `
Where-Object Name -NotMatch "_Promo" | `
Sort-Object NumberOfCores, MemoryInMB | `
Select-Object -First 1
# resource group things
$VMOwner = $AppName.split('-')[0].ToLower()
$VMFunction = (($AppName -replace "$VMOwner-") -replace "-").ToLower() -replace " "
#$IPAddress = (Resolve-DnsName -Name $ComputerName -ErrorAction Stop).IpAddress
$ResourceGroup = "rg-$VMOwner-$VMFunction-$EnvShortString"
If ($ResourceGroupIndex) { $ResourceGroup = $ResourceGroup + "-$ResourceGroupIndex" }
$VMName = "vm-$HostName-$EnvShortString"
$NewITDAzureRMVMParams = @{
VMFQDN = $ComputerName
VMSubscription = $Subscription
VMEnvironment = $EnvShortString
VMOwner = $VMOwner
VMFunction = $VMFunction
VMSize = $VMSize.Name
VMOS = $VMOS
VMPublisher = $Publisher
VMOffer = $Offer
VMSku = $sku
VMVnetName = $VNet
VMSubnet = $VNetSubnet
VMLocation = $location
VMIP = $IPAddress.IPAddressToString
VMCredential = $LocalCredential
AppName = $AppName
}
<#
$VMFQDN = $ComputerName
$VMSubscription = $Subscription
$VMEnvironment = $EnvShortString
$VMOwner = $VMOwner
$VMFunction = $VMFunction
$VMSize = $VMSize.Name
$VMOS = $VMOS
$VMPublisher = $Publisher
$VMOffer = $Offer
$VMSku = $sku
$VMVnetName = $VNet
$VMSubnet = $VNetSubnet
$VMLocation = $location
$VMIP = $IPAddress
$VMCredential = $LocalCredential
$AppName = $AppName
#>
New-ITDAzureRMVM @NewITDAzureRMVMParams
# wait for build
$VMName = ('vm-' + $ComputerName.split('.')[0] + '-' + $EnvShortString)
$VMStatus = $null
$VMCreation = $Null
While ($VMCreation -ne "Complete") {
If (( (Get-AzVM -ResourceGroupName $ResourceGroup -Name $VMName -Status).Statuses | Where-Object Code -Match "PowerState").Code -eq "PowerState/running") {
$VMCreation = "Complete"
}
else {
Start-Sleep -Seconds 300
}
}
Start-Sleep -Seconds 30
# Add extra disk
Add-ITDAzureRMNewDataDisk -VMName $VMName -SizeGB 20
# pre-firewall Guest OS customization
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroup -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath 'C:\AzWinBuild\1-SetWMITags.ps1'
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroup -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath 'C:\AzWinBuild\3-Disks.ps1'
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroup -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath 'C:\AzWinBuild\5-TimeZone.ps1'
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroup -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath 'C:\AzWinBuild\6-PerformanceCounters.ps1'
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroup -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath 'C:\AzWinBuild\7-DisableWindowsFirewall.ps1'
# determine Active Directory Forest and OU
$DomainName = $FQDN.Substring($FQDN.IndexOf(".") + 1)
switch ($DomainName) {
'nd.gov' {
$SearchBaseDomain = "dc=nd,dc=gov"
}
'ndcloud.gov' {
$SearchBaseDomain = "dc=ndcloud,dc=gov"
}
}
If ($DomainName -eq "nd.gov") {
$OUAppName = Get-ADOrganizationalUnit -Server $DomainName -SearchBase ("OU=Windows,OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq $AppName }
If (!($OUAppName)) {
$OUAppName = Get-ADOrganizationalUnit -SearchBase ("OU=Windows,OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq 'All-General' }
}
$ExistingADComputer = Get-ADComputer -Filter { Name -eq $Hostname }
If ($ExistingADComputer) {
If ($ExistingADComputer.DistinguishedName -like ("*" + $AppName + "*") -or $ExistingADComputer.DistinguishedName -like "*All-General*") {
Write-Warning "AD object already exists, OU path does match"
$OuFinal = $ExistingADComputer.DistinguishedName -replace '^.+?(?<!\\),', ''
}
Else {
Write-Error "AD object already exists, OU path mismatch"
Exit
Exit
}
}
Else {
switch ($Environment) {
'Test' {
If ($AppName -like "Shared-Peoplesoft*") { $EnvString = "Non-Prod" }
Else { $EnvString = "Test" }
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -EQ "$EnvString"
}
'Production' {
If ($AppName -like "Shared-Peoplesoft*") { $EnvString = "Prod" }
Else { $EnvString = "Prod" }
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -EQ "$EnvString"
}
}
If ($OuAppNameEnv) { $OUFinal = $OUAppNameEnv.DistinguishedName }
Else { $OuFinal = $OUAppName.DistinguishedName }
New-ADComputer -Name $HostName.ToUpper() -Path $OUFinal -Credential $ADCred -Description ($SPItem | Select-Object AppName, Environment | ConvertTo-Json)
}
}
# disconnect, wait for firewall, then reconnect
Disconnect-AzAccount
While ($PingStatus -eq $false) {
$PingTest = Test-NetConnection -ComputerName $FQDN
If ($PingTest.PingSuccedded -eq $true) {
$PingStatus = $true
}
Start-Sleep -Seconds 300
}
Connect-AzAccount -ServicePrincipal -Credential $IaasAutoAzApp -Tenant $tenantId
Set-AzContext -Subscription $Subscription
# post-firewall Guest OS customization
switch ($DomainName) {
'nd.gov' {
Write-Warning "Attempting domain join nd.gov"
Write-Warning "Domain: $DomainName"
Write-Warning "OuPath: $OuFinal"
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroup -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath 'C:\AzWinBuild\8-Domain-ndgov.ps1' -Parameter @{"DomainName" = 'nd.gov'; "OuPath" = ' CN=ITDSOSCMTSQL22,OU=SOS-BLS,OU=SOS-All,OU=Windows,OU=SERVERS,OU=COMPUTERS,OU=ITD,DC=nd,DC=gov' }
}
}
Write-Verbose -Message "Activating windows against $KMS..."
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroup -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath 'C:\AzWinBuild\9-KMS.ps1'
<#
Write-Warning "[$FQDN]:Register SCCM Client"
$CcmRegistered = $false
While ($CcmRegistered -eq $false) {
$CcmResult = Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroup -Name $VMName -CommandId 'RunPowerShellScript' -ScriptPath 'C:\AzWinBuild\10-SCCM-a.ps1'
If ($CcmResult.Value -match "SCCM Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistered -eq $false) { Start-Sleep -Seconds 60 }
}
Write-Warning -Message "[$FQDN]:Approve SCCM Client"
#Start-Sleep -Seconds 30 # ADD LOOP/SMARTS TO WAIT FOR DISCOVERY AND ANOTHER FOR APPROVAL
Invoke-Command -ComputerName itdsccmp2.nd.gov -Credential $CcmCred -ArgumentList $Hostname -ScriptBlock {
Import-Module 'D:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1'
$PSDrives = Get-PSDrive
If ($PSDrives | Where-Object Name -EQ "ITD") {
# ITD Drive exists, do nothing
}
else {
New-PSDrive -Name "ITD" -PSProvider AdminUI.PS.Provider\CMSite -Root itdsccmp2.nd.gov
}
Set-Location ITD:\
$Device = Get-CMDevice -Name $args[0]
If ($Device.IsApproved -eq 0) {
Approve-CMDevice -DeviceName $args[0]
}
}
#>
}
function New-ITDAzureRMVM {
[CmdletBinding()]
Param
(
# VM Computer Name (FQDN)
[Parameter(Mandatory = $true, Position = 0)]
[String]
$VMFQDN,
# VM Subscription (tst,prd,dr)
[Parameter(Mandatory = $true)]
[string]
$VMSubscription,
# Environment (tst,prd,dr)
[Parameter(Mandatory = $true)]
[string]
$VMEnvironment,
# Owner (infra,shared,ITD,DHS,etc)
[Parameter(Mandatory = $true)]
[string]
$VMOwner,
# Function (testdc, POC, etc)
[Parameter(Mandatory = $true)]
[string]
$VMFunction,
#[Parameter(Mandatory=$true)]
[string]
$ResourceGroupIndexNumber,
# Azure VM Size
[Parameter(Mandatory = $true)]
[string]
$VMSize,
# Azure OS (Windows or Linux)
[Parameter(Mandatory = $true)]
[string]
$VMOS,
# Availability Set
[switch]
$VMAS,
# Availability Set Tier
[string]
$VMASTier,
# Availability Zone
[ValidateSet(1, 2, 3)]
[int]
$VMAvailZone,
# Azure Publisher
[string]
$VMPublisher,
# Azure Offer
[string]
$VMOffer,
# Azure Sku
[string]
$VMSku,
# Azure vNet
[Parameter(Mandatory = $true)]
[string]
$VMVNetName,
# Azure Subnet
[Parameter(Mandatory = $true)]
[string]
$VMSubnet,
# Azure Location
[Parameter(Mandatory = $true)]
[string]
$VMLocation,
# Azure Private IP
[Parameter(Mandatory = $true)]
[string]
$VMIP,
[Parameter(Mandatory = $true)]
[PSCredential]
$VMCredential,
# App name to be used for the RG
[Parameter(Mandatory = $true)]
[string]
$AppName
)
Begin {
$VMName = $VMFQDN.Split('.')[0]
#$VMIndexNumber = "001"
$VMIPConfigName = "ipconfig-$VMName-$VMEnvironment"
$VMNicName = "nic-$VMName-$VMEnvironment" ######
$VMObjectName = "vm-$VMName-$VMEnvironment"
$ResourceGroup = "rg-$VMOwner-$VMFunction-$VMEnvironment"
#If($ResourceGroupIndexNumber){$ResourceGroup = $ResourceGroup + "-$ResourceGroupIndexNumber"}
#removing diag storage account because replaced by managed storage accounts for boot diagnostics
#$VMDiagStorageAcct = "sa" + $VMOwner + $VMFunction + "diag" + $VMEnvironment
$VMOSDiskName = "vm-$VMName-os-$VMEnvironment"
<#
If($VMASTier)
{
$VMASName = "as-$VMOwner-$VMFunction-$VMASTier-$VMEnvironment"
}
Else
{
$VMASName = "as-$VMOwner-$VMFunction-$VMEnvironment"
}
#>
<#
Write-Verbose "Checking Storage Account Length"
If (($VmDiagStorageAcct.Length) -gt 24){
Write-Verbose "Storage Account Length is too long. Truncating function...."
$TruncateCharacters = $VmDiagStorageAcct.Length - 24
$ShortVMFunction = $VMFunction.Substring(0, ($VMFunction.length) - $TruncateCharacters)
$VMDiagStorageAcct = "sa" + $VMOwner + $ShortVMFunction + "diag" + $VMEnvironment
}
If (($VmDiagStorageAcct.Length) -gt 24){
Write-Verbose "Storage Account Length is too long after truncating. Terminating Build"
Return
}
#>
Write-Verbose "Verifying Applicable Inputs are Lowercase"
$VMIPConfigName = $VMIPConfigName.ToLower()
$VMNicName = $VMNicName.ToLower()
$VMObjectName = $VMObjectName.ToLower()
$ResourceGroup = $ResourceGroup.ToLower()
#$VMDiagStorageAcct = $VMDiagStorageAcct.ToLower()
$VMOSDiskName = $VMOSDiskName.ToLower()
}
Process {
Set-AzContext $VMSubscription
$ResGroupExist = ""
Write-Verbose "Creating Resource Group if it doesn't exist"
$ResGroupExist = Get-AzResourceGroup -Name $ResourceGroup -ErrorAction SilentlyContinue
If (@($ResGroupExist).count -gt 1) {
Write-Error "Multiple Resource Groups matched" -ErrorAction Stop
}
If (@($ResGroupExist).count -lt 1) {
Write-Warning "No matching resource group found, creating it now"
New-AzResourceGroup -Name $ResourceGroup -Location $VMLocation -Tag @{ApplicationName = $AppName }
$ResourceGroupName = $ResourceGroupSearch.ResourceGroupName
#Write-Error "No Resource Groups matched" -ErrorAction Stop
}
If (@($ResGroupExist).count -eq 1) {
Write-Warning "Exactly one matching resource group found"
$ResourceGroupName = $ResourceGroupSearch.ResourceGroupName
}
<#
Write-Verbose "Checking Storage Account Availability in Subscription"
If (!(Get-AzureRmStorageAccount | Where-Object {$_.StorageAccountName -eq $VMDiagStorageAcct}))
{
If ((Get-AzureRmStorageAccountNameAvailability -Name $VMDiagStorageAcct).NameAvailable -eq $True)
{
New-AzureRmStorageAccount -Name $VMDiagStorageAcct -Location $VMLocation -ResourceGroupName $ResourceGroup -SkuName "Standard_LRS" -EnableHttpsTrafficOnly $true
#Start-Sleep -Seconds 5
Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroup -Name $VMDiagStorageAcct | Update-AzureRmStorageAccountNetworkRuleSet -DefaultAction Deny -Bypass None
#Update-AzureRmStorageAccountNetworkRuleSet -ResourceGroupName $ResourceGroup -Name $VMDiagStorageAcct -DefaultAction Deny -Bypass None
Add-AzureRmStorageAccountNetworkRule -ResourceGroupName $ResourceGroup -AccountName $VMDiagStorageAcct -IPAddressOrRange "165.234.248.3"
}
Else
{
Write-Verbose "Storage Account already exists. Re-run with a valid storage account"
Return
}
}
#>
<#
Write-Verbose "Evaluating Availability Set"
If($VMAS)
{
Write-Verbose "Checking for existing Availability Set"
$VMASExist = Get-AzAvailabilitySet -ResourceGroupName $ResourceGroup -Name $VMASName -ErrorAction SilentlyContinue
If($VMASExisting)
{
$VMASID = $VMASExist.id
}
Else
{
New-AzAvailabilitySet -ResourceGroupName $ResourceGroup -Name $VMASName -Location $VMLocation -PlatformFaultDomainCount 3 -PlatformUpdateDomainCount 5 -Sku Aligned
$VMASID = (Get-AzAvailabilitySet -ResourceGroupName $ResourceGroup -Name $VMASName).id
}
}
#>
Write-Verbose "Preparing Network Config"
$VNet = (Get-AzVirtualNetwork | where { $_.Name -eq $VMVNetName })
$VNetID = $VNet.id
$Subnet = ($VNet.Subnets | where { $_.Name -eq $VMSubnet })
$SubnetName = $Subnet.name
$SubnetID = $Subnet.id
Write-Verbose "Creating IPConfig and NIC"
$IPConfig = New-AzNetworkInterfaceIpConfig -Name $VMIPConfigName -PrivateIpAddress $VMIP -PrivateIpAddressVersion IPv4 -Subnet $Subnet
$VMNIC = New-AzNetworkInterface -IpConfigurationName $IPConfig -Location $VMLocation -Name $VMNICName -ResourceGroupName $ResourceGroup -SubnetId $SubnetID
$VMNIC.IpConfigurations[0].PrivateIpAllocationMethod = "Static"
$VMNIC.IpConfigurations[0].PrivateIpAddress = $VMIP
Set-AzNetworkInterface -NetworkInterface $VMNIC
Write-Verbose "Building VM Config"
#If($VMAS)
#{
#$vmConfig = New-AzVMConfig -VMName $VMObjectName -VMSize $VMSize -AvailabilitySetId $VMASID
#}
#Else
#{
#If($VMAvailZone)
#{
# Write-Verbose "AvailZone $VMAvailZone"
# $vmConfigParams = @{
# VMName = $VMObjectName
# VMSize = $VMSize
# Zone = $VMAvailZone
# }
#}
#Else
#{
# Write-Verbose "No AvailZone"
$vmConfigParams = @{
VMName = $VMObjectName
VMSize = $VMSize
}
#}
#$vmConfig = New-AzureRmVMConfig -VMName $VMObjectName -VMSize $VMSize
$vmConfig = New-AzVMConfig @vmConfigParams
#}
$vmConfig | Set-AzVMOSDisk -Name $VMOSDiskName -CreateOption FromImage
If ($VMOS -eq "Windows") {
$vmConfig | Set-AzVMOperatingSystem -Windows -ComputerName $VMName -Credential $VMCredential
$vmConfig | Set-AzVMSourceImage -PublisherName $VMPublisher -Offer $VMOffer -Skus $VMSku -Version latest
}
If ($VMOS -eq "Linux") {
$vmConfig | Set-AzVMOperatingSystem -Linux -ComputerName $VMFQDN -Credential $VMCredential
Switch ($VMSubscription) {
#"npd01" {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/76297098-764c-43de-8525-c9fda1b237be/resourceGroups/rg-infra-templates-tst-001/providers/Microsoft.Compute/images/vm-rhel74template-prd-001"}
#"infra01" {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/e53aa0c7-824d-40a2-b420-4ab77b1051d2/resourceGroups/rg-infra-templates-prd-001/providers/Microsoft.Compute/images/vm-rhel74template-prd-001"}
#"prd01" {$vmConfig | Set-AzureRmVMSourceImage -Id "/subscriptions/437b2bfa-850e-4464-b6c2-38a68cda7c69/resourceGroups/rg-infra-templates-prd-002/providers/Microsoft.Compute/images/vm-rhel74template-prd-002"}
"npd01" { $vmConfig | Set-AzVMSourceImage -Id "/subscriptions/76297098-764c-43de-8525-c9fda1b237be/resourceGroups/rg-infra-templates-tst-001/providers/Microsoft.Compute/images/vm-rhel74template-prd-103" }
"infra01" { $vmConfig | Set-AzVMSourceImage -Id "/subscriptions/e53aa0c7-824d-40a2-b420-4ab77b1051d2/resourceGroups/rg-infra-templates-prd-001/providers/Microsoft.Compute/images/vm-rhel74template-prd-403" }
"prd01" { $vmConfig | Set-AzVMSourceImage -Id "/subscriptions/437b2bfa-850e-4464-b6c2-38a68cda7c69/resourceGroups/rg-infra-templates-prd-002/providers/Microsoft.Compute/images/vm-rhel74template-prd-003" }
}
}
$vmConfig | Add-AzVMNetworkInterface -Id $VMNIC.ID
#$vmConfig | Set-AzureRmVMBootDiagnostics -Enable -ResourceGroupName $ResourceGroup -StorageAccountName $VMDiagStorageAcct
##set to use managed storage account after module conversion to Az
#$vmConfig | Set-AzVMBootDiagnostic -VM $vmConfig -Enable -ResourceGroupName $ResourceGroup
Set-AzVMBootDiagnostic -VM $vmConfig -Enable -ResourceGroupName $ResourceGroup
Write-Verbose "Creating VM"
New-AzVM -VM $vmConfig -ResourceGroupName $resourceGroup -Location $VMLocation -DisableBginfoExtension -LicenseType "Windows_Server" -AsJob
}
End {
}
}
function Add-ITDAzureRMNewDataDisk {
[CmdletBinding()]
Param
(
[string]
$VMName,
[int[]]
$SizeGB
)
Begin {
$search = @()
$Hostname = $VMName.split('-')[1]
$Environment = $VMName.split('-')[2]
Get-AzSubscription | ForEach-Object {
$Subscription = $_
Set-AzContext $_ | Out-Null
$search += Get-AzVM | Where-Object Name -EQ $VMName | Select-Object *, @{n = 'SubscriptionName'; e = { $Subscription.Name } }
}
}
Process {
If ($search.count -eq 1) {
Set-AzContext $search.SubscriptionName
$ResourceGroup = $search.ResourceGroupName.ToLower()
$Location = (Get-AzResourceGroup -Name $ResourceGroup).Location
$VM = Get-AzVM -Name $VMName -ResourceGroupName $ResourceGroup
$Zone = $VM.Zones
ForEach ($Size in $SizeGB) {
$ExistingDisks = @($VM.StorageProfile.DataDisks | Select-Object *, @{n = 'ItdId'; e = { [int]($_.Name -replace "vm-$hostname-app-$environment-") } })
$NewDiskItdIdInt = ($ExistingDisks | Sort-Object ItdId -Descending | Select-Object -First 1).ItdId + 1
$NewDiskItdIdStr = $NewDiskItdIdInt.ToString("000")
$NewDiskName = "vm-$Hostname-app-$Environment-$NewDiskItdIdStr" #vm-itduc4p1-app-tst-001
$LunID = ($ExistingDisks | Sort-Object Lun -Descending | Select-Object -First 1).Lun + 1
$count = 0
If ($ExistingDisks) {
while ($Size -match $ExistingDisks.DiskSizeGB) {
$count++
Write-Warning "SizeGB: $Size, Count: $count"
If ($count -ge 11) {
Write-Error "Disk size not available" -ErrorAction Stop
}
Else {
$Size = $Size - 1
}
}
}
Write-Warning "SizeGB: $Size, Count: $count"
$AzureRmDiskConfigParams = @{
DiskSizeGB = $Size
Location = $Location
CreateOption = "Empty"
SkuName = "Premium_LRS"
}
If ($Zone) {
Write-Verbose "VM is located in Zone $Zone"
$AzureRmDiskConfigParams += @{Zone = $Zone }
}
#$DiskConfig = New-AzureRmDiskConfig -DiskSizeGB $Size -Location $Location -CreateOption Empty -SkuName Premium_LRS
$DiskConfig = New-AzDiskConfig @AzureRmDiskConfigParams
If (!(Get-AzDisk -ResourceGroupName $ResourceGroup -DiskName $NewDiskName -ErrorAction SilentlyContinue)) {
$NewDisk = New-AzDisk -DiskName $NewDiskName -Disk $DiskConfig -ResourceGroupName $ResourceGroup
$VM = Add-AzVMDataDisk -Name $NewDiskName -CreateOption Attach -ManagedDiskId $NewDisk.Id -VM $VM -Lun $LunID -Caching ReadOnly
Update-AzVM -VM $VM -ResourceGroupName $ResourceGroup -AsJob
}
}
}
Else {
Write-Error "Search count invalid" -ErrorAction SilentlyContinue
}
}
End {
}
}
$IaasAutoCred = Get-AutomationPSCredential -Name 'ITD Iaas Automation'
$IaasAutoCred = $IaaSAutoAz
<#
New-ITDAzureWindowsVMAA `
-ComputerName itdbuilddba.nd.gov `
-CPU 2 `
-MemoryGB 8 `
-Subnet '10.21.8.0/22'`
-OS 'Windows Server 2019 Datacenter' `
-Environment 'Test' `
-AppName 'Infra-SoftDev-TFS' `
-LicensingRestrictions 'No Licensing Restrictions' `
-verbose
#>
<#
$params = @{
ComputerName = "itdpurshir1.nd.gov"
CPU = 2;
MemoryGB = 8;
Subnet = '10.69.254.0/24';
OS = 'Windows Server 2022 Datacenter';
Environment = 'CARES-tst';
AppName = 'ITD-POC-Purview';
LicensingRestrictions = 'No Licensing Restrictions';
Verbose = $true;
}
New-ITDAzureWindowsVMAA @params
#>
$params = @{
ComputerName = "itdsoscmtsql22.nd.gov"
CPU = 4;
MemoryGB = 16;
Subnet = '10.21.8.0/22';
OS = 'Windows Server 2022 Datacenter';
Environment = 'Test';
AppName = 'SOS-BLS';
LicensingRestrictions = 'Microsoft SQL Standard';
Verbose = $true;
}
New-ITDAzureWindowsVMAA @params
#>
@@ -0,0 +1,18 @@
$RestMethodParams = @{
Method = 'Post';
Uri = 'https://96bdfe01-af80-4575-8f23-e7057184c8f6.webhook.cus.azure-automation.net/webhooks?token=dVIj9zHSJwNeR2Ow8QTOoiSoKaPPux9EVJsQAMiGUPg%3d';
Headers = @{ITD = 'mXJU74ABYyDHcVY6iJihPDk8LidJ2ibBA2sA3RAwKaBHS6Gw7Rr2Zz5JZAhPm6wMuvY7X54ZzJxAXaM7ig3PHG4MKvtkBf8X7q3jGNcePgUqg9WCwCSJ3JWG7AA6M39x4vpihKeZV'};
Body = [PSCustomObject]@{
ComputerName = 'itddhsharvestp1.nd.gov';
CPU = 2;
MemoryGB = 24;
VlanId = 3822;
OS = 'Windows Server 2022 Datacenter';
Environment = 'Production';
Datacenter = 'Bismarck';
AppName = 'DHS-Orchard-Harvest';
LicensingRestrictions = 'No Licensing Restrictions';
} | ConvertTo-Json;
}
Invoke-RestMethod @RestMethodParams | ConvertTo-Json
@@ -0,0 +1,358 @@
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[object] $WebhookData
)
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq '6EE8DaFMbswirY38qPfewwT82G9Bdiv8p3SKEdisX88mfnFfiredy6uti4nJprecedegJkTGBHDV3alpineePkM5grainsE56xp3JmuffWjwL') {
Write-Verbose "Header has required data"
}
Else {
Write-Error "Header missing required data"
exit;
}
$InputParams = (ConvertFrom-Json -InputObject $WebhookData.RequestBody)
$FQDN = 'itdzmbuild01.nd.gov'
# Get Credentials
$SPCred = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite'
$ADCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation'
$PSCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation'
$IBCred = New-Object System.Management.Automation.PSCredential ($ADCred.UserName.split('\')[1], $ADCred.Password)
$VMCred = Get-AutomationPSCredential -Name 'VMware Auto'
Clear-DnsClientCache
$SharePointList = Get-ITDVMwareSharePointVMGuestListTst -Credential $SPCred
$SPItem = $SharePointList | Where-Object Title -eq $FQDN
$HostName = $FQDN.split('.')[0]
# Infoblox
[Net.IpAddress]$NetworkId = $SPItem.CIDR.split('/')[0]
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
$SubnetMaskInt = $SPItem.Cidr.split('/')[1]
$Int64 = ([convert]::ToInt64(('1' * $SubnetMaskInt + '0' * (32 - $SubnetMaskInt)), 2))
[Net.IPAddress]$SubnetMask = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($Int64 / 16777216)).ToString(),
([math]::Truncate(($Int64 % 16777216) / 65536)).ToString(),
([math]::Truncate(($Int64 % 65536) / 256)).ToString(),
([math]::Truncate($Int64 % 256)).ToString()
$IPSplit = $SPItem.Cidr.Split('.')
[Net.IPAddress]$DefaultGateway = ($IPSplit[0] + '.' + $IPSplit[1] + '.' + $IPSplit[2] + '.' + (($SPItem.Cidr.split('/')[0].split('.')[-1] -as [int]) + 1) )
If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) {
Write-Verbose "IP Address and CIDR Block match"
}
Else {
Write-Error "DNS record already exists, and does not match CIDR Block" -ErrorAction Stop
}
If ($IpAddress) {
If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) {
Write-Warning "DNS record already exists, CIDR Block match"
}
else {
Write-Error "DNS record already exists, and does not match CIDR Block"
Break
}
}
Else {
New-ITDIbDNSRecordNextAvailableIP -HostName $SPItem.Title -CIDR $SPItem.CIDR -Credential $IBCred
}
If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) {
Write-Error "IP Address already in use." -ErrorAction Stop
}
# Active Directory
If ($PSEdition -eq 'Core') { Import-Module ActiveDirectory -UseWindowsPowerShell }
$Filter = ("{Name -eq '" + $SPItem.AppName + "'}")
$OUAppName = Get-ADOrganizationalUnit -SearchBase "OU=Windows,OU=SERVERS,ou=COMPUTERS,ou=ITD,dc=nd,dc=gov" -Filter $Filter
If (!($OUAppName)) {
$OUAppName = Get-ADOrganizationalUnit -SearchBase "OU=Windows,OU=SERVERS,ou=COMPUTERS,ou=ITD,dc=nd,dc=gov" -Filter { Name -eq 'All-General' }
}
$ExistingADComputer = Get-ADComputer -Identity $Hostname -ErrorAction SilentlyContinue
If ($ExistingADComputer) {
If ($ExistingADComputer.DistinguishedName -like ("*" + $SPItem.AppName + "*") -or $ExistingADComputer.DistinguishedName -like "*All-General*") {
Write-Warning "AD object already exists, OU path does match"
}
Else {
Write-Error "AD object already exists, OU path mismatch"
Exit
Exit
}
}
else {
switch ($SPItem.Environment) {
'Test' {
$OUAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -like "*Test*"
}
'Production' {
$OUAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -like "*Prod*"
}
}
If ($OUAppNameEnv) { $OUFinal = $OUAppNameEnv }
Else { $OUFinal = $OUAppName }
New-ADComputer -Name $HostName.ToUpper() -Path $OUFinal -Credential $ADCred -Description ($SPItem | Select-Object AppName, Environment | ConvertTo-Json)
}
# Passwordstate
$LocalCredential = New-ITDPassword -Title $FQDN -Username itdadmin -Description 'Local Administrator' -PasswordList CSRC -Credential $PrvCred
$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ($LocalCredential.UserName, ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
# VMware
If (Get-VM -Name $FQDN -ErrorAction SilentlyContinue) {
Write-Error "Virtual machine with the name $FQDN already exists." -ErrorAction Stop
Stop
Stop
}
switch ($SPItem.Cluster) {
"WINDOWS1" {
$ViServer = 'itdvmvc1.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data"
$DiskStorageFormat = 'Thin'
}
"WINDOWS2" {
$ViServer = 'itdvmvc2.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data"
$DiskStorageFormat = 'Thin'
}
"SQL1" {
$ViServer = 'itdvmvc1.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data"
$DiskStorageFormat = 'EagerZeroedThick'
}
"SQL2" {
$ViServer = 'itdvmvc2.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data"
$DiskStorageFormat = 'EagerZeroedThick'
}
"WAS1" {
$ViServer = 'itdvmvc1.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data"
$DiskStorageFormat = 'Thin'
}
"WAS2" {
$ViServer = 'itdvmvc2.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data"
$DiskStorageFormat = 'Thin'
}
"PS1" {
$ViServer = 'itdvmvc1.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-PS1-Data"
$DiskStorageFormat = 'Thin'
}
"PS2" {
$ViServer = 'itdvmvc2.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-PS2-Data"
$DiskStorageFormat = 'Thin'
}
"TEL1" {
$ViServer = 'itdvmvc1.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL1-Data"
$DiskStorageFormat = 'Thin'
}
"TEL2" {
$ViServer = 'itdvmvc2.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL2-Data"
$DiskStorageFormat = 'Thin'
}
"DCN1" {
$ViServer = 'itdvmvc1.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-DCN-vMotion-Data"
$DiskStorageFormat = 'Thin'
}
}
# verify disk will fit
$DiskTotal = $SPItem.Disk1 + $SPItem.Disk2 + $SPItem.Disk3
$DatastoreCluster = Get-DatastoreCluster | Where-Object Name -like ("*" + $SPItem.Cluster + "*")
$ClusterDatastoreWithHighestFreeSpaceGB = ($DatastoreCluster | Get-Datastore | Sort-Object FreeSpaceGB -Descending | Select -First 1)
If ($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB -gt $DiskTotal) {
Write-Verbose ("VM DiskTotal " + $DiskTotal + "GB, will fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)")
}
else {
Write-Verbose ("VM DiskTotal " + $DiskTotal + "GB, will not fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)")
Write-Error ("New VM " + $FQDN + " needs " + $DiskTotal + "GB of free space on a single datastore in the " + $DatastoreCluster.Name + " datastore cluster.") -ErrorAction Stop
}
$FolderLocation = Get-Folder -Server $ViServer -Name "_New Builds"
switch ($SPItem.OS) {
"Windows Server 2012R2 Standard (64-Bit)" { $Template = "Windows Server 2012R2 Standard" }
"Windows Server 2016 Standard (64-Bit)" { $Template = "Windows Server 2016 Standard" }
"Windows Server 2019 Standard (64-Bit)" { $Template = "Windows Server 2019 Standard" }
Default {}
}
$PortGroupsAvailable = Get-VDPortGroup -Server $ViServer -VDSwitch $VirtualSwitch
$PortGroup = $PortGroupsAvailable | Where-Object Name -eq ("dvPG_" + $SPItem.Vlan_Id + "_" + $NetworkId.IPAddressToString + "_" + $SubnetMaskInt)
If (!($PortGroup)) {
Write-Error "Virtual port group not found" -ErrorAction Stop
Stop
}
$NewOSSpecName = ("AutoBuild-$Hostname-" + (Get-Date -UFormat "%Y%m%d%H%M%S"))
Get-OSCustomizationSpec -Name "Windows (Auto)" -Server $ViServer | New-OSCustomizationSpec -Name $NewOSSpecName -Type Persistent
Get-OSCustomizationSpec -Name $NewOSSpecName | `
Set-OSCustomizationSpec `
-NamingScheme fixed `
-NamingPrefix $Hostname `
-AdminPassword $GuestCredentialBB.GetNetworkCredential().Password `
Get-OSCustomizationSpec -Name $NewOSSpecName | `
Get-OSCustomizationNicMapping | `
Set-OSCustomizationNicMapping `
-IpMode UseStaticIP `
-IpAddress $IpAddress.IPAddressToString `
-SubnetMask $SubnetMask.IPAddressToString `
-DefaultGateway $DefaultGateway.IPAddressToString `
-Dns "10.2.7.40", "10.2.5.40"
$OSSpec = Get-OSCustomizationSpec -Name $NewOSSpecName
$NewVMParams = @{
Name = $FQDN;
ResourcePool = $SPItem.Cluster;
Datastore = $DatastoreCluster;
DiskStorageFormat = $DiskStorageFormat;
Template = $Template;
Location = $FolderLocation;
OSCustomizationSpec = $OSSpec;
}
New-VM @NewVMParams
#If (!($BuildError)) {
$VM = Get-VM -Name $FQDN
# Ensure CPU/Memory Hot-Add Enabled
$vmView = $VM | Get-View
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmOptValCPU = New-Object VMware.Vim.OptionValue
$vmOptValMem = New-Object VMware.Vim.OptionValue
$vmOptValCPU.Key = "vcpu.hotadd"
$vmOptValMem.Key = "mem.hotadd"
$vmOptValCPU.Value = "true"
$vmOptValMem.Value = "true"
$vmConfigSpec.ExtraConfig += $vmOptValCPU
$vmConfigSpec.ExtraConfig += $vmOptValMem
$vmView.ReconfigVM($vmConfigSpec)
# Set CPU, Memory, Network
$VM | Set-VM -NumCpu $SPItem.Processors -MemoryGB $SPItem.RAM -Confirm:$false
$VM | Get-NetworkAdapter | Set-NetworkAdapter -Portgroup $PortGroup -Confirm:$false
# Power On VM
$VM | Start-VM
# Wait for Customization to finish
$VMStarted = $false
$VMCustomizationStarted = $false
$VMCustomizationResult = $false
While ($VMStarted -eq $false -or $VMCustomizationStarted -eq $false -or $VMCustomizationResult -eq $false) {
Write-Warning ("Customization wait loop started " + (Get-Date))
Write-Verbose "Current Status:"
Write-Verbose ("VMStarted: " + $VMStarted)
Write-Verbose ("VMCustomizationStarted: " + $VMCustomizationStarted)
Write-Verbose ("VMCustomizationResult: " + $VMCustomizationResult)
$GetVIEventRuntime = Measure-Command -Expression { $VMEvents = Get-VIEvent -Entity $VM -Server $ViServer -ErrorAction SilentlyContinue }
Write-Verbose ("Get-VIEvent last run time: " + $GetVIEventRuntime.TotalSeconds + " seconds")
If ($VMStarted -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "VMStartingEvent" })) {
$VMStarted = $true
Write-Warning "[$FQDN]:Virtual machine started"
}
}
If ($VMCustomizationStarted -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationStartedEvent" })) {
$VMCustomizationStarted = $true
Write-Warning "[$FQDN]:Virtual machine customization started"
}
}
If ($VMCustomizationResult -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationFailed" })) {
$VMCustomizationResult = $true
Write-Error "[$FQDN]:Virtual machine customization failed"
Exit
Exit
}
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationSucceeded" })) {
$VMCustomizationResult = $true
Write-Warning "[$FQDN]:Virtual machine customization completed"
}
}
}
# Delete OS Customization Spec
Get-OSCustomizationSpec -Name $NewOSSpecName | Remove-OSCustomizationSpec -Confirm:$false
# Add/Expand Disks
$VMDisk = $VM | Get-HardDisk
$VMDisk1 = $VMDisk | Where-Object Name -EQ "Hard disk 1"
$VMDisk2 = $VMDisk | Where-Object Name -EQ "Hard disk 2"
$VMDisk3 = $VMDisk | Where-Object Name -EQ "Hard disk 3"
If ($SPItem.Disk1) {
If (!$VMDisk1) {
$VM | New-HardDisk `
-CapacityGB $SPItem.Disk1 `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk1 = $VMDisk | Where-Object Name -EQ "Hard disk 1"
If ($VMDisk1.CapacityGB -lt $SPItem.Disk1) {
Set-HardDisk -HardDisk $VMDisk1 -CapacityGB $SPItem.Disk1 -Confirm:$false
}
}
If ($SPItem.Disk2) {
If (!$VMDisk2) {
$VM | New-HardDisk `
-CapacityGB $SPItem.Disk2 `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk2 = $VMDisk | Where-Object Name -EQ "Hard disk 2"
If ($VMDisk2.CapacityGB -lt $SPItem.Disk2) {
Set-HardDisk -HardDisk $VMDisk2 -CapacityGB $SPItem.Disk2 -Confirm:$false
}
}
If ($SPItem.Disk3) {
If (!$VMDisk3) {
$VM | New-HardDisk `
-CapacityGB $SPItem.Disk3 `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk3 = $VMDisk | Where-Object Name -EQ "Hard disk 3"
If ($VMDisk3.CapacityGB -lt $SPItem.Disk3) {
Set-HardDisk -HardDisk $VMDisk3 -CapacityGB $SPItem.Disk3 -Confirm:$false
}
}
# Run Guest OS code
$InvokeVMScriptFunc = {
}
$VM | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptText $InvokeVMScriptFunc
#}
}
Else {
Write-Error "Runbook must be started from webhook"
}
@@ -0,0 +1,2 @@
"target_platform","target_hostname","target_cpus","target_memory","target_osdisk","target_datadisk","target_subnet","target_os","target_environment","target_vm_app_name","target_datacenter","target_licensingrestrictions"
"VMware","itdzmtest110.nd.gov","1","4","50","20","10.11.12.0/23","Windows Server 2022 Datacenter","Production","ITD-POC-zmeier","Bismarck","No Licensing Restrictions"
1 target_platform target_hostname target_cpus target_memory target_osdisk target_datadisk target_subnet target_os target_environment target_vm_app_name target_datacenter target_licensingrestrictions
2 VMware itdzmtest110.nd.gov 1 4 50 20 10.11.12.0/23 Windows Server 2022 Datacenter Production ITD-POC-zmeier Bismarck No Licensing Restrictions
@@ -0,0 +1,64 @@
$DriveLetter = 'D'
$CsvPath = ($DriveLetter + ":\AutoBuildInputFiles\")
$FailedPath = ($DriveLetter + ":\AutoBuildInputFiles\Failed")
$CompletedPath = ($DriveLetter + ":\AutoBuildInputFiles\Completed")
$GetBuildFile = Get-ChildItem -Path $CsvPath -Filter *.csv | Sort-Object LastWriteTime | select -First 1
#$IaasAutoCred = Get-AutomationPSCredential -Name 'ITD Iaas Automation'
$IaasAutoCred = $PrvCred
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -ParticipateInCeip $false -Confirm:$false -InvalidCertificateAction Ignore
$InputParams = Import-Csv -Path $GetBuildFile.FullName
$ComputerName = $InputParams.target_hostname.ToLower()
Send-MailMessage -From "zmauto@nd.gov" -To "zmeier@nd.gov" -SmtpServer apprelay1.nd.gov -Body $InputParams -Subject ("AutoBuildFromFile-$ComputerName-" + $InputParams.target_platform)
try {
switch ($InputParams.target_platform) {
'azure' {
}
'vmware' {
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $IaasAutoCred
New-ITDVMwareWindowsVM -ComputerName $ComputerName `
-CPU $InputParams.target_cpus `
-MemoryGB $InputParams.target_memory `
-DiskOS $InputParams.target_osdisk `
-DiskData $InputParams.target_datadisk `
-Subnet $InputParams.target_subnet `
-OS $InputParams.target_os `
-Environment $InputParams.target_environment `
-Datacenter $InputParams.target_datacenter `
-AppName $InputParams.target_vm_app_name `
-LicensingRestrictions $InputParams.target_licensingrestrictions `
-Credential $IaasAutoCred `
-Verbose
Move-Item -Path $GetBuildFile.FullName -Destination $CompletedPath
$postParams = [PSCustomObject]@{
AutomationName = "Infra-VMware";
Action = 'Provisioning';
Units = 240;
Platform = 'PowerShell-VMware-VMWindows';
}
Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json)
}
}
}
catch {
$error[0]
Write-Warning "Email vmware admins about failure"
$Body = $error[0] | Select-Object *
Send-MailMessage -From autobuild@nd.gov -To "zmeier@nd.gov" -Subject "Failure-AutoBuildFromFile-$ComputerName" -SmtpServer apprelay.nd.gov -Body $Body
Write-Warning "Error detected. Moving csv input file to folder Failed"
Move-Item -Path $GetBuildFile.FullName -Destination $FailedPath
}
Disconnect-VIServer -Server * -Confirm:$false -ErrorAction SilentlyContinue
@@ -0,0 +1,31 @@
$RestMethodParams = @{
Method = 'Post';
Uri = 'https://96bdfe01-af80-4575-8f23-e7057184c8f6.webhook.cus.azure-automation.net/webhooks?token=4cWZz%2fq97AqMdlNak6qv2lUurLPFsWmPJmovLmAE%2fNg%3d';
Headers = @{ITD = 'mXJU74ABYyDHcVY6iJihPDk8LidJ2ibBA2sA3RAwKaBHS6Gw7Rr2Zz5JZAhPm6wMuvY7X54ZzJxAXaM7ig3PHG4MKvtkBf8X7q3jGNcePgUqg9WCwCSJ3JWG7AA6M39x4vpihKeZV' };
Body = [PSCustomObject]@{
target_platform = "VMware"
target_hostname = 'itdcndsperms.nd.gov';
target_cpus = 1;
target_memory = 8;
target_osdisk = 100;
target_datadisk = 20; # this is now swap
target_subnet = '10.221.8.0/28';
target_os = 'Windows Server 2019 Datacenter';
target_environment = 'Production';
target_vm_app_name = 'Shared-PeopleSoft-State';
target_datacenter = 'Bismarck';
target_licensingrestrictions = 'No Licensing Restrictions';
} | ConvertTo-Json;
}
Invoke-RestMethod @RestMethodParams
$VMNames=@"
itdcndhftdb22.nd.gov
itdcndhhtdb22.nd.gov
"@
$VMNames = ConvertTo-Array -MultiLineString $VMNames
Invoke-Command -ComputerName $VMNames -Credential $PrvCred -ScriptBlock {
Get-Process -Name ccmexec*,cohesity*,cortex*,nessus*,vmtoolsd*
} | sort-object PSComputerName
@@ -0,0 +1,23 @@
#https://96bdfe01-af80-4575-8f23-e7057184c8f6.webhook.cus.azure-automation.net/webhooks?token=4cWZz%2fq97AqMdlNak6qv2lUurLPFsWmPJmovLmAE%2fNg%3d
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[object] $WebhookData
)
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'mXJU74ABYyDHcVY6iJihPDk8LidJ2ibBA2sA3RAwKaBHS6Gw7Rr2Zz5JZAhPm6wMuvY7X54ZzJxAXaM7ig3PHG4MKvtkBf8X7q3jGNcePgUqg9WCwCSJ3JWG7AA6M39x4vpihKeZV') {
Write-Verbose "Header has required data"
Write-Host $
}
Else {
Write-Error "Header missing required data"
exit;
}
$InputParams = (ConvertFrom-Json -InputObject $WebhookData.RequestBody)
$ComputerName = $InputParams.target_hostname.ToLower()
$TimeStamp = Get-Date -UFormat "%Y%m%d%H%M%S"
$InputParams | Export-Csv "E:\AutoBuildInputFiles\$ComputerName-$Timestamp.csv"
}
@@ -0,0 +1,153 @@
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[object]
$WebhookData
)
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'PJaSEgC5HML5ZuZk6wKfZQrpj2XfuQ5svBxbnq2g9M7cQJtFN3iGU4kD4p') {
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
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$VMName = $InputParams.HostName
$Id = $InputParams.Id
$Duration = $InputParams.Duration
$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 -first 1).Name }
switch ($Duration) {
{$Duration -ge 1 -and $Duration -le 7}
{
Write-Verbose "Duration = Snapshot"
$VMSnapshots = $VM | Get-Snapshot | where-object Description -like "AutoSnap_$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*")
}
else {
if (@($VMSnapshots | where-object Description -like "AutoSnap_$Id*").count -gt 1) {
Write-Error "More than one snapshot match found, abort"
Exit
}
else { Write-Verbose "Snapshot Id #$Id match not found on $VMName" }
}
}
{$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 Description -like "AutoClone_$Id*")
}
else {
if (@($VMClones).count -gt 1) {
Write-Error "More than one VM clone match found, abort"
Exit
}
else { Write-Verbose "Clone Id #$Id match not found for $VMName" }
}
}
Default {
Write-Error "Duration less than zero."
}
}
If ($Taken -eq $true) {
write-verbose "Updating SharePoint fields named Status and SnapshotTaken"
$UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$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'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
$RecordToModify = $ListItems | Where-Object Id -eq $InputParams.Id
If (@($RecordToModify).count -gt 1) { Write-Error "More than one record, stopping"; break }
$IDtoModify = $RecordToModify.ID
$UrlItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($IDtoModify)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
Status = 'Taken';
SnapshotTaken = $Task.PrevRunTime;
AutoExpire = ($Task.Description -split '[\r\n]+')[1].split('_')[1];
AutoDelete = ($Task.Description -split '[\r\n]+')[2].split('_')[1];
}
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
Invoke-RestMethod @InvokeWebRequestParams
Disconnect-VIServer * -Confirm:$false -ErrorAction SilentlyContinue
}
}
else {
Write-Error "Runbook must be started from webhook"
}
@@ -0,0 +1,237 @@
# 2021 https://96bdfe01-af80-4575-8f23-e7057184c8f6.webhook.cus.azure-automation.net/webhooks?token=EHlEzPMvDt02gdqMb9wlkdt1FrbmlZjbfQpFTtoIrBc%3d
# content-type application/x-www-form-urlencoded
# 2022 https://96bdfe01-af80-4575-8f23-e7057184c8f6.webhook.cus.azure-automation.net/webhooks?token=%2b6PP2%2bd3FDLqb4bgMs%2b4V1%2bDAMw0tPxN%2f4Ee0eWMa5Q%3d
#
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[object] $WebhookData
)
function Get-ITDVMwareSharePointSnapshotRequestList {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
$InvokeWebRequestParams = @{ }
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "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,Status,NotifyEmail&$expand=Author/Id'
$InvokeWebRequestParams += @{
Uri = $URL
Method = "Get"
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
$List = (Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
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
$UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$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'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
$SPListItem = $ListItems | Where-object Id -eq $InputParams.Id
If ($SPListItem.Title -ne $InputParams.HostName) {
Write-Error ("Web request JSON does not match SharePoint Record for SPListItem.Hostname " + $SPListItem.HostName + " and InputParams.Hostname " + $InputParams.Hostname)
Exit
}
$VMName = $InputParams.HostName
$SnapTime = [DateTime]$SPListItem.DateTime
$NotifyEmail = $SPListItem.Author.Email
If ($SPListItem.NotifyEmail) { $NotifyEmail = $NotifyEmail + ',' + $SPListItem.NotifyEmail }
$tryCount = 0
#while ($tryCount -lt 5) {
try {
$tryCount++
$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 = "AutoSnap_" + $InputParams.ID + "`r" + "AutoExpire_$SnapExpireDateTime" + "`r" + "AutoDelete_$SnapDeleteDateTime"
$SnapDescription = "AutoSnap_" + 1080 + "`r" + "AutoExpire_$SnapExpireDateTime" + "`r" + "AutoDelete_$SnapDeleteDateTime"
$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)
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$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]
$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
}
# prep for update SharePoint record status
$RecordToModify = $ListItems | Where-Object Id -eq $InputParams.Id
If (@($RecordToModify).count -gt 1) { Write-Error "More than one result, stopping"; Exit }
$IDtoModify = $RecordToModify.ID
$UrlItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($IDtoModify)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
If ($Credential) { $InvokeWebRequestParams += @{Credential = $SharePointCredential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
# Create vCenter scheduled task
$scheduledTaskManager.CreateObjectScheduledTask($vm.ExtensionData.MoRef, $spec)
Start-Sleep -Seconds 3
}<#
catch [System.Management.Automation.MethodInvocationException] {
If ($tryCount -lt 4) {
If ($Error[1].Exception -like "*You have attempted to schedule the scheduler at a time*in the past*") {
Write-Warning ((Get-Date))# + ": Attempted schedule in past @ $SnapTime, trying again")
}
write-warning $trycount
}
Else {
write-error "vCenter Snapshot 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
}
}#>
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
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential
}
Invoke-RestMethod @InvokeWebRequestParams
$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)
Disconnect-VIServer -Server * -Confirm:$false -ErrorAction SilentlyContinue
}
Else {
Write-Error "Runbook must be started from webhook"
}
@@ -0,0 +1,153 @@
[CmdletBinding()]
param
(
)
$StartTime = Get-Date
function Get-ITDVMwareSharePointSnapshotRequestList {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "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,Status,NotifyEmail,AutoExpire,AutoDelete&$expand=Author/Id'
$InvokeWebRequestParams += @{
Uri = $URL;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
$List = (Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
$vCenterCredential = Get-AutomationPSCredential -Name 'VMware Auto'
$SharePointCredential = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite'
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -ParticipateInCeip $false -Confirm:$false
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$SnapshotList = Get-ITDVMwareSharePointSnapshotRequestList -Credential $SharePointCredential
$ListToRemove = $SnapshotList | Where-Object { $_.Status -eq "Expired, Delete Approved" } | Sort-Object AutoDelete
ForEach ($SPRecord in $ListToRemove) {
$Id = $null
$VMName = $null
$SnapName = $null
$Id = $SPRecord.ID
$VMName = $SPRecord.Title
$SnapName = "AutoSnap_" + $Id
$SnapshotToRemove = Get-Snapshot -Name $SnapName -VM $VMName
$Datastore = Get-VM $VMName | Get-Datastore
$ViServer = $SnapshotToRemove.uid.split('@')[1].split(':')[0]
Write-Warning ($SnapshotToRemove.Name + " for " + $SnapshotToRemove.VM + " on " + $Datastore + " on " + $ViServer)
try {
$SnapshotTaskCount = @(Get-Task -Server $ViServer | Where-Object { $_.Name -eq "RemoveSnapshot_Task" -and $_.State -eq "Running" }).count
Write-Warning $SnapshotTaskCount
while ($SnapshotTaskCount -ge 1) {
$timestamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Write-Warning "[$timestamp]:$SnapshotTaskCount RemoveSnapshot_Task already running, pausing 60 seconds."
Start-Sleep -Seconds 60
$timestamp = $null
$SnapshotTaskCount = @(Get-Task | Where-Object { $_.Name -eq "RemoveSnapshot_Task" -and $_.State -eq "Running" }).count
Write-Warning $SnapshotTaskCount
}
$timestamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Write-Warning "[$timestamp]:$SnapshotTaskCount RemoveSnapshot_Task already running, starting removal."
$SnapshotToRemove | Remove-Snapshot -Confirm:$false
}
catch {
Write-Error "Snapshot Removal failed";
Write-Error $Error[1];
exit
}
#update SharePoint field
Write-Verbose "Exactly one match found, updating SharePoint fields named Status and SnapshotTaken"
$UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$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'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -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)"
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
Status = 'Removed';
SnapshotRemoved = [datetime](Get-Date);
}
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
Invoke-RestMethod @InvokeWebRequestParams
}
Disconnect-VIServer -Server * -Confirm:$false -ErrorAction SilentlyContinue
$DiffTime = [math]::round((4+((Get-Date) - $StartTime).Minutes),0)
$postParams = [PSCustomObject]@{
AutomationName = "Infra-VMware";
Action = 'Deprovisioning';
Units = $DiffTime;
Platform = 'PowerShell-VMware-SnapshotRemove';
}
Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json)
@@ -0,0 +1,202 @@
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[object]
$WebhookData
)
function Get-ITDVMwareSharePointSnapshotRequestList {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
$InvokeWebRequestParams = @{ }
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "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,Status,NotifyEmail,AutoExpire,AutoDelete&$expand=Author/Id'
$InvokeWebRequestParams += @{
Uri = $URL;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
$List = (Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
$vCenterCredential = Get-AutomationPSCredential -Name 'VMware Auto'
$SharePointCredential = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite'
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -ParticipateInCeip $false -Confirm:$false
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$SnapshotList = Get-ITDVMwareSharePointSnapshotRequestList -Credential $SharePointCredential
$ListToUpdate = $SnapshotList | where-object { $_.Status -eq "Scheduled" } | Sort-Object DateTime
#$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 -first 1).Name }
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*"
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*")
}
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 Description -like "AutoClone_$Id*")
}
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"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$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'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -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)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
#Status = 'Taken';
Status = If ($Taken -eq $true) {'Taken'} Else {'Errored'};
SnapshotTaken = $Task.PrevRunTime;
AutoExpire = ($Task.Description -split '[\r\n]+')[1].split('_')[1];
AutoDelete = ($Task.Description -split '[\r\n]+')[2].split('_')[1];
}
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
Invoke-RestMethod @InvokeWebRequestParams
}
}
$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)
Disconnect-VIServer * -Confirm:$false -ErrorAction SilentlyContinue
@@ -0,0 +1,6 @@
[
{
"Id": "575",
"Hostname":"itdfmauditp1.nd.gov"
}
]
@@ -0,0 +1,11 @@
{
"WebhookName": "rh-VMware-UpdateVMSnapshotStatus-prd",
"RequestBody": "[\n {\n \"Id\": \"68\",\n \"HostName\": \"itddeqappt1.nd.gov\",\n \"DateTime\": \"2/5/2020 7:00 PM\",\n \"Duration\": \"8\",\n \"NotifyEmail\": \"\"\n }\n]",
"RequestHeader": {
"Connection": "Close",
"Expect": "100-continue",
"Host": "s25events.azure-automation.net",
"ITD": "PJaSEgC5HML5ZuZk6wKfZQrpj2XfuQ5svBxbnq2g9M7cQJtFN3iGU4kD4p",
"x-ms-request-id": "5ee3253c-5bb4-4aea-a950-6149ddb0436e"
}
}
@@ -0,0 +1,168 @@
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[object] $WebhookData
)
function Get-ITDVMwareSharePointSnapshotRequestList {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
$InvokeWebRequestParams = @{ }
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "https://testshare.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,Status,NotifyEmail&$expand=Author/Id'
$InvokeWebRequestParams += @{
Uri = $URL;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
$List = (Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'w3gVRLEq2Yi7yzWW8fpKNCPTKqtHssnNGBref5BDtxXkr3mZA3NB5gUcnHfr9sdhXC53y7gWHAKpueFYU4L3NMXV7DszCWy63znqPGh3AJ2bn43uP7GjzfLcgqYLQRkirpR3kjiLgi3FpRPgUWus9Zx') {
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
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$Id = $InputParams.Id
$VMName = $InputParams.Hostname
$SnapshotList = Get-ITDVMwareSharePointSnapshotRequestList -Credential $SharePointCredential
$Request = $SnapshotList | where-object ID -eq $id
$SnapName = "AutoSnap_" + $Id
$SnapshotToRemove = Get-Snapshot -Name $SnapName -VM $VMName
$Datastore = Get-VM $VMName | Get-Datastore
$ViServer = $SnapshotToRemove.uid.split('@')[1].split(':')[0]
write-warning ($SnapshotToRemove.Name + " for " + $SnapshotToRemove.VM + " on " + $Datastore + " on " + $ViServer)
#try {
$SnapshotTaskCount = @(Get-Task -Server $ViServer | Where-Object {$_.Name -eq "RemoveSnapshot_Task" -and $_.State -eq "Running"}).count
write-warning $SnapshotTaskCount
while ($SnapshotTaskCount -ge 1) {
$timestamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Write-Warning "[$timestamp]:$SnapshotTaskCount RemoveSnapshot_Task already running, pausing 60 seconds."
Start-Sleep -Seconds 60
$timestamp = $null
$SnapshotTaskCount = @(Get-Task | Where-Object {$_.Name -eq "RemoveSnapshot_Task" -and $_.State -eq "Running"}).count
write-warning $SnapshotTaskCount
}
$timestamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Write-Warning "[$timestamp]:$SnapshotTaskCount RemoveSnapshot_Task already running, starting removal."
$SnapshotToRemove | Remove-Snapshot -Confirm:$false -RunAsync
<#}
catch {
Write-Error "Snapshot Removal failed";
Write-Error $Error[1];
exit
}#>
#update SharePoint field
Write-Verbose "Exactly one match found, updating SharePoint fields named Status and SnapshotTaken"
$UrlContextInfo = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
$RecordToModify = $ListItems | Where-Object Id -eq $InputParams.Id
If (@($RecordToModify).count -gt 1) { Write-Error "More than one result, stopping"; break }
$IDtoModify = $RecordToModify.ID
$UrlItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($IDtoModify)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
Status = 'Removed';
SnapshotRemoved = [datetime](Get-Date);
}
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
Invoke-RestMethod @InvokeWebRequestParams
Disconnect-VIServer -Server * -Confirm:$false
}
Else {
Write-Error "Runbook must be started from webhook"
}
@@ -0,0 +1,128 @@
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[object]
$WebhookData
)
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'vBxbnq2g9M7cQJtFN3iGU4kD4pPJaSEgC5HML5ZuZk6wKfZQrpj2XfuQ5s') {
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
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$VMName = $InputParams.HostName
$Id = $InputParams.Id
$Duration = $InputParams.Duration
#$VM = Get-VM -Name $VMName | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
Write-Verbose "Duration = Clone"
$VMClones = Get-VM | Where-Object Name -eq ($VMName + "_AutoClone_" + $Id)
If (@($VMClones).count -eq 1) {
$Taken = $true
$VMClone = $VMClones
}
else {
if (@($VMClones).count -gt 1) {
Write-Error "More than one VM clone match found, abort"
Exit
}
else { Write-Verbose "Clone Id #$Id match not found for $VMName" }
}
If (@($VMClones).count -eq 1) {
$VMClone = $VMClones
Write-Verbose "Exactly one clone match found, updating SharePoint fields named Status and SnapshotTaken"
$Task = ((Get-View ((Get-View ScheduledTaskManager).ScheduledTask)).info | where-object Description -like "AutoClone_$Id*")
If ($Taken -eq $true) {
$UrlContextInfo = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
$RecordToModify = $ListItems | Where-Object Id -eq $Id
If (@($RecordToModify).count -gt 1) { Write-Error "More than one record, stopping"; break }
$IDtoModify = $RecordToModify.ID
$UrlItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($IDtoModify)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
Status = 'Taken';
SnapshotTaken = $Task.PrevRunTime;
AutoExpire = ($Task.Description -split '[\r\n]+')[1].split('_')[1];
AutoDelete = ($Task.Description -split '[\r\n]+')[2].split('_')[1];
}
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
Invoke-RestMethod @InvokeWebRequestParams
Disconnect-VIServer * -Confirm:$false
}
}
}
else {
Write-Error "Runbook must be started from webhook"
}
@@ -0,0 +1,127 @@
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[object]
$WebhookData
)
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'vBxbnq2g9M7cQJtFN3iGU4kD4pPJaSEgC5HML5ZuZk6wKfZQrpj2XfuQ5s') {
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
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$VMName = $InputParams.HostName
$Id = $InputParams.Id
$Duration = $InputParams.Duration
$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 -first 1).Name }
Write-Verbose "Duration = Snapshot"
$VMSnapshots = $VM | Get-Snapshot | where-object Description -like "AutoSnap_$Id*"
If (@($VMSnapshots).count -eq 1) {
$Taken = $true
$VMSnapshot = $VMSnapshots
}
else {
if (@($VMSnapshots | where-object Description -like "AutoSnap_$Id*").count -gt 1) {
Write-Error "More than one snapshot match found, abort"
Exit
}
else { Write-Verbose "Snapshot Id #$Id match not found on $VMName" }
}
If (@($VMSnapshots).count -eq 1) {
Write-Verbose "Exactly one snapshot match found, updating SharePoint fields named Status and SnapshotTaken"
If ($Taken -eq $true) {
$UrlContextInfo = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
$RecordToModify = $ListItems | Where-Object Id -eq $InputParams.Id
If (@($RecordToModify).count -gt 1) { Write-Error "More than one record, stopping"; break }
$IDtoModify = $RecordToModify.ID
$UrlItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($IDtoModify)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
Status = 'Taken';
SnapshotTaken = $VMSnapshot.Created;
AutoExpire = ($VMSnapshot.Description -split '[\r\n]+')[1].split('_')[1];
AutoDelete = ($VMSnapshot.Description -split '[\r\n]+')[2].split('_')[1];
}
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
Invoke-RestMethod @InvokeWebRequestParams
Disconnect-VIServer * -Confirm:$false
}
}
}
else {
Write-Error "Runbook must be started from webhook"
}
@@ -0,0 +1,216 @@
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[object] $WebhookData
)
function Get-ITDVMwareSharePointSnapshotRequestList {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
$InvokeWebRequestParams = @{ }
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "https://testshare.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,Status,NotifyEmail&$expand=Author/Id'
$InvokeWebRequestParams += @{
Uri = $URL
Method = "Get"
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
$List = (Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'HAKpueFYU4L3NMXTKqtHssnNGBrew3gVRLEq2Yi7yzWW8fpKNCPB5gUcnHfr9sdhXC53y7gWf5BDtxXkr3mZA3NV7DszpR3kjiLgi3FpRPgUWus9ZxCWy63znqPGh3AJ2bn43uP7GjzfLcgqYLQRkir') {
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
$UrlContextInfo = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List2 = Invoke-RestMethod @InvokeWebRequestParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://testshare.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'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
$SPListItem = $ListItems | Where-object Id -eq $InputParams.Id
If ($SPListItem.Title -ne $InputParams.HostName) {
Write-Error ("Web request JSON does not match SharePoint Record for SPListItem.Hostname " + $SPListItem.HostName + " and InputParams.Hostname " + $InputParams.Hostname)
Exit
}
$VMName = $InputParams.HostName
$SnapTime = ([DateTime]$SPListItem.DateTime).AddMinutes($Duration * 3)
$NotifyEmail = $SPListItem.Author.Email
If ($SPListItem.NotifyEmail) { $NotifyEmail = $NotifyEmail + ',' + $SPListItem.NotifyEmail }
$tryCount = 0
# while ($tryCount -lt 5) {
try {
$tryCount++
Write-Warning ("SharePoint: " + $SnapTime)
If ($SnapTime -lt (Get-Date)) {
$SnapTime = (Get-Date).AddSeconds(30)
}
Write-Warning ("PowerShell: " + $SnapTime)
$SnapName = "AutoSnap_" + $SPListItem.ID
$SnapExpireDateTime = $SnapTime.AddMinutes($SPListItem.Duration * 3)
$SnapDeleteDateTime = $SnapExpireDateTime.AddMinutes(30)
$SnapDescription = "AutoSnap_" + $InputParams.ID + "`r" + "AutoExpire_$SnapExpireDateTime" + "`r" + "AutoDelete_$SnapDeleteDateTime"
$snapMemory = $false
$snapQuiesce = $false
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$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]
$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
}
# prep for update SharePoint record status
$RecordToModify = $ListItems | Where-Object Id -eq $InputParams.Id
If (@($RecordToModify).count -gt 1) { Write-Error "More than one result, stopping"; Exit }
$IDtoModify = $RecordToModify.ID
$UrlItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($IDtoModify)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
If ($Credential) { $InvokeWebRequestParams += @{Credential = $SharePointCredential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
# Create vCenter scheduled task
$scheduledTaskManager.CreateObjectScheduledTask($vm.ExtensionData.MoRef, $spec)
Start-Sleep -Seconds 3
}
catch [System.Management.Automation.MethodInvocationException] {
If ($tryCount -lt 4) {
If ($Error[1].Exception -like "*You have attempted to schedule the scheduler at a time*in the past*") {
Write-Warning ((Get-Date))# + ": Attempted schedule in past @ $SnapTime, trying again")
}
write-warning $trycount
}
Else {
write-error "vCenter Snapshot 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
}
}
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
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential
}
Invoke-RestMethod @InvokeWebRequestParams
Disconnect-VIServer -Server * -Confirm:$false
}
Else {
Write-Error "Runbook must be started from webhook"
}
@@ -0,0 +1,164 @@
[CmdletBinding()]
param
(
)
function Get-ITDVMwareSharePointSnapshotRequestList {
[CmdletBinding()]
Param
(
[PSCredential]
$Credential
)
begin {
$InvokeWebRequestParams = @{ }
If ($Credential) { $InvokeWebRequestParams += @{Credential = $Credential } }
Else { $InvokeWebRequestParams += @{UseDefaultCredentials = $true } }
$URL = "https://testshare.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,Status,NotifyEmail,AutoExpire,AutoDelete&$expand=Author/Id'
$InvokeWebRequestParams += @{
Uri = $URL;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" }
}
$List = (Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json
}
process {
}
end {
$List.d.results
}
}
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'w3gVRLEq2Yi7yzWW8fpKNCPTKqtHssnNGBref5BDtxXkr3mZA3NB5gUcnHfr9sdhXC53y7gWHAKpueFYU4L3NMXV7DszCWy63znqPGh3AJ2bn43uP7GjzfLcgqYLQRkirpR3kjiLgi3FpRPgUWus9Zx') {
Write-Verbose "Header has required data"
}
Else {
Write-Error "Header missing required data"
exit;
}
$vCenterCredential = Get-AutomationPSCredential -Name 'VMware Auto'
$SharePointCredential = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite'
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -ParticipateInCeip $false -Confirm:$false
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$SnapshotList = Get-ITDVMwareSharePointSnapshotRequestList -Credential $SharePointCredential
$ListToRemove = $SnapshotList | where-object { $_.Status -eq "Expired, Delete Approved" } | Sort-Object AutoDelete
ForEach ($SPRecord in $ListToRemove) {
$Id = $null
$VMName = $null
$SnapName = $null
$Id = $SPRecord.ID
$VMName = $SPRecord.Title
$SnapName = "AutoSnap_" + $Id
$SnapshotToRemove = Get-Snapshot -Name $SnapName -VM $VMName
$Datastore = Get-VM $VMName | Get-Datastore
$ViServer = $SnapshotToRemove.uid.split('@')[1].split(':')[0]
Write-Warning ($SnapshotToRemove.Name + " for " + $SnapshotToRemove.VM + " on " + $Datastore + " on " + $ViServer)
try {
$SnapshotTaskCount = @(Get-Task -Server $ViServer | Where-Object { $_.Name -eq "RemoveSnapshot_Task" -and $_.State -eq "Running" }).count
Write-Warning $SnapshotTaskCount
while ($SnapshotTaskCount -ge 1) {
$timestamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Write-Warning "[$timestamp]:$SnapshotTaskCount RemoveSnapshot_Task already running, pausing 60 seconds."
Start-Sleep -Seconds 60
$timestamp = $null
$SnapshotTaskCount = @(Get-Task | Where-Object { $_.Name -eq "RemoveSnapshot_Task" -and $_.State -eq "Running" }).count
Write-Warning $SnapshotTaskCount
}
$timestamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Write-Warning "[$timestamp]:$SnapshotTaskCount RemoveSnapshot_Task already running, starting removal."
$SnapshotToRemove | Remove-Snapshot -Confirm:$false
}
catch {
Write-Error "Snapshot Removal failed";
Write-Error $Error[1];
exit
}
#update SharePoint field
Write-Verbose "Exactly one match found, updating SharePoint fields named Status and SnapshotTaken"
$UrlContextInfo = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
#$RecordToModify = $ListItems | Where-Object Id -eq $InputParams.Id
#If (@($RecordToModify).count -gt 1) { Write-Error "More than one result, stopping"; break }
#$IDtoModify = $RecordToModify.ID
$UrlItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($Id)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
Status = 'Removed';
SnapshotRemoved = [datetime](Get-Date);
}
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
Invoke-RestMethod @InvokeWebRequestParams
}
Disconnect-VIServer -Server * -Confirm:$false
}
@@ -0,0 +1,153 @@
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[object]
$WebhookData
)
If ($WebhookData) {
If ($WebhookData.RequestHeader.ITD -eq 'vBxbnq2g9M7cQJtFN3iGU4kD4pPJaSEgC5HML5ZuZk6wKfZQrpj2XfuQ5s') {
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
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential
$VMName = $InputParams.HostName
$Id = $InputParams.Id
$Duration = $InputParams.Duration
$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 -first 1).Name }
switch ($Duration) {
{$Duration -ge 1 -and $Duration -le 7}
{
Write-Verbose "Duration = Snapshot"
$VMSnapshots = $VM | Get-Snapshot | where-object Description -like "AutoSnap_$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*")
}
else {
if (@($VMSnapshots | where-object Description -like "AutoSnap_$Id*").count -gt 1) {
Write-Error "More than one snapshot match found, abort"
Exit
}
else { Write-Verbose "Snapshot Id #$Id match not found on $VMName" }
}
}
{$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 Description -like "AutoClone_$Id*")
}
else {
if (@($VMClones).count -gt 1) {
Write-Error "More than one VM clone match found, abort"
Exit
}
else { Write-Verbose "Clone Id #$Id match not found for $VMName" }
}
}
Default {
Write-Error "Duration less than zero."
}
}
If ($Taken -eq $true) {
write-verbose "Updating SharePoint fields named Status and SnapshotTaken"
$UrlContextInfo = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo"
$InvokeWebRequestParams = @{
Uri = $UrlContextInfo;
Method = "Post";
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$RequestDigest = Invoke-RestMethod @InvokeWebRequestParams
$RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue
$UrlList = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')"
$InvokeWebRequestParams = @{
Uri = $UrlList;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
$List = Invoke-RestMethod @InvokeWebRequestParams
$ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName
$UrlListItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000'
$InvokeWebRequestParams = @{
Uri = $UrlListItem;
Method = "Get";
UseBasicParsing = $true;
Headers = @{ "Accept" = "application/json;odata=verbose" };
Credential = $SharePointCredential
}
$ListItems = ((Invoke-WebRequest @InvokeWebRequestParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results
$header = @{
"accept" = "application/json;odata=verbose"
"X-RequestDigest" = $RequestDigest
"IF-MATCH" = '*'
"X-HTTP-Method" = "MERGE"
}
$RecordToModify = $ListItems | Where-Object Id -eq $InputParams.Id
If (@($RecordToModify).count -gt 1) { Write-Error "More than one record, stopping"; break }
$IDtoModify = $RecordToModify.ID
$UrlItem = "https://testshare.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($IDtoModify)"
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Get";
Headers = @{ "Accept" = "application/json;odata=verbose" }
UseBasicParsing = $true;
Credential = $SharePointCredential
}
[PSCustomObject]$SetRecord = @{
"__metadata" = @{type = $ListItemEntityTypeFullName };
Status = 'Taken';
SnapshotTaken = $Task.PrevRunTime;
AutoExpire = ($Task.Description -split '[\r\n]+')[1].split('_')[1];
AutoDelete = ($Task.Description -split '[\r\n]+')[2].split('_')[1];
}
$body = $SetRecord | ConvertTo-Json
$InvokeWebRequestParams = @{
Uri = $UrlItem;
Method = "Post";
Body = $body;
ContentType = "application/json;odata=verbose";
Headers = $header;
UseBasicParsing = $true;
Credential = $SharePointCredential;
}
Invoke-RestMethod @InvokeWebRequestParams
Disconnect-VIServer * -Confirm:$false
}
}
else {
Write-Error "Runbook must be started from webhook"
}
@@ -0,0 +1,8 @@
[
{
"Id": "{ItemProperty:ID}",
"HostName": "{ItemProperty:HostName}",
"DateTime": "{ItemProperty:DateTime}",
"Duration": "{ItemProperty:Duration}"
}
]
@@ -0,0 +1,6 @@
[
{
"Id": "566",
"HostName": "itdscmt1.nd.gov"
}
]
@@ -0,0 +1,655 @@
function Import-ITDVMwareSRMExport {
[CmdletBinding()]
Param
(
[string]
$Path
)
begin {
}
process {
[xml]$Global:SrmXml = Get-Content -Path $Path
}
end {
}
}
function Get-ITDVMwareSRMDatacenter {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name
)
begin {
}
process {
switch ($PsCmdlet.ParameterSetName) {
'Id' {
ForEach ($i in $Id) {
((($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter | Where-Object id -EQ $i)
}
}
'Name' {
ForEach ($n in $Name) {
((($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter | Where-Object name -Like "*$n*")
}
}
'Default' {
((($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter )
}
}
}
end {
}
}
function Get-ITDVMwareSRMVMFolder {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name
)
begin {
}
process {
$VMInventoryFolders = (($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.vmFolder.InventoryFolder + (($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.vmFolder.InventoryFolder.InventoryFolder
switch ($PsCmdlet.ParameterSetName) {
'Id' {
ForEach ($i in $Id) {
$VMInventoryFolders | Where-Object id -Like "*$i*"
}
}
'Name' {
ForEach ($n in $Name) {
$VMInventoryFolders | Where-Object name -Like "*$n*"
}
}
'Default' {
$VMInventoryFolders
}
}
}
end {
}
}
function Get-ITDVMwareSRMHostFolder {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name
)
begin {
}
process {
switch ($PsCmdlet.ParameterSetName) {
'Id' {
Foreach ($i in $Id) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder | Where-Object id -EQ $i
}
}
'Name' {
Foreach ($i in $Id) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder | Where-Object name -Like "*$n*"
}
}
'Default' {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder
}
}
}
end {
}
}
function Get-ITDVMwareSRMComputeResource {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'ResPoolId')]
[string[]]
$ResPoolId,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name
)
begin {
}
process {
switch ($PsCmdlet.ParameterSetName) {
'Id' {
ForEach ($i in $Id) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder.ComputeResource | Where-Object { $_.id -like "*$i*" }
}
}
'ResPoolId' {
ForEach ($i in $ResPoolId) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder.ComputeResource | Where-Object { $_.resourcepool.id -like "*$i*" }
}
}
'Name' {
If ($Name) {
ForEach ($n in $Name) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder.ComputeResource | Where-Object { $_.name -like "*$n*" }
}
}
Else {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder.ComputeResource
}
}
'Default' {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder.ComputeResource
}
}
}
end {
}
}
function Get-ITDVMwareSRMVMHost {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name
)
begin {
}
process {
switch ($PsCmdlet.ParameterSetName) {
'Id' {
ForEach ($i in $Id) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder.ComputeResource.hosts | Where-Object { $_.id -like "*$i*" }
}
}
'Name' {
ForEach ($n in $Name) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder.ComputeResource.hosts | Where-Object { $_.name -like "*$n*" }
}
}
'Default' {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.hostFolder.ComputeResource.hosts
}
}
}
end {
}
}
function Get-ITDVMwareSRMDatastore {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name
)
begin {
}
process {
switch ($PsCmdlet.ParameterSetName) {
'Id' {
ForEach ($i in $Id) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.datastore | Where-Object id -Like "*$i*"
}
}
'Name' {
ForEach ($n in $Name) {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.datastore | Where-Object { $_.name -like "*$n*" }
}
}
'Default' {
(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.datastore
}
}
}
end {
}
}
function Get-ITDVMwareSRMNetwork {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name
)
begin {
}
process {
$dvportgrouplist = (($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.NetworkFolder.InventoryFolder.DistributedVirtualPortgroup
switch ($PsCmdlet.ParameterSetName) {
'Id' {
ForEach ($i in $Id) {
#(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.NetworkFolder.InventoryFolder.DistributedVirtualPortgroup | Where-Object { $_.id -eq "*$i*" }
$dvportgrouplist | where-object id -eq $i
}
}
'Name' {
ForEach ($n in $Name) {
#(($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.NetworkFolder.InventoryFolder.DistributedVirtualPortgroup | Where-Object { $_.name -eq "*$n*" }
$dvportgrouplist | where-object name -eq $n
}
}
'Default' {
$dvportgrouplist
}
}
}
end {
}
}
function Get-ITDVMwareSRMVM {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name
)
begin {
}
process {
$VMInventory = (($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.vmFolder.InventoryFolder.VirtualMachine + (($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ Inventory).Attributes.InventoryTree).root.datacenter.vmFolder.InventoryFolder.InventoryFolder.VirtualMachine
switch ($PsCmdlet.ParameterSetName) {
'Id' {
ForEach ($i in $Id) {
$VMInventory | Where-Object { $_.id -like "*$i*" }
}
}
'Name' {
ForEach ($n in $Name) {
$VMInventory | Where-Object { $_.name -like "*$n*" }
}
}
<#'Default' {
$VMInventory
}#>
}
}
end {
}
}
function Get-ITDVMwareSRMProtectionGroup {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[Parameter(ParameterSetName = 'Name')]
[string[]]
$Name,
[switch]
$Detailed,
[ValidateScript( { $Detailed -eq $true })]
[switch]
$Formatted
)
begin {
}
process {
$ProtectionGroups = ($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ "ProtectionGroups").Attributes.Folder.vmProtectionGroup
switch ($PsCmdlet.ParameterSetName) {
'Id' {
$ProtectionGroupsSearch = $Id | ForEach-Object {
$ProtectionGroups | Where-Object Id -Like "*$_*"
}
}
'Name' {
$ProtectionGroupsSearch = $Name | ForEach-Object {
$ProtectionGroups | Where-Object Name -Like "*$_*"
}
}
'Default' {
$ProtectionGroupsSearch = $ProtectionGroups
}
}
$AllVrDatastores = Get-ChildItem -Path "vmstores:\itdvmvc2.nd.gov@443\Secondary Datacenter\" | Where-Object Name -Like "*_VR*"
$VrFolders = $AllVrDatastores | Get-ChildItem | Where-Object ItemType -EQ "Folder"
If ($Detailed) {
$DetailedResult = [System.Collections.ArrayList]@()
ForEach ($ProtectionGroup in $ProtectionGroupsSearch) {
Write-Warning -Message ("Start Protection Group Loop for " + $ProtectionGroup.Name.TrimStart().TrimEnd() )
$AbrDatastores = $null
If ($ProtectionGroup.datastores) {
$AbrDatastores = Get-ITDVMwareSRMDatastore -Id ($ProtectionGroup.datastores | select -Unique).TrimStart().TrimEnd()
}
Else {
$AbrDatastores = $null
}
$VMs = (Get-ITDVMwareSRMVM -Id ($ProtectionGroup.ProtectionProperties.id)).Name
$VrDatastores = [System.Collections.ArrayList]@()
ForEach ($VM in $VMs) {
$null = $VRDatastores.add( ($VRFolders | Where-Object Name -Like "$VM*").Datastore)
}
$VrDatastores = $VRDatastores | Select-Object -Unique Name
$PGobj = [PSCustomObject]@{
Name = $ProtectionGroup.Name.TrimStart().TrimEnd();
ReplicationType = $ProtectionGroup.ReplicationProviderType.TrimStart().TrimEnd();
ArrayPairKey = ( $ProtectionGroup.arrayPairKey | ForEach-Object { If ($_.GetType().Name -eq 'String') { $_.TrimStart().TrimEnd() } } | Select-Object -Unique )
Folder = ( Get-ITDVMwareSRMVMFolder -Id ($ProtectionGroup.ProtectionProperties.folder | select -Unique).TrimStart().TrimEnd() ).Name.TrimStart().TrimEnd();
ResourceGroup = ( Get-ITDVMwareSRMComputeResource -ResPoolId ($ProtectionGroup.ProtectionProperties.resourceGroup | select -Unique).TrimStart().TrimEnd() ).Name.TrimStart().TrimEnd();
Network = ( Get-ITDVMwareSRMNetwork -Id ($ProtectionGroup.ProtectionProperties.RecoveryLocationSettings.DeviceInfo.NetworkDeviceBacking.network | select -Unique).TrimStart().TrimEnd() ).Name.TrimStart().TrimEnd();
AbrDatastores = If ($AbrDatastores -ne $null) { ($AbrDatastores.name.TrimStart().TrimEnd() ) };
VrDatastores = $VrDatastores.Name | Select-Object -Unique
VM = ( Get-ITDVMwareSRMVM -Id ($ProtectionGroup.ProtectionProperties.id.TrimStart().TrimEnd()) ).Name.TrimStart().TrimEnd();
}
$null = $DetailedResult.add($PGobj)
}
If ($Formatted) {
$FormattedResult = $DetailedResult | select Name, ReplicationType, ArrayPairKey, `
@{n = 'Folder'; e = { ($_.Folder | Sort-Object | Out-String).TrimEnd() } }, `
@{n = "ResourceGroup"; e = { ($_.ResourceGroup | Sort-Object | Out-String).TrimEnd() } }, `
@{n = "Network"; e = { ($_.Network | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'AbrDatastores'; e = { ($_.AbrDatastores | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'VrDatastores'; e = { ($_.VrDatastores | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'VM'; e = { ($_.VM | Sort-Object | Out-String).TrimEnd() } }
}
}
}
end {
switch ($PsCmdlet.ParameterSetName) {
'Id' {
If ($Detailed) {
If ($Formatted) {
Write-Output $FormattedResult
}
else {
Write-Output $DetailedResult
}
}
Else {
Write-Output $ProtectionGroupsSearch
}
}
'Name' {
If ($Detailed) {
If ($Formatted) {
Write-Output $FormattedResult
}
else {
Write-Output $DetailedResult
}
}
Else {
Write-Output $ProtectionGroupsSearch
}
}
'Default' {
If ($Detailed) {
If ($Formatted) {
Write-Output $FormattedResult
}
else {
Write-Output $DetailedResult
}
}
Else {
Write-Output $ProtectionGroups
}
}
}
}
}
function Get-ITDVMwareSRMVMSettings {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName = 'Id')]
[string[]]
$Id,
[CmdletBinding(DefaultParameterSetName = 'Default')]
[switch]
$Detailed
)
begin {
}
process {
switch ($PsCmdlet.ParameterSetName) {
'Id' {
$VMSettingsSearch = $Id | ForEach-Object {
($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ VMSettings).Attributes.VMSettings | Where-Object Id -Like "*$_*"
}
}
'Default' {
$VMSettingsSearch = ($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ VMSettings).Attributes.VMSettings
}
}
If ($Detailed) {
$DetailedResult = [System.Collections.ArrayList]@()
ForEach ($VMSetting in $VMSettingsSearch) {
$VMSettingObj = [PSCustomObject]@{
Id = $VMSetting.id.TrimStart().TrimEnd();
Name = (Get-ITDVMwareSRMVM -Id $VMSetting.Id.TrimStart().TrimEnd()).Name.TrimStart().TrimEnd();
#recoveryPriority = $VMSetting.recoveryPriority;
recoveryPriorityGui = switch ($VMSetting.recoveryPriority.TrimStart().TrimEnd()) {
25 { 1 }
40 { 2 }
50 { 3 }
60 { 4 }
75 { 5 }
}
}
$null = $DetailedResult.add($VMSettingObj)
}
}
}
end {
If ($Detailed) {
Write-Output $DetailedResult
}
Else {
$VMSettingsSearch
}
}
}
function Get-ITDVMwareSRMRecoveryPlan {
[CmdletBinding()]
param (
[string[]]
$Name,
[switch]
$Formatted
)
begin {
}
process {
$RecoveryPlans = ($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ RecoveryPlans).Attributes.Folder.RecoveryPlan
If ($Name) {
$RecoveryPlansSearch = $Name | ForEach-Object {
$RecoveryPlans | Where-Object name -Like "*$_*"
}
}
else {
$RecoveryPlansSearch = $RecoveryPlans
}
$DetailedResult = [System.Collections.ArrayList]@()
ForEach ($RecoveryPlan in $RecoveryPlansSearch) {
Write-Warning -Message ("Start Recovery Plan Loop for " + $RecoveryPlan.Name.TrimStart().TrimEnd() )
$ProtectionGroupDetailed = Get-ITDVMwareSRMProtectionGroup -Id $RecoveryPlan.protectionGroups.TrimStart().TrimEnd() -Detailed
$AbrDatastores = $ProtectionGroupDetailed.AbrDatastores | Select-Object -Unique | Sort-Object
$VrDatastores = $ProtectionGroupDetailed.VrDatastores | Select-Object -Unique | Sort-Object
$Network = $ProtectionGroupDetailed.Network | Select-Object -Unique | Sort-Object
$VMSettings = Get-ITDVMwareSRMVMSettings -Id (Get-ITDVMwareSRMVM -Name $ProtectionGroupDetailed.VM).Id.TrimStart().TrimEnd() -Detailed
If ($RecoveryPlan.Callouts) {
$Callouts = [System.Collections.ArrayList]@()
$RecoveryPlan.Callouts.CalloutSpec | ForEach-Object {
}
}
$RPobj = [PSCustomObject]@{
Name = $RecoveryPlan.Name.TrimStart().TrimEnd();
ProtectionGroups = $ProtectionGroupDetailed.Name | Sort-Object;
Network = $Network;
AbrDatastores = $AbrDatastores;
VrDatastores = $VrDatastores;
BeforePriority1 = ($RecoveryPlan.Callouts.CallOutSpec | Where-Object position -EQ 'beforeRecoverPriority1Vms').RecoveryPrompt | select promptText, Description
Priority1VMs = ($VMSettings | Where-Object recoveryPriorityGui -EQ 1).Name;
BeforePriority2 = ($RecoveryPlan.Callouts.CallOutSpec | Where-Object position -EQ 'beforeRecoverPriority2Vms').RecoveryPrompt | select promptText, Description
Priority2VMs = ($VMSettings | Where-Object recoveryPriorityGui -EQ 2).Name;
BeforePriority3 = ($RecoveryPlan.Callouts.CallOutSpec | Where-Object position -EQ 'beforeRecoverPriority3Vms').RecoveryPrompt | select promptText, Description
Priority3VMs = ($VMSettings | Where-Object recoveryPriorityGui -EQ 3).Name;
BeforePriority4 = ($RecoveryPlan.Callouts.CallOutSpec | Where-Object position -EQ 'beforeRecoverPriority4Vms').RecoveryPrompt | select promptText, Description
Priority4VMs = ($VMSettings | Where-Object recoveryPriorityGui -EQ 4).Name;
BeforePriority5 = ($RecoveryPlan.Callouts.CallOutSpec | Where-Object position -EQ 'beforeRecoverPriority5Vms').RecoveryPrompt | select promptText, Description
Priority5VMs = ($VMSettings | Where-Object recoveryPriorityGui -EQ 5).Name;
}
$null = $DetailedResult.Add($RPobj)
}
If ($Formatted) {
$FormattedResult = $DetailedResult | select Name, `
@{n = 'ProtectionGroups'; e = { ($_.ProtectionGroups | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'Network'; e = { ($_.Network | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'AbrDatastores'; e = { ($_.AbrDatastores | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'VrDatastores'; e = { ($_.VrDatastores | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'BeforePriority1'; e = { $_.BeforePriority1 | Out-String } }, `
@{n = 'Priority1VMs'; e = { ($_.Priority1VMs | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'BeforePriority2'; e = { $_.BeforePriority2 | Out-String } }, `
@{n = 'Priority2VMs'; e = { ($_.Priority2VMs | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'BeforePriority3'; e = { $_.BeforePriority3 | Out-String } }, `
@{n = 'Priority3VMs'; e = { ($_.Priority3VMs | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'BeforePriority4'; e = { $_.BeforePriority4 | Out-String } }, `
@{n = 'Priority4VMs'; e = { ($_.Priority4VMs | Sort-Object | Out-String).TrimEnd() } }, `
@{n = 'BeforePriority5'; e = { $_.BeforePriority5 | Out-String } }, `
@{n = 'Priority5VMs'; e = { ($_.Priority5VMs | Sort-Object | Out-String).TrimEnd() } }
}
}
end {
If ($Formatted) {
Write-Output $FormattedResult
}
Else {
Write-Output $DetailedResult
}
}
}
function Get-ITDVMwareSRMMasterPlan {
[CmdletBinding()]
param (
)
begin {
$RecoveryPlans = ($Global:SrmXml.configurablesWrapper.data.object | Where-Object Type -EQ RecoveryPlans).Attributes.Folder.RecoveryPlan
}
process {
}
end {
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,109 @@
#$AllVMHosts = Get-Cluster AVAYA*,LINUX*,ODM*,ORACLE*,SQL*,SQL2-DR,TEL*,WAS*,WINDOWS* | Get-VMHost | Sort-object Name
$VMhostNames = @"
itdbisvm-av05.nd.gov
"@
$VMhostNames = ConvertTo-Array -MultiLineString $VMhostNames
$AllVMHosts = Get-VMHost $VMhostNames
$AllVMHosts = Get-Cluster WINDOWS2 | Get-VMHost
ForEach ($VMHost in $AllVMHosts) {
Clear-DnsClientCache
$VirtualSwitch = $null
$CohesityDNS = $null
$IpAddress = $null
$VMHostDNS = $VMHost.Name
$VirtualSwitch = $VMHost | Get-VirtualSwitch -Name "*Data*"
$PortGroup = $VirtualSwitch | Get-VirtualPortGroup | Where-Object Name -Like "dvPG_3534_10.2.170.0_24*"
$CohesityDNS = $VMHostDNS.split('.')[0] + 'co.nd.gov'
# does vmhost already have vmkernel in Cohesity range?
If ($VMHost | Get-VMHostNetworkAdapter -VMKernel | Where-Object IP -Like "10.2.170.*") {
Write-Warning "VMKernel already exists on $VMHostDNS"
}
Else {
$IpAddress = (Resolve-DnsName -Name $CohesityDNS).IpAddress
If ($IpAddress) {
New-VMHostNetworkAdapter -VMHost $VMHost `
-PortGroup $PortGroup `
-VirtualSwitch $VirtualSwitch `
-IP $IpAddress `
-SubnetMask 255.255.255.0 `
-ManagementTrafficEnabled $true `
-VMotionEnabled $false `
-VsanTrafficEnabled $false
}
else {
Write-Error "IpAddress null for $VMHostDNS"
}
}
}
<# Create DNS records
$AllVMHosts = @"
itdvmbismgmt01.nd.gov
itdvmbismgmt02.nd.gov
itdvmbisvapp01.nd.gov
itdvmbisvapp02.nd.gov
itdvmbiswas04.nd.gov
itdvmbiswas05.nd.gov
itdvmbisora02.nd.gov
itdvmbisora03.nd.gov
itdvmbissql09.nd.gov
itdvmbissql10.nd.gov
itdvmbissql11.nd.gov
itdvmbiswin07.nd.gov
itdvmbiswin08.nd.gov
itdvmbiswin09.nd.gov
itdvmbiswin10.nd.gov
itdvmbiswin11.nd.gov
itdvmbiswin12.nd.gov
itdvmbiswin13.nd.gov
itdvmbissql07.nd.gov
itdvmbissql08.nd.gov
itdvmmdnmgmt01.nd.gov
itdvmmdnvapp01.nd.gov
itdvmmdnsql07.nd.gov
itdvmmdnsql08.nd.gov
itdvmmdnsql09.nd.gov
itdvmmdnlin05.nd.gov
itdvmmdnora02.nd.gov
itdvmmdnmgmt02.nd.gov
itdvmmdnvapp02.nd.gov
itdvmmdnsql10.nd.gov
itdvmmdnsql11.nd.gov
itdvmmdnsql12.nd.gov
itdvmmdnlin03.nd.gov
itdvmmdnlin04.nd.gov
"@
$AllVMHosts = ConvertTo-Array -MultiLineString $AllVMHosts
#Get-Cluster WINDOWS2,WAS2,SQL2,SQL2-DR,TEL2,PS2,ORACLE2,ODM2,LINUX2,AVAYA2 | Get-VMHost
ForEach($VMHost in $AllVMhosts){
$CohesityDNS = $VMHost.split('.')[0] + 'co.nd.gov'
New-ITDIbDNSRecordNextAvailableIP -CIDR 10.2.170.0/24 -Credential $IbCred -Hostname $CohesityDNS
#$CohesityDNS
}
#>
# static routes
$AllVMHosts = Get-VMHost -Name itdmdnvm-av03.nd.gov
$result = [System.Collections.ArrayList]@()
ForEach ($VMHost in $AllVMHosts) {
$x = $null
$esxcli = Get-EsxCli -VMHost $VMHost -V2
$params = @{
network = '10.2.169.128/26'
gateway = '10.2.170.1'
}
$esxcli.network.ip.route.ipv4.add.Invoke($params)
$x = $esxcli.network.ip.route.ipv4.list.Invoke() | Where-Object {$_.Interface -eq 'vmk2' -and $_.Network -eq '10.2.169.128'}
$x | Add-Member -Name "Name" -MemberType NoteProperty -Value $VMHost.Name
$null = $result.Add($x)
}
@@ -0,0 +1,404 @@
#----------------------------------------------------------------------------------------------------------------------------------------------------
#vCenter Credentials
$creds = Get-Credential
Connect-VIServer itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $creds
#----------------------------------------------------------------------------------------------------------------------------------------------------
#ConvertTo-Array
$VMs=@"
itdtaxtga1.nd.gov
itdtaxpfa1.nd.gov
itdtaxsga1.nd.gov
itdtaxsga2.nd.gov
itdtaxpga1.nd.gov
itdtaxpga2.nd.gov
itdtaxpga3.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Move VM to Datastore
$VMdatastore = 'VMWINDOWS1_143_A9K_R_SHRDPPLSFTST'
Get-VM $VMs | Get-HardDisk
Get-VM $VMs | Move-VM -DiskStorageFormat Thin -Datastore $VMdatastore
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Copy Files to/from Remote Computer
#$fileloc = "C:\Users\delange\State of North Dakota\-Tm-ITD-Virtualization - Documents\VMware\Upgrades\ESXi\6.5.0Update3preGen9\VMware-ESXi-6.5.0-Update3-13932383-HPE-preGen9-650.U3.9.6.8.8-Jun2019.iso"
$fileloc = "C:\users\delange\Downloads\sql.zip"
#$fileloc = "O:\Backups\vp_grandforks\vp_grandforks.bak"
#$fileloc = "C:\temp3\AccelaSchool\*"
#$fileloc = "C:\temp\vp_bis_11252019.bak"
#$fileloc = "C:\ITD\vc-itdvmvc1.nd.gov-2020-01-14--19.33-53492.tgz"
#$fileloc = "D:\Upgrades\VMware\VMware-VCSA-all-6.5.0-14836121.iso"
#$fileloc = "F:\Support Bundles\vc-itdvmvc1.nd.gov-2020-01-07--19.02-29010.tgz"
#$destination = "D:\Upgrades\VMware\"
#$destination = "D:\delange"
#$destination = "C:\users\delange\Downloads\"
#$destination = "C:\inetpub\wwwroot\"
$destination = "D:\ITD\temp\"
#$servers = 'itdvmutil'
$servers = 'itdps-update.nd.gov'
#$servers = 'itdps-images.nd.gov'
#Copy to server
foreach ($server in $servers){
$s=New-PSSession $server -Credential $creds
Copy-Item $fileloc -ToSession $s -Destination $destination
}
#Copy from server
foreach ($server in $servers){
$s=New-PSSession $server -Credential $creds
Copy-Item $fileloc -FromSession $s -Destination $destination
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Approve New VMs
Compare-ITDVMwareVMtoSharePoint -NewBuilds -OutVariable MatchSP | Format-Table
$MatchSP -Match $false | Sort-Object Name | Format-Table
$VMs=@"
itdohrcdbp1.nd.gov
itdohrcwebp1.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
Approve-ITDVMwareVMNewBuild -ComputerName $VMs
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Snapshots/Clones
#Get Current Snapshots
Get-VM | Get-Snapshot | Select-Object Name,VM | Sort-Object -Property Name | Format-Table -AutoSize #| clip.exe
#Take Snapshot
$SnapId = 2151..2156
New-ITDVMwareVMSnapshotTask -id $SnapId -vCenterCredential $creds
#Delete Snapshot from Scripted Task
$SnapId = 2186
Remove-ITDVMwareVMSnapshot -Id $SnapId -vCenterCredential $creds
#Delete Snapshot taken manually
$VM = 'bnd0704.nd.gov','itdscmt1.nd.gov'
Get-VM -Name $VM | Where-Object -Property PowerState -EQ PoweredOn | Get-Snapshot | Remove-Snapshot -Confirm:$false
#New Clone
$CloneId = 2149
New-ITDVMwareVMCloneTask -Id $CloneId -vCenterCredential $creds
#Delete Clone
$CloneId = 2117
Get-VM | Where-Object -Property Name -Like "*$CloneId*"
foreach ($Clone in $CloneId){
$DeleteClone = Get-VM | Where-Object -Property Name -Like "*$Clone*"
$DeleteClone | Remove-VM -DeleteFromDisk -Confirm:$false
}
#Snap entire vCenter environment at once
Get-VM itdvmpsc1*,itdvmvc1*,itdvmpsc2*,itdvmvc2* | New-Snapshot -Name "Converge External PSC"
Get-VM itdvmpsct1*,itdvmvct1*,itdvmpsct2*,itdvmvct2* | New-Snapshot -Name "PSCT2 Decommissioned"
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Edit VMs
#Add CPU
$VMs = 'itdsql16p1.nd.gov'
$cpu = '4'
Get-VM $VMs
Set-VM $VMs -NumCpu $cpu -Confirm:$false
#Remove CPU
$VMs = 'bnd0557.nd.gov'
$cpu = '1'
Get-VM -Name $VMs | Shutdown-VMGuest -Confirm:$false
#Start-Sleep -Seconds 60
Get-VM -Name $VMs
Get-VM -Name $VMs | Set-VM -NumCPU $cpu -Confirm:$false
Start-VM $VMs -Confirm:$false
#Increase RAM
$VMs = 'itdcndhf16qps.nd.gov','itdcndhefqps.nd.gov'
$ram = '12'
Get-VM $VMs
Set-VM $VMs -MemoryGB $ram -Confirm:$false
#Remove RAM
$VMs = ''
$ram = ''
Get-VM $VMs | Shutdown-VMGuest -Confirm:$false
Start-Sleep -Seconds 60
Get-VM -Name $VMs | Set-VM -MemoryGB 16 -Confirm:$false
Start-VM $VMs -Confirm:$false
#Disconnect CDROM
$VMs = 'itdcndstrwt7.nd.gov'
foreach ($VM in $VMs){
Get-VM $VM | Get-CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
#Expand Disks
$VM = 'itdcndstvm04.nd.gov'
Get-VM | Where-Object -Property Name -Like "*$VM*"
Get-VM $VM | Get-HardDisk | Select-Object Name,CapacityGB,Filename
$harddisk = "Hard Disk 2"
$increasedisk = 3
$datastore = Get-VM $VM | Get-HardDisk | Where-Object -Property Name -EQ $harddisk | Get-Datastore
Get-Datastore $datastore | Select Name,FreeSpaceGB,CapacityGB
$newcap = (Get-VM $VM | Get-HardDisk | Where-Object -Property Name -EQ $harddisk).CapacityGB + $increasedisk
$newcap
Get-VM $VM | Get-HardDisk | Where-Object -Property Name -EQ $harddisk | Set-HardDisk -CapacityGB $newcap -Confirm:$false
#List NumCpu, MemoryGB, Total HardDiskSizeGB
$VMs = 'itd1xaes2','itdbiscmsvr','itdredskyaes','itdwfoaes4'
$datacenter = 'Primary Datacenter'
$harddisk = @{n="HardDiskSizeGB";e={(Get-HardDisk -VM $_ | Measure-Object -Sum CapacityGB).Sum}}
foreach ($VM in $VMs){
Get-Datacenter $datacenter | Get-VM | Where-Object -Property Name -Like "$VM*" | Select-Object -Property Name,NumCpu,MemoryGB,$harddisk
}
foreach ($VM in $VMs){
Get-VM | Where-Object -Property Name -Like "$VM*" | Get-HardDisk | Select-Object Name,CapacityGB,Filename | Sort-Object Filename -Descending
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Port groups
#New distributed port group
$IP = '10.2.160.240/28' <#10.10.10.10/28#>
$VLANid = '3326' <#0001#>
New-ITDVMNetwork -CIDR $IP -VLAN $VLANid
#Remove distributed port group
$portgroup = 'dvPG_'
Get-VDPortgroup | Where-Object -Property Name -EQ $portgroup | Remove-VDPortGroup -Confirm:$false
#Manually add port group
$BismarckVDSwitch = 'dvSwitch3-PDC-AVAYA1-Data'
$MandanVDSwitch = 'dvSwitch3-SDC-AVAYA2-Data'
$PGName = 'dvPG3_2278_165.234.164.0_27'
$VlanId = '2278'
Get-VDSwitch -Name $BismarckVDSwitch | New-VDPortGroup -Name $PGName -NumPorts 1 -VlanId $VlanId
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortGroup | Where-Object {$_.Name -like ("*" + "_" + $VlanId)} | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -FailoverDetectionPolicy BeaconProbing
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortGroup | Where-Object {$_.Name -like ("*" + "_" + $VlanId)} | Get-VDPortgroupOverridePolicy | Set-VDPortgroupOverridePolicy -BlockOverrideAllowed $false -ResetPortConfigAtDisconnect $false
Get-VDSwitch -Name $MandanVDSwitch | New-VDPortGroup -Name $PGName -NumPorts 1 -VLANID $VlanId
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortGroup | Where-Object {$_.Name -like ("*" + "_" + $VlanId)} | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -FailoverDetectionPolicy BeaconProbing
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortGroup | Where-Object {$_.Name -like ("*" + "_" + $VlanId)} | Get-VDPortgroupOverridePolicy | Set-VDPortgroupOverridePolicy -BlockOverrideAllowed $false -ResetPortConfigAtDisconnect $false
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Delete VMs
#Rename VMs for decommission
$VMs=@"
itdcndstfwp.nd.gov
itdcndstfsowp.nd.gov
itdcndstfwp1.nd.gov
itdcndstfapp1.nd.gov
itdcndstfwp2.nd.gov
itdcndstfapp2.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
Remove-ITDVMWareVM -ComputerName $VMs | Select-Object -Property Name,PowerState
foreach ($VM in $VMs){
Get-VM | Where-Object -Property Name -Like "$VM*" | Select-Object -Property Name,PowerState
}
#Delete VM - FINAL DELETE
$deleteVM = foreach ($VM in $VMs){
Get-VM | Where-Object -Property Name -Like "$VM*delete*"
}
$deleteVM.Name
$deleteVM | Remove-VM -DeleteFromDisk -Confirm:$false
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Replace VMs
$VMs = 'itdexchcasbis2.nd.gov','itdexchcasman2.nd.gov','itdcndhehb.nd.gov','itdcndheclnadd.nd.gov'
foreach ($VM in $VMs){
$VMold = Get-VM | Where-Object -Property Name -Like "$VM*" | Where-Object -Property PowerState -EQ PoweredOff
$VMnew = Get-VM | Where-Object -Property Name -Like "$VM*new*"
$VMtags = ($VMold | Get-TagAssignment).Tag | Sort-Object -Unique
foreach ($VMtag in $VMtags){
New-TagAssignment -Entity $VMnew -Tag $VMtag
}
Remove-ITDVMWareVM -ComputerName $VMold.Name
Set-VM -VM $VMnew -Name $VMold -Confirm:$false
}
foreach ($VM in $VMs){
Get-VM | Where-Object -Property Name -Like "$VM*" | Get-TagAssignment
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Datastores
$Datastore = 'VMWINDOWS1_138_A9K_R_BNDFISERV'
#Rescan Host Cluster
Get-Cluster WINDOWS1 | Get-VMHost | Get-VMHostStorage -RescanAllHba -RescanVmfs
#Maintenance Mode
$Datastore = 'VMPS1_48_A9K_R','VMPS1_49_A9K_R','VMPS1_50_A9K_R','VMPS1_51_A9K_R','VMPS1_52_A9K_R','VMPS1_53_A9K_R'
Get-Datastore $Datastore | Set-Datastore -MaintenanceMode $true -EvacuateAutomatically
Get-Datastore $Datastore | Set-Datastore -MaintenanceMode $false
#Adding Datastores
$VMhost = 'itdbisvm-sql01.nd.gov'
#Get CanonicalName
Get-ScsiLun -VmHost $VMhost -LunType Disk | Select-Object CanonicalName,CapacityGB | Sort-Object CanonicalName
#Create Datastore
$Datastore = 'VMSQL1_119_A9K_TAX'
$CanonicalName = 'naa.6001738ccce06785000000000018ef24'
New-Datastore -VMHost $VMhost -Name $Datastore -Path $CanonicalName -VMFS -FileSystemVersion 6
#Removing Datastores
#Datastore Unmap
$Datastores = 'VMLINUX1_248_V5K_SECLOG','VMLINUX1_249_V5K_SECLOG','VMLINUX1_250_V5K_SECLOG','VMLINUX1_251_V5K_SECLOG'
#$Datastores = (Get-DatastoreCluster SQL1_A9K_General | Get-Datastore).Name
foreach ($Datastore in $Datastores){
Start-ITDVMwareDatastoreUnmap -Datastore $Datastores
}
#Expand Datastore
$Datastore = Get-Datastore 'VMTEL1_124_A9K_VBRICK'
$esxi = Get-View -Id ($Datastore.ExtensionData.Host | Select-Object -Last 1 | Select-Object -ExpandProperty Key)
$DatastoreSystem = Get-View -Id $esxi.ConfigManager.DatastoreSystem
$ExpandOptions = $DatastoreSystem.QueryVmfsDatastoreExpandOptions($Datastore.ExtensionData.MoRef)
$DatastoreSystem.ExpandVmfsDatastore($Datastore.ExtensionData.MoRef,$expandOptions.spec)
#Disable Storage I/O Control
$Datastores = 'VMWINDOWS1_90_A9K','VMWINDOWS1_91_A9K','VMWINDOWS1_92_A9K','VMSQL1_57_A9K','VMLINUX1_99_A9K_ELASTIC'
foreach ($Datastore in $Datastores){
Get-Datastore $Datastore | Set-Datastore -StorageIOControlEnabled $false
}
#Unmount/Detach
#Unmount/Detach
Remove-ITDVmwareDatastoreStep1 -LunId 90
#Step2 Storage Admin unmaps LUN from Host
#LUN cleanup (after storage unmap, should return empty)
Remove-ITDVMwareDatastoreStep3 -LunId 57
Remove-ITDVMwareDatastoreStep3 -LunId 90
Remove-ITDVMwareDatastoreStep3 -LunId 91
Remove-ITDVMwareDatastoreStep3 -LunId 92
Remove-ITDVMwareDatastoreStep3 -LunId 99
$Id = "_90_"
$Datastores = Get-Datastore | Where-Object Name -Like ("*_" + $Id + "_*")
ForEach ($Datastore in $Datastores) {
$SharePointRecord = $null
$DatastoreHosts = $Datastore | Get-VMHost
$VMHostCanonicalName = (Get-ScsiLun -VmHost ($DatastoreHosts | Select -First 1) | where-object RuntimeName -Like "*$Id*").CanonicalName
$SharePointRecord = ($SharePointList | Where-Object Title -eq $Datastore.Name)
If ($SharePointRecord.ExtentName -eq $VMHostCanonicalName) {
Write-Verbose ($Datastore.Name + " *** " + $VMHostCanonicalName + " *** CanonicalName accurate in SharePoint, continuing with unmount")
try {
Get-Datastore $Datastore #| Unmount-Datastore
$DatastoreHosts | Select-Object -First 1 | Remove-Datastore $Datastore -Confirm:$false -RunASync
$DatastoreRemovalSuccess += $Datastore.Name
}
catch {
$DatastoreRemovalFailure += $Datastore.Name
}
}
else {
Write-Error ($Datastore.Name + " *** " + " *** CanonicalName mismatch with SharePoint Record")
}
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Clusters
#Get cluster that VM resides in
foreach ($VM in $VMs){
Get-VM $VM | Get-Datastore | Select-Object Name
}
#Get VMs with Resource Reservations
$Cluster = 'TEL1'
$VMs = Get-Cluster $Cluster | Get-VM
$VMs2 = Get-VM | Where-Object {$_.ExtensionData.ResourceConfig.MemoryAllocation.Reservation -ne "0" -or $_.ExtensionData.ResourceConfig.CpuAllocation.Reservation -ne "0"}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Tags
$VMs=@"
itdintrpmgrp1.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
#Spectrum Protect for VE
$TagCat = "Backup Management (IBM Spectrum Protect)"
$TagName = "Included"
#RPO
$TagCat = "VR RPO"
$TagName = "ABR"
$TagName = "RPO 0:15"
$TagName = "RPO 0:30"
$TagName = "RPO 1:00"
$TagName = "RPO 2:00"
$TagName = "RPO 4:00"
$TagName = "RPO 8:00"
#VR Datastores
$TagCat = "VR Datastores"
$TagName = "VMAVAYA2_210_A9K_VR"
$TagName = "VMLINUX2_212_A9K_VR"
$TagName = "VMLINUX2_213_A9K_VR"
$TagName = "VMSQL2_218_A9K_VR"
$TagName = "VMTEL2_220_A9K_VR"
$TagName = "VMTEL2_221_A9K_VR"
$TagName = "VMWAS2_222_A9K_VR"
$TagName = "VMWAS2_223_A9K_VR"
$TagName = "VMWINDOWS2_224_A9K_VR"
$TagName = "VMWINDOWS2_225_A9K_VR"
$TagName = "VMWINDOWS2_226_A9K_VR"
#SRM Type
$TagCat = "SRM Type"
$TagName = "SRM Reserved"
$TagName = "SRM Repurposed Suspend"
$TagName = "SRM Repurposed"
#HA Host
$TagCat = "HA"
$TagName = "Dedicated HA Host"
#Assign Tag
foreach ($VM in $VMs){
$VM = Get-VM $VM | Where-Object -Property PowerState -EQ PoweredOn
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
New-TagAssignment -Entity $VM -Tag (Get-Tag -Server $VIServer -Category $TagCat -Name $TagName) -Server $VIServer
}
foreach ($VMHost in $VMHosts){
$VMHost = Get-VMHost $VMHost
$VIServer = $VMHost.Uid.split('@')[1].split(':')[0]
New-TagAssignment -Entity $VMHost -Tag (Get-Tag -Server $VIServer -Category $TagCat -Name $TagName) -Server $VIServer
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#VMhosts
$VMhosts=@"
itdbisvm-av01.nd.gov
itdbisvm-av02.nd.gov
itdbisvm-av03.nd.gov
itdbisvm-av04.nd.gov
itdbisvm-av05.nd.gov
"@
$VMhosts=ConvertTo-Array -MultiLineString $VMhosts
#VMhosts by Cluster
$VMhosts = (Get-Cluster | Where-Object -Property Name -EQ WINDOWS1 | Get-VMHost | Sort-Object).Name
#Disable Lockdown Mode
foreach ($VMhost in $VMhosts){
(Get-VMHost $VMhost | Get-View).ExitLockdownMode()
}
#Enable Lockdown Mode
(Get-VMHost $VMhost | Get-View).EnterLockdownMode()
$VMhosts = Get-Datacenter | Where-Object -Property Uid -Like "*itdvmvc*" | Get-VMHost
(Get-VMHost $Vmhosts | Get-View).EnterLockdownMode()
foreach ($VMhost in $VMhosts){
(Get-VMHost $VMhost | Get-View).EnterLockdownMode()
}
#Enable SSH services
Get-VMHost $VMhost | Get-VMHostService | Where-Object {$_.Label -eq "SSH"} | Start-VMHostService
Get-VMHost $VMhost | Get-VMHostService | Where-Object {$_.Label -eq "ESXi Shell"} | Start-VMHostService
#Get Lockdown Status for all VMhosts
$VMhosts = Get-Datacenter | Where-Object -Property Uid -Like "*itdvmvc*" | Get-VMHost
$Lockdown = @{N="Lockdown";E={$_.Extensiondata.Config.adminDisabled}}
Get-VMHost $VMhosts | Select-Object Name,$Lockdown
#Disable Alarms
foreach ($VMhost in $VMhosts){
$disableHost = Get-VMhost $VMhost
$viServer = $disableHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $viServer
$alarmEnabled = $disableHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true){
$alarmMgr.EnableAlarmActions($disableHost.ExtensionData.MoRef,$false)
}
$disableHost = $null
}
#Enable Alarms
foreach ($VMhost in $VMhosts){
$enableHost = Get-VMhost $VMhost
$viServer = $enableHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $viServer
$alarmEnabled = $enableHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false){
$alarmMgr.EnableAlarmActions($enableHost.ExtensionData.MoRef,$true)
}
$enableHost = $null
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Disk Space
$VMs=@"
itdcndhhpdb.nd.gov
itdcndhhpdbdr.nd.gov
itdcndhfpdb.nd.gov
itdcndhfpdbdr.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
$export = 'C:\temp\usedspace.csv'
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Avaya1 | Export-Csv $export
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Avaya1 | Export-Csv $export -Append
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Linux1 | Export-Csv $export -Append
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable ODM1 | Export-Csv $export -Append
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable PS1 | Export-Csv $export -Append
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable WAS1 | Export-Csv $export -Append
Get-VM $WindowsVMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Windows1 | Export-Csv $export -Append
#----------------------------------------------------------------------------------------------------------------------------------------------------
$export = "C:\temp2\usedspace.csv"
Export-Csv -Path $export -InputObject $Avaya1
Get-VM $VMs | Select-Object @{n="Cluster"; e={($_ | Get-Cluster).Name}},Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Avaya1 | Export-Csv $export
@@ -0,0 +1,97 @@
Start-Transcript C:\ITDSCRIPT\Logs\GetIPs.txt -Append
#Add-PSSnapin VMware.VimAutomation.Core
Set-PowerCLIConfiguration -DefaultVIServerMode multiple -Scope Session -Confirm:$false
#Connect
Connect-VIServer itdvmvc1.nd.gov, itdvmvc2.nd.gov
##Windows
#Output File
$OutFileWin = "c:\inetpub\wwwroot\Win.txt"
$Date = Get-Date -UFormat "%Y%m%d%H%M%S"
Get-Item -Path $OutFileWin | Copy-Item -Destination "D:\Backup\Win\$Date-Win.txt"
Remove-Item $OutFileWin
Start-Sleep -Seconds 5
#Get Powered On VM's
$vmwin = get-VM | Where-Object { $_.PowerState -eq "PoweredOn" `
-and ($_.GuestID -eq "windows7Guest" `
-or $_.GuestID -eq "windows7_64Guest" `
-or $_.GuestID -eq "windows7Server64Guest" `
-or $_.GuestID -eq "windows8_64Guest" `
-or $_.GuestID -eq "windows8Server64Guest" `
-or $_.GuestID -eq "windows9Server64Guest" `
-or $_.GuestID -eq "winLonghorn64Guest" `
-or $_.GuestID -eq "winLonghornGuest" `
-or $_.GuestID -eq "winNetStandardGuest" `
-or $_.GuestID -eq "winNetEnterpriseGuest" `
-or $_.GuestID -eq "windows9_64Guest") }
$vmviewwin = $vmwin | Get-View
$Outputwin = ""
#Loop through VM's, NIC's, and IP addresses.
Foreach ($v in $vmviewwin) {
Foreach ($nic in $v.Guest.Net) {
Foreach ($IP in $nic.IPAddress) {
If ($IP -notlike "fe80*" -and $IP -notlike "192.168.*" -and $IP -notlike "172.16*") {
$OutputWin += $IP + "`n"
}
}
}
}
#If ($Outputwin -ne "") {$OutputWin | Out-File $OutFileWin -Encoding utf8 -NoNewline}
If ($Outputwin -ne "") { $OutputWin | Out-File $OutFileWin -Encoding ASCII -NoNewline }
##Linux
#Output File
$OutFileLin = "c:\inetpub\wwwroot\Lin.txt"
$Date = Get-Date -UFormat "%Y%m%d%H%M%S"
Get-Item -Path $OutFileLin | Copy-Item -Destination "D:\Backup\Lin\$Date-Lin.txt"
Remove-Item $OutFileLin
Start-Sleep -Seconds 5
#Get Powered On VM's
$vmLin = get-VM | Where-Object { $_.PowerState -eq "PoweredOn" `
-and ($_.GuestID -eq "centos6_64Guest" `
-or $_.GuestID -eq "centos64Guest" `
-or $_.GuestID -eq "centos7_64Guest" `
-or $_.GuestID -eq "oracleLinux64Guest" `
-or $_.GuestID -eq "oracleLinux7_64Guest" `
-or $_.GuestID -eq "rhel4Guest" `
-or $_.GuestID -eq "rhel5Guest" `
-or $_.GuestID -eq "rhel5_64Guest" `
-or $_.GuestID -eq "rhel6Guest" `
-or $_.GuestID -eq "rhel6_64Guest" `
-or $_.GuestID -eq "rhel7_64Guest" `
-or $_.GuestID -eq "sles11_64Guest" `
-or $_.GuestID -eq "sles12_64Guest" `
-or $_.GuestID -eq "ubuntu64Guest") }
$vmviewlin = $vmLin | Get-View
$OutputLin = ""
#Loop through VM's, NIC's, and IP addresses.
Foreach ($v in $vmviewlin) {
Foreach ($nic in $v.Guest.Net) {
Foreach ($IP in $nic.IPAddress) {
If ($IP -notlike "fe80*" -and $IP -notlike "192.168.*" -and $IP -notlike "172.16*") {
$OutputLin += $IP + "`n"
}
}
}
}
#If ($OutputLin -ne "") {$OutputLin | Out-File $OutFileLin -Encoding utf8 -NoNewline}
If ($OutputLin -ne "") { $OutputLin | Out-File $OutFileLin -Encoding ASCII -NoNewline }
Stop-Transcript
@@ -0,0 +1,133 @@
Start-Transcript C:\itdscript\Logs\GetIPsAzureB.txt -Append
$VerbosePerfrence = "Continue"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$OutputPath = "C:\inetpub\wwwroot"
$WindowsIPs = ""
$LinuxIPs = ""
$OutFileWin = $OutputPath + "\AzureWin.txt"
$OutFileLin = $OutputPath + "\AzureLin.txt"
Remove-Item $OutFileWin
Remove-Item $OutFileLin
$username="svcitdazurescript@nd.gov"
$usernameg="svcitdazurescript@ndstate.onmicrosoft.com"
#Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat
$password=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat | ConvertTo-SecureString
$passwordg=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sacg.bat | ConvertTo-SecureString
$AdminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$password
$AdminCredg=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $usernameg,$passwordg
Login-AzureRMAccount -Credential $AdminCred -Environment AzureCloud -Verbose
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$WindowsVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Windows"}
$LinuxVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $WindowsVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$WindowsIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$WindowsIPs += $privateip.privateIPAddress + "`n"
}
}
}
foreach($vm in $LinuxVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$LinuxIPs += $private.privateIPAddress + "`n"
}
}
elseif($privateip.privateIPAddress -ne $null)
{
$LinuxIps += $privateip.privateIPAddress + "`n"
}
}
}
}
Login-AzureRMAccount -EnvironmentName AzureUSGovernment -Credential $AdminCredg
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$WindowsVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Windows"}
$LinuxVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $WindowsVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$WindowsIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$WindowsIPs += $privateip.privateIPAddress + "`n"
}
}
}
foreach($vm in $LinuxVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$LinuxIPs += $private.privateIPAddress + "`n"
}
}
elseif($privateip.privateIPAddress -ne $null)
{
$LinuxIps += $privateip.privateIPAddress + "`n"
}
}
}
}
If ($WindowsIPs -ne "" -and $WindowsIPs.Length -gt 150) {$WindowsIPs | Out-File $OutFileWin -Encoding ASCII -NoNewline -Force}
If ($LinuxIPs -ne ""-and $LinuxIPs.Length -gt 150) {$LinuxIPs | Out-File $OutFileLin -Encoding ASCII -NoNewline -Force}
@@ -0,0 +1,89 @@
start-transcript D:\zm.log -force
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$OutputPath = "C:\inetpub\wwwroot"
$OutputBackupPath = "C:\inetpub\wwwroot\AzureBak\"
$CurrentDateTime = Get-Date -UFormat "%Y%m%d%H%M%S"
$BackupIPs = ""
$OutFileBak = $OutputPath + "\AzureBak.txt"
$OutFileBakBackup = $OutputBackupPath + "\AzureBak-$CurrentDateTime.txt"
Remove-Item $OutFileBak
$username="svcitdazurescript@nd.gov"
$usernameg="svcitdazurescript@ndstate.onmicrosoft.com"
#Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat
$password=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat | ConvertTo-SecureString
$passwordg=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sacg.bat | ConvertTo-SecureString
$AdminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$password
$AdminCredg=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $usernameg,$passwordg
Login-AzureRMAccount -Credential $AdminCred -Environment AzureCloud
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$BackupVMs = Get-AzureRMVM | Where-Object {$_.Tags["Backup"] -match "OS-BackupEnabled"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $BackupVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$BackupIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$BackupIPs += $privateip.privateIPAddress + "`n"
}
}
}
}
Login-AzureRMAccount -EnvironmentName AzureUSGovernment -Credential $AdminCredg
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$BackupVMs = Get-AzureRMVM | Where-Object {$_.Tags["Backup"] -match "OS-BackupEnabled"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $BackupVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$BackupIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$BackupIPs += $privateip.privateIPAddress + "`n"
}
}
}
}
If ($BackupIPs -ne "") {
$BackupIPs | Out-File $OutFileBak -Encoding ASCII -NoNewline -Force
$BackupUPs | Out-File $OutFileBakBackup -Encoding ascii -NoNewline -Force
}
@@ -0,0 +1,88 @@
$servers = @"
itdvmbisvdi05lo.nd.gov
itdvmbisvdi06lo.nd.gov
"@
$servers = ConvertTo-Array -MultiLineString $servers
# validate DNS is configured
ForEach($server in $servers){
Resolve-DnsName -Name $server
}
#ServerHardware.mpHostInfo.mpIpAddresses
# requires powershell 5.1 as of 2023/02/09
# Generate CSRs
ForEach ($server in $servers) {
$csr = $Null
$connection = Connect-HPEiLO $server -Credential $iLOCred -DisableCertificateAuthentication
$FQDN = $connection.Hostname
If($FQDN -notlike "itdvm*"){
$FQDN = ((Get-HPEiLOServerInfo -Connection $connection).ServerName.split('.')[0] + 'lo' + '.nd.gov')
}
$Hostname = $FQDN.split('.')[0]
Start-HPEiLOCertificateSigningRequest -Connection $connection -State "North Dakota" -Country "US" -City "Bismarck" -Organization "State of North Dakota" -OrganizationalUnit "NDIT" -CommonName $FQDN
do {
$csr = (Get-HPEiLOCertificateSigningRequest -Connection $connection -ErrorAction SilentlyContinue).CertificateSigningRequest.TrimEnd()
Write-Warning ((Get-Date).tostring() + " pausing for 5 seconds")
Start-Sleep -Seconds 5
} while ( $csr -eq $null )
$csr | Set-Content "D:\iLO\CSRs\$FQDN-csr.txt"
Disconnect-HPEiLO -Connection $connection
}
$CsrList = [System.Collections.ArrayList]@()
ForEach($server in $servers){
$obj=[PSCustomObject]@{
'Server' = $Server
'CSR' = (Get-Content "D:\iLO\CSRs\$server-csr.txt" -Raw);
}
$null = $CsrList.Add($obj)
}
$CsrList | group-object CSR
# If any appear with count not equal to 1, something is broken
ForEach ($server in $servers){
Write-Warning "$server csr to clipboard"
Get-Content "D:\iLO\CSRs\$server-csr.txt" | Set-Clipboard
Pause
}
ForEach ($server in $servers){
$certfile = $Null
$cert = $Null
$connection = Connect-HPEiLO $server -Credential $iloCred -DisableCertificateAuthentication
$FQDN = $connection.Hostname
If($FQDN -notlike "itdvm*"){
$FQDN = ((Get-HPEiLOServerInfo -Connection $connection).ServerName.split('.')[0] + 'lo' + '.nd.gov')
}
$Hostname = $FQDN.split('.')[0]
$certfile = ($hostname) + "_nd_gov_cert.cer"
$cert = (Get-Content "D:\iLO\Certs\$certfile" -Raw).Replace("`r`n", "`n").Trim()
Import-HPEiLOCertificate -Certificate $cert -Connection $connection -Verbose
Disconnect-HPEiLO -Connection $connection
}
# Refresh server hardware, in powershell 7
# Connect-OVMgmt
$OVServers = Get-OVServer | Sort-Object ServerName
Foreach($OVServer in $OVServers){
Write-Warning ("Start " + $OVServer.ServerName)
$OVServer | Update-OVServer -Async
Start-Sleep -Seconds 15
}
#######################
@@ -0,0 +1,19 @@
$VMHosts = Get-VMHost
#SSH Service Status
$SSHServiceStatus = $VMHosts | Get-VMHostService | Where-Object Key -eq "TSM-SSH" | select VMhost,Key,Label,Running
#Disable SSH
ForEach($item in ($SSHService | Where-Object Running -eq $true)){
Get-VMHost $item.VMHost | Get-VMHostService | Where-Object Key -eq "TSM-SSH" | Stop-VMHostService
}
#Lockdown status
$LockdownStatus = $VMHosts | Select Name,@{n='LockdownMode';e={$_.ExtensionData.Config.LockdownMode}}
#Enable Lockdown
ForEach($VMHost in ($LockdownStatus | Where-Object LockdownMode -eq "lockdownDisabled")){
(Get-VMHost $VMHost.Name | Get-View).EnterLockdownMode()
}
@@ -0,0 +1,102 @@
$VMHostNames=@"
itdvmbisps10.nd.gov
itdvmbisps11.nd.gov
itdvmbisps12.nd.gov
itdvmbisps13.nd.gov
itdvmbisps14.nd.gov
itdvmbisps15.nd.gov
itdvmbisps16.nd.gov
itdvmbisps17.nd.gov
itdvmbisps18.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
<#$VMHostNames | ForEach-Object{
New-ITDVMwareHostScratchFolder -Site Bismarck $_.split('.')[0]
}
#>
foreach ($VMHostName in $VMHostNames){
$GetVMHost = Get-VMhost $VMHostName
$VMHostParent = $GetVMHost.Parent
$HostCluster = Get-Cluster $VMHostParent
$NewSpec = New-Object VMware.Vim.ClusterConfigSpec
$NewSpec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
$NewSpec.DasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
$NewSpec.DasConfig.AdmissionControlPolicy.AutoComputePercentages = $true
$HostCluster.ExtensionData.ReconfigureCluster($NewSpec,$true)
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true){
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef,$false)
}
$VMs = $GetVMHost | Get-VM
#Disconnect CDROM and/or VMtools ISO
foreach ($VM in $VMs){
$GetVM = Get-VM $VM
$CDDrive = $GetVM | Get-CDDrive
if ($CDDrive | Where-Object {$_.IsoPath -Like "*vmware/isoimages*"}){
$GetVM | Dismount-Tools
#$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
elseif ($CDDrive.HostDevice -Like "*drive*"){
$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
}
$GetVMHost = $null
}
#Move Powered Off VMs
foreach ($VMHostName in $VMHostNames){
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostParent = $VMHostDetails.Parent.Name
$VMHostMigrate = Get-Cluster $VMHostParent | Get-VMHost | Where-Object Name -NE $VMHostName | Select-Object -First 1
$VMsPoweredOff = Get-VMHost $VMHostName | Get-VM | Where-Object PowerState -EQ "PoweredOff"
Move-VM -VM $VMsPoweredOff -Destination $VMHostMigrate
}
#Enter Maintenance Mode
Set-VMHost -VMHost $VMHostNames -State "Maintenance" -RunAsync
#Monitor
Get-VMHost -Name $VMHostNames | Select-Object Name,ConnectionState,@{Name="VM.count";E={@($_ | Get-VM | Where-Object {$_.ExtensionData.Summary.Config.ManagedBy.Type -NE "placeholderVm"}).Count}} | sort-object Name
# shutdown
Get-VMHost -Name $VMHostnames | Stop-VMHost -Confirm:$false
#status
Get-VMHost -Name $VMHostnames
# OneView, Update Server Profile from Template
ForEach($VMHostName in $VMHostNames){
Get-OVServerProfile -Name $VMHostName.split('.')[0] | Update-OVServerProfile -Async -confirm:$false
}
# Power on
ForEach($VMHostName in $VMHostNames){
Get-OVServer -ServerName $VMHostName | Start-OVServer -Async
}
# Verify on and connected
Get-VMHost $VMHostNames
# attach new host profile
Get-VMHost -Name $VMHostnames | Set-VMHost -Profile "MDN 6.5.0 Synergy General 2203"
# Apply/Remediate Host Profile (invoke)
Get-VMHost -Name $VMHostnames | Invoke-VMHostProfile -confirm:$false -RunAsync
# manual check for dvswitch data-user
#Exit Maintenance Mode and Enable Alarms
Set-VMHost -VMHost $VMHostNames -State "Connected" -RunAsync
Start-Sleep -Seconds 60
foreach ($VMHostName in $VMHostNames){
$GetVMHost = Get-VMhost $VMHostName
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false){
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef,$true)
}
$GetVMHost = $null
}
@@ -0,0 +1,136 @@
$sctasknum='SCTASK0123474'
$sctask = Get-ServiceNowRecord -Table 'Catalog Task' -ID $sctasknum -IncludeCustomVariable
$request_itemNum = $sctask.request_item.display_value
$TimeStampString = Get-Date -UFormat "%Y%m%d%H%M%S"
$CommentsToAdd=@"
$TimeStampString
Added disk
"@
Update-ServiceNowRecord -ID $sctask.number -Values @{comments = $CommentsToAdd} # enter comments into sctask
Update-ServiceNowRecord -ID $RitmNum -values @{comments = $CommentsToAdd}
If($CloseTask){
Update-ServiceNowRecord -Id $sctask.number -Values @{close_notes = $CommentsToAdd; state = "Closed Complete" }
}
Update-ServiceNowRecord -ID $sctask.number -Values @{short_description = "VMware VM change for $HostName"}
Update-ServiceNowRecord -ID $sctask.number -Values @{assigned_to = "Donald E. Lange"}
Update-ServiceNowRecord -ID $sctask.number -Values @{assigned_to = $assignTo.name}
# full auto cpu/memory
$SCTaskNum = 'SCTASK0123802'
$SCTask = Get-ServiceNowRecord -Table 'Catalog Task' -ID $SCTaskNum
$RitmNum = $SCTask.request_item.display_value
$RITM = Get-ServiceNowRecord -Table 'Requested Item' -ID $RitmNum -IncludeCustomVariable
[string]$HostName = ($RITM.CustomVariable | where-object Name -eq server_name).Value
[int]$CPU = ($RITM.CustomVariable | where-object Name -eq Processors).Value
[int]$MemoryGB = ($RITM.CustomVariable | where-object Name -eq MemoryGB).Value
[int]$Disk1 = ($RITM.CustomVariable | where-object Name -eq disk_1_os).Value
[int]$Disk2 = ($RITM.CustomVariable | where-object Name -eq disk_2_swap_disk).Value
[int]$Disk3 = ($RITM.CustomVariable | where-object Name -eq disk_3).Value
[int]$Disk4 = ($RITM.CustomVariable | where-object Name -eq disk_4).Value
[int]$Disk5 = ($RITM.CustomVariable | where-object Name -eq disk_5).Value
[int]$Disk6 = ($RITM.CustomVariable | where-object Name -eq disk_6).Value
[int]$Disk7 = ($RITM.CustomVariable | where-object Name -eq disk_7).Value
[int]$Disk8 = ($RITM.CustomVariable | where-object Name -eq disk_8).Value
[int]$Disk9 = ($RITM.CustomVariable | where-object Name -eq disk_9).Value
[int]$Disk10 = ($RITM.CustomVariable | where-object Name -eq disk_10).Value
[int]$Disk11 = ($RITM.CustomVariable | where-object Name -eq disk_11).Value
[int]$Disk12 = ($RITM.CustomVariable | where-object Name -eq disk_12).Value
[int]$Disk13 = ($RITM.CustomVariable | where-object Name -eq disk_13).Value
[int]$Disk14 = ($RITM.CustomVariable | where-object Name -eq disk_14).Value
[int]$Disk15 = ($RITM.CustomVariable | where-object Name -eq disk_15).Value
[int]$Disk16 = ($RITM.CustomVariable | where-object Name -eq disk_16).Value
$VM = Get-VM -Name $HostName* | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
Write-Warning -Message ("VM: " + $VM.Name)
If($CPU -ne 0){
Write-Verbose -Message ($VM.Name + " attempt increasing CPU to " + $CPU)
try {
$VM | Set-VM -NumCpu $CPU
}
catch {
<#Do this if a terminating exception happens#>
}
}
If($MemoryGB -ne 0){
Write-Verbose -Message ($VM.Name + " attempt increasing MemoryGB to " + $CPU)
try {
$VM | Set-VM -MemoryGB $MemoryGB
}
catch{
}
}
If($Disk1){
$HardDisk = $VM | Get-HardDisk -Name "Hard disk 1"
$Datastore = $HardDisk | Get-Datastore
$HardDiskIncreaseGB = $Disk1 - $HardDisk.CapacityGB
$FreePercentBefore = ($Datastore.FreeSpaceGB) / $Datastore.CapacityGB
$FreePercentAfter = ($Datastore.FreeSpaceGB - $HardDiskIncreaseGB) / $Datastore.CapacityGB
If ($FreePercentAfter -gt 0.10){
Write-Warning -Message ("Hard disk 1: Increasing from " + $HardDisk.CapacityGB + "GB to " + $Disk1 + "GB")
#Write-Warning -Message ("Datastore " + $Datastore.Name + " free space will lower from " + [math]::round($FreePercentBefore,4)*100 + "% to " + [math]::round($FreePercentAfter,4)*100 + "%")
Write-Warning -Message ("Datastore " + $Datastore.Name + " free space will lower from " + [math]::round($FreePercentBefore,4) + " to " + [math]::round($FreePercentAfter,4) + "")
$VM | Get-HardDisk -Name "Hard disk 1" | Set-HardDisk -CapacityGB $Disk1 -Confirm:$false
}
Else{
Write-Error -Message ("Hard disk 1 failed. 20% free space is required for automated disk expansions. " + $Datastore.Name + " would be " + [math]::round($FreePercentAfter,4) + ".")
}
}
If($Disk2){
#$VM | Get-HardDisk -Name "Hard disk 2" | Set-HardDisk -CapacityGB $Disk2
}
If($Disk3){
#$VM | Get-HardDisk -Name "Hard disk 3" | Set-HardDisk -CapacityGB $Disk3
}
<#
If($Disk4){
$VM | Get-HardDisk -Name "Hard disk 4" | Set-HardDisk -CapacityGB $Disk4
}
If($Disk5){
$VM | Get-HardDisk -Name "Hard disk 5" | Set-HardDisk -CapacityGB $Disk5
}
If($Disk6){
$VM | Get-HardDisk -Name "Hard disk 6" | Set-HardDisk -CapacityGB $Disk6
}
If($Disk7){
$VM | Get-HardDisk -Name "Hard disk 7" | Set-HardDisk -CapacityGB $Disk7
}
If($Disk8){
$VM | Get-HardDisk -Name "Hard disk 8" | Set-HardDisk -CapacityGB $Disk8
}
If($Disk9){
$VM | Get-HardDisk -Name "Hard disk 9" | Set-HardDisk -CapacityGB $Disk9
}
If($Disk10){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk10
}
If($Disk11){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk11
}
If($Disk12){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk12
}
If($Disk13){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk13
}
If($Disk14){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk14
}
If($Disk15){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk15
}
If($Disk16){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk16
}#>
@@ -0,0 +1,75 @@
<#
VM level:
VM Name
Storage provisioned per disk
Storage used per disk
Free capacity per disk
Disk Mode ( dependent persistent vs independent persistent )
Disk Type ( Thick, thin, lazy, eager, etc... )
Datastore
Replication Technology, if applicable
Datacenter
#>
$VMStorageList = [System.Collections.ArrayList]@()
$AllVMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
ForEach($VM in $AllVMs){
$VmObj = [PSCustomObject]@{
VMName = $VM.Name;
UsedSpaceGB = $VM.UsedSpaceGB;
ProvisionedSpaceGB = $VM.ProvisionedSpaceGB;
Datastores = ($VM | Get-Datastore).Name
DatastoreCluster = ($VM | Get-DatastoreCluster).Name
Replication = switch ( ($VM | Get-TagAssignment -Category 'VR RPO').Tag.Name ){
{$_ -like "*ABR*"} {"ABR"}
{$_ -like "*:*"} {"VR"}
Default {$false}
}
Datacenter = ($VM | Get-Datacenter).Name
Disks = $VM | Get-HardDisk | Select-Object Name,CapacityGB,@{n='StorageFormat';e={$_.StorageFormat.ToString()}},@{n='Persistence';e={$_.Persistence.ToString()}}
}
$null = $VMStorageList.Add($VmObj)
}
$VMStorageList | ConvertTo-Json -Depth 5 | Out-File "C:\temp\VMs.json"
<#
Datastore:
Name
Capacity provisioned
Capacity used
Free capacity
Associated SAN device backing ( LUN Name )
Space Reclamation rate ( MB/s )
Datacenter
#>
$AllDatastores = Get-Datastore
$DatastoreList = [System.Collections.ArrayList]@()
ForEach($Datastore in $AllDatastores){
Write-Verbose -Message ("Start " + $Datastore.Name) -Verbose
#$Metadata = ($Datastore | Get-ScsiLun | Select-Object -First 1)
If ( $Datastore.ExtensionData.info.vmfs.UnmapBandwidthSpec.FixedValue){
# if reclamation rate is enabled at fixed rate, get that rate
$ReclamationRate = ("Enabled at fixed rate: " + $Datastore.ExtensionData.info.vmfs.UnmapBandwidthSpec.FixedValue + " MB/s")
} Else {
$ReclamationRate = "UnmapBandwidthSpec is null. Enabled at Low priority: Deleted or unmapped blocks are reclaimed on the LUN at low priority"
}
$DatastoreObj = [PSCustomObject]@{
Name = $Datastore.Name;
CapacityGB = $Datastore.CapacityGB;
UsedSpaceGB = ($Datastore.CapacityGB - $Datastore.FreeSpaceGB);
FreeSpaceGB = $Datastore.FreeSpaceGB;
CanonicalName = ($Datastore | Get-ScsiLun | Select-Object -First 1).CanonicalName;
SpaceReclamationRate = $ReclamationRate;
Datacenter = ($VMHostToUse | Get-Datacenter).Name
}
$null = $DatastoreList.Add($DatastoreObj)
}
$DatastoreList | ConvertTo-Json -Depth 5 | Out-File "C:\temp\Datastores.json"
@@ -0,0 +1,270 @@
<#
.SYNOPSIS
Daily HPE OneView enclosure and server inventory for PowerBI trending and lifecycle planning.
.DESCRIPTION
Iterates across all configured HPE OneView appliances, collecting enclosure and server
hardware metadata including compute capacity, power state, and server profile assignment.
Exports timestamped CSVs and inserts into SQL each run.
Append daily runs to build a historical dataset for PowerBI trend analysis and
physical hardware purchasing / lifecycle decisions.
Appliances processed:
itdoneviewp1.nd.gov - Rack servers only (no enclosures)
itdbissyncompp1.nd.gov - Synergy enclosures + servers
itdmdnsyncompp1.nd.gov - Synergy enclosures + servers
.NOTES
Run the following DDL once to create the destination tables:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Enclosure]
CREATE TABLE [dbo].[VMware_Trends_Enclosure] (
[ReportDate] DATETIME2 NOT NULL,
[ApplianceConnection] NVARCHAR(100) NULL,
[EnclosureName] NVARCHAR(255) NOT NULL,
[EnclosureModel] NVARCHAR(255) NULL,
[EnclosureSerialNumber] NVARCHAR(100) NULL,
[Status] NVARCHAR(50) NULL,
[DeviceBayCount] INT NULL
)
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Server]
CREATE TABLE [dbo].[VMware_Trends_Server] (
[ReportDate] DATETIME2 NOT NULL,
[ApplianceConnection] NVARCHAR(100) NULL,
[EnclosureName] NVARCHAR(255) NULL,
[BayNumber] INT NULL,
[ServerHardwareName] NVARCHAR(255) NOT NULL,
[ServerName] NVARCHAR(255) NULL,
[ServerModel] NVARCHAR(255) NULL,
[ServerSerialNumber] NVARCHAR(100) NULL,
[Status] NVARCHAR(50) NULL,
[PowerState] NVARCHAR(50) NULL,
[ServerProfileName] NVARCHAR(255) NULL,
[ProcessorType] NVARCHAR(255) NULL,
[ProcessorCount] INT NULL,
[MemoryGB] DECIMAL(10,2) NULL,
[FormFactor] NVARCHAR(100) NULL
)
EnclosureName and BayNumber are NULL for rack-mounted servers not seated in an enclosure.
ServerName is the iLO/DNS hostname populated once a server profile is assigned.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string[]] $OVHostnames = @(
'itdoneviewp1.nd.gov',
'itdbissyncompp1.nd.gov',
'itdmdnsyncompp1.nd.gov'
)
[string] $OutputPath = 'C:\temp\OV_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $EnclosureTable = 'VMware_Trends_Enclosure'
[string] $ServerTable = 'VMware_Trends_Server'
[System.Management.Automation.PSCredential] $OVCredential = $PrvCred #$Secret:ndgov_svcitdvmhpe
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "OVServerInventory_$DateStamp.log") -Append
#endregion
#region --- Collect Data From All Appliances -----------------------------------
$AllEnclosureResults = [System.Collections.Generic.List[PSCustomObject]]::new()
$AllServerResults = [System.Collections.Generic.List[PSCustomObject]]::new()
foreach ($OVHostname in $OVHostnames) {
Write-Verbose "Connecting to HPE OneView: $OVHostname"
Connect-OVMgmt -Hostname $OVHostname -Credential $OVCredential -AuthLoginDomain nd.gov -LoginAcknowledge
#--- Enclosures ------------------------------------------------------------
Write-Verbose "[$OVHostname] Gathering enclosures..."
$Enclosures = Get-OVEnclosure
# Build URI map for server lookups (only populated if there are enclosures)
$EnclosureUriMap = @{}
foreach ($Enclosure in $Enclosures) {
$EnclosureUriMap[$Enclosure.uri] = $Enclosure.name
$AllEnclosureResults.Add([PSCustomObject]@{
ReportDate = $Timestamp
ApplianceConnection = $OVHostname
EnclosureName = $Enclosure.name
EnclosureModel = $Enclosure.model
EnclosureSerialNumber = $Enclosure.serialNumber
Status = $Enclosure.status
DeviceBayCount = ($Enclosure.deviceBays | Measure-Object).Count
})
}
#--- Servers ---------------------------------------------------------------
Write-Verbose "[$OVHostname] Gathering servers..."
$Servers = Get-OVServer | Where-Object { $_.serverName -like 'itdvm*' }
# Build profile URI map for this appliance
$ProfileUriMap = @{}
Get-OVServerProfile | ForEach-Object {
$ProfileUriMap[$_.uri] = $_.name
}
Write-Verbose "[$OVHostname] Processing $($Servers.Count) servers..."
foreach ($Server in $Servers) {
$EnclosureName = if ($Server.locationUri) {
$EnclosureUriMap[$Server.locationUri]
} else {
$null
}
$ProfileName = if ($Server.serverProfileUri) {
$ProfileUriMap[$Server.serverProfileUri]
} else {
$null
}
$MemoryGB = if ($null -ne $Server.memoryMb -and $Server.memoryMb -gt 0) {
[Math]::Round($Server.memoryMb / 1024, 2)
} else {
$null
}
$AllServerResults.Add([PSCustomObject]@{
ReportDate = $Timestamp
ApplianceConnection = $OVHostname
EnclosureName = $EnclosureName
BayNumber = if ($null -ne $Server.position) { [int]$Server.position } else { $null }
ServerHardwareName = $Server.name
ServerName = $Server.serverName
ServerModel = $Server.model
ServerSerialNumber = $Server.serialNumber
Status = $Server.status
PowerState = $Server.powerState
ServerProfileName = $ProfileName
ProcessorType = $Server.processorType
ProcessorCount = if ($null -ne $Server.processorCount) { [int]$Server.processorCount } else { $null }
MemoryGB = $MemoryGB
FormFactor = $Server.formFactor
})
}
Disconnect-OVMgmt
Write-Verbose "[$OVHostname] Disconnected."
}
#endregion
#region --- Export CSVs --------------------------------------------------------
$EnclosureCsv = Join-Path $OutputPath "OVEnclosures_$DateStamp.csv"
$ServerCsv = Join-Path $OutputPath "OVServers_$DateStamp.csv"
$AllEnclosureResults | Export-Csv -Path $EnclosureCsv -NoTypeInformation
$AllServerResults | Export-Csv -Path $ServerCsv -NoTypeInformation
Write-Verbose "Exported $($AllEnclosureResults.Count) enclosure records to: $EnclosureCsv"
Write-Verbose "Exported $($AllServerResults.Count) server records to: $ServerCsv"
#endregion
#region --- SQL Insert: Enclosures ---------------------------------------------
$EnclosureTable_DT = [System.Data.DataTable]::new()
$EnclosureColDefs = [ordered]@{
ReportDate = [datetime]
ApplianceConnection = [string]
EnclosureName = [string]
EnclosureModel = [string]
EnclosureSerialNumber = [string]
Status = [string]
DeviceBayCount = [int]
}
foreach ($Col in $EnclosureColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$EnclosureTable_DT.Columns.Add($Column)
}
foreach ($Row in $AllEnclosureResults) {
$DataRow = $EnclosureTable_DT.NewRow()
foreach ($Col in $EnclosureColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$EnclosureTable_DT.Rows.Add($DataRow)
}
Write-SqlTableData -ServerInstance $ServerInstance -DatabaseName $Database -SchemaName 'dbo' `
-TableName $EnclosureTable -Credential $SqlCredential -InputData $EnclosureTable_DT
Write-Verbose "Inserted $($EnclosureTable_DT.Rows.Count) enclosure records into [$Database].[dbo].[$EnclosureTable]"
#endregion
#region --- SQL Insert: Servers ------------------------------------------------
$ServerTable_DT = [System.Data.DataTable]::new()
$ServerColDefs = [ordered]@{
ReportDate = [datetime]
ApplianceConnection = [string]
EnclosureName = [string]
BayNumber = [int]
ServerHardwareName = [string]
ServerName = [string]
ServerModel = [string]
ServerSerialNumber = [string]
Status = [string]
PowerState = [string]
ServerProfileName = [string]
ProcessorType = [string]
ProcessorCount = [int]
MemoryGB = [decimal]
FormFactor = [string]
}
foreach ($Col in $ServerColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$ServerTable_DT.Columns.Add($Column)
}
foreach ($Row in $AllServerResults) {
$DataRow = $ServerTable_DT.NewRow()
foreach ($Col in $ServerColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$ServerTable_DT.Rows.Add($DataRow)
}
Write-SqlTableData -ServerInstance $ServerInstance -DatabaseName $Database -SchemaName 'dbo' `
-TableName $ServerTable -Credential $SqlCredential -InputData $ServerTable_DT
Write-Verbose "Inserted $($ServerTable_DT.Rows.Count) server records into [$Database].[dbo].[$ServerTable]"
#endregion
#region --- Cleanup ------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,188 @@
<#
.SYNOPSIS
Daily VMware Cluster metadata report for PowerBI trending and capacity planning.
.DESCRIPTION
Collects cluster-level metadata from vCenter including DRS/HA configuration,
aggregate compute capacity, and effective resource availability.
Exports a timestamped CSV and inserts into SQL each run.
Append daily runs to build a historical dataset for PowerBI trend analysis.
.NOTES
Run the following DDL once to create the destination table:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Cluster]
CREATE TABLE [dbo].[VMware_Trends_Cluster] (
[ReportDate] DATETIME2 NOT NULL,
[ClusterName] NVARCHAR(255) NOT NULL,
[Datacenter] NVARCHAR(100) NULL,
[DrsEnabled] BIT NOT NULL,
[DrsMode] NVARCHAR(50) NULL,
[HaEnabled] BIT NOT NULL,
[HostCount] INT NULL,
[EffectiveHostCount] INT NULL,
[TotalCpuCores] INT NULL,
[TotalCpuMhz] INT NULL,
[EffectiveCpuMhz] INT NULL,
[TotalMemoryGB] DECIMAL(10,2) NULL,
[EffectiveMemoryGB] DECIMAL(10,2) NULL,
[UsedMemoryGB] DECIMAL(10,2) NULL,
[VMCount] INT NULL
)
TotalCpuMhz, EffectiveCpuMhz, TotalMemoryGB, and EffectiveMemoryGB come from
vCenter's cluster summary (real-time aggregate).
UsedMemoryGB is summed from each host's current MemoryUsageGB.
TotalCpuCores is summed from each host's hardware CpuInfo.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string] $OutputPath = 'C:\temp\VM_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $Table = 'VMware_Trends_Cluster'
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "ClusterMetadataReport_$DateStamp.log") -Append
#endregion
#region --- Build Cluster -> Datacenter Lookup ---------------------------------
Write-Verbose 'Building cluster-to-datacenter map...'
$ClusterDatacenterMap = @{}
Get-Datacenter | ForEach-Object {
$DatacenterName = $_.Name
Get-Cluster -Location $_ | ForEach-Object {
$ClusterDatacenterMap[$_.Name] = $DatacenterName
}
}
#endregion
#region --- Collect Cluster Data -----------------------------------------------
Write-Verbose 'Gathering clusters...'
$AllClusters = Get-Cluster
Write-Verbose "Processing $($AllClusters.Count) clusters..."
$Results = foreach ($Cluster in $AllClusters) {
$Summary = $Cluster.ExtensionData.Summary # reuse for all summary fields
#--- Aggregate host-level stats that vCenter summary does not expose
$ClusterHosts = Get-VMHost -Location $Cluster
$TotalCpuCores = ($ClusterHosts | ForEach-Object {
$_.ExtensionData.Hardware.CpuInfo.NumCpuCores
} | Measure-Object -Sum).Sum
$UsedMemoryGB = [Math]::Round(
($ClusterHosts | Measure-Object -Property MemoryUsageGB -Sum).Sum, 2
)
$VMCount = ($ClusterHosts | ForEach-Object {
($_.ExtensionData.Vm | Measure-Object).Count
} | Measure-Object -Sum).Sum
#--- Capacity from cluster summary
$TotalCpuMhz = $Summary.TotalCpu # MHz
$EffectiveCpuMhz = $Summary.EffectiveCpu # MHz
$TotalMemoryGB = [Math]::Round($Summary.TotalMemory / 1GB, 2) # bytes -> GB
$EffectiveMemGB = [Math]::Round($Summary.EffectiveMemory / 1KB, 2) # MB -> GB
[PSCustomObject]@{
ReportDate = $Timestamp
ClusterName = $Cluster.Name
Datacenter = $ClusterDatacenterMap[$Cluster.Name]
DrsEnabled = $Cluster.DrsEnabled
DrsMode = $Cluster.DrsAutomationLevel
HaEnabled = $Cluster.HAEnabled
HostCount = $Summary.NumHosts
EffectiveHostCount = $Summary.NumEffectiveHosts
TotalCpuCores = [int]$TotalCpuCores
TotalCpuMhz = $TotalCpuMhz
EffectiveCpuMhz = $EffectiveCpuMhz
TotalMemoryGB = $TotalMemoryGB
EffectiveMemoryGB = $EffectiveMemGB
UsedMemoryGB = $UsedMemoryGB
VMCount = [int]$VMCount
}
}
#endregion
#region --- Export CSV ---------------------------------------------------------
$OutputFile = Join-Path $OutputPath "ClusterMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) cluster records to: $OutputFile"
#endregion
#region --- SQL Insert ---------------------------------------------------------
$DataTable = [System.Data.DataTable]::new()
$ColDefs = [ordered]@{
ReportDate = [datetime]
ClusterName = [string]
Datacenter = [string]
DrsEnabled = [bool]
DrsMode = [string]
HaEnabled = [bool]
HostCount = [int]
EffectiveHostCount = [int]
TotalCpuCores = [int]
TotalCpuMhz = [int]
EffectiveCpuMhz = [int]
TotalMemoryGB = [decimal]
EffectiveMemoryGB = [decimal]
UsedMemoryGB = [decimal]
VMCount = [int]
}
foreach ($Col in $ColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$DataTable.Columns.Add($Column)
}
foreach ($Row in $Results) {
$DataRow = $DataTable.NewRow()
foreach ($Col in $ColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$DataTable.Rows.Add($DataRow)
}
$SqlParams = @{
ServerInstance = $ServerInstance
DatabaseName = $Database
SchemaName = 'dbo'
TableName = $Table
Credential = $SqlCredential
InputData = $DataTable
}
Write-SqlTableData @SqlParams
Write-Verbose "Inserted $($DataTable.Rows.Count) cluster records into [$Database].[dbo].[$Table]"
#endregion
#region --- Cleanup -------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,212 @@
<#
.SYNOPSIS
Daily VMware Host metadata report for PowerBI trending and hardware capacity planning.
.DESCRIPTION
Collects ESXi host metadata from vCenter including hardware, compute capacity, and
version information. Exports a timestamped CSV and inserts into SQL each run.
Append daily runs to build a historical dataset for PowerBI trend analysis and
physical hardware purchasing / lifecycle decisions.
.NOTES
Run the following DDL once to create the destination table:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Host]
CREATE TABLE [dbo].[VMware_Trends_Host] (
[ReportDate] DATETIME2 NOT NULL,
[HostName] NVARCHAR(255) NOT NULL,
[Datacenter] NVARCHAR(100) NULL,
[Cluster] NVARCHAR(100) NULL,
[ConnectionState] NVARCHAR(50) NULL,
[PowerState] NVARCHAR(50) NULL,
[InMaintenanceMode] BIT NOT NULL,
[Model] NVARCHAR(255) NULL,
[ProcessorType] NVARCHAR(255) NULL,
[CpuSockets] INT NULL,
[CoresPerSocket] INT NULL,
[TotalCpuCores] INT NULL,
[CpuMhz] INT NULL,
[TotalCpuMhz] INT NULL,
[MemoryTotalGB] DECIMAL(10,2) NULL,
[MemoryUsageGB] DECIMAL(10,2) NULL,
[VMCount] INT NULL,
[EsxiVersion] NVARCHAR(50) NULL,
[EsxiBuild] NVARCHAR(50) NULL,
[UptimeDays] DECIMAL(10,2) NULL
)
MemoryUsageGB reflects real-time memory consumed by running VMs at the time of collection.
UptimeDays will be NULL for hosts that are powered off or disconnected.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string] $OutputPath = 'C:\temp\VM_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $Table = 'VMware_Trends_Host'
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "VMHostMetadataReport_$DateStamp.log") -Append
#endregion
#region --- Build VMHost -> Cluster/Datacenter Lookups (avoids per-host queries) -
Write-Verbose 'Building host-to-cluster and host-to-datacenter maps...'
$HostClusterMap = @{}
$HostDatacenterMap = @{}
Get-Datacenter | ForEach-Object {
$DatacenterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostDatacenterMap[$_.Name] = $DatacenterName
}
}
Get-Cluster | ForEach-Object {
$ClusterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostClusterMap[$_.Name] = $ClusterName
}
}
#endregion
#region --- Collect Host Data --------------------------------------------------
Write-Verbose 'Gathering hosts...'
$AllHosts = $HostDatacenterMap.Keys | ForEach-Object { Get-VMHost -Name $_ }
Write-Verbose "Processing $($AllHosts.Count) hosts..."
$Results = foreach ($VMHost in $AllHosts) {
$Ext = $VMHost.ExtensionData # single API object -- reuse for all fields
#--- CPU info from hardware summary
$CpuSockets = $Ext.Hardware.CpuInfo.NumCpuPackages
$TotalCpuCores = $Ext.Hardware.CpuInfo.NumCpuCores
$CoresPerSocket = if ($CpuSockets -gt 0) { [int]($TotalCpuCores / $CpuSockets) } else { $null }
$CpuMhz = $Ext.Hardware.CpuInfo.Hz / 1000000 # Hz -> MHz
$TotalCpuMhz = $Ext.Summary.Hardware.CpuMhz * $TotalCpuCores
#--- Memory
$MemoryTotalGB = [Math]::Round($VMHost.MemoryTotalGB, 2)
$MemoryUsageGB = [Math]::Round($VMHost.MemoryUsageGB, 2)
#--- VM count on this host right now
$VMCount = ($Ext.Vm | Measure-Object).Count
#--- Uptime (null when host is powered off / disconnected)
$UptimeDays = $null
$BootTime = $Ext.Runtime.BootTime
if ($null -ne $BootTime) {
$UptimeDays = [Math]::Round(($RunDate - $BootTime).TotalDays, 2)
}
[PSCustomObject]@{
ReportDate = $Timestamp
HostName = $VMHost.Name
Datacenter = $HostDatacenterMap[$VMHost.Name]
Cluster = $HostClusterMap[$VMHost.Name]
ConnectionState = $VMHost.ConnectionState
PowerState = $VMHost.PowerState
InMaintenanceMode = $VMHost.ExtensionData.Runtime.InMaintenanceMode
Model = $Ext.Hardware.SystemInfo.Model
ProcessorType = $VMHost.ProcessorType
CpuSockets = $CpuSockets
CoresPerSocket = $CoresPerSocket
TotalCpuCores = $TotalCpuCores
CpuMhz = [int]$CpuMhz
TotalCpuMhz = $TotalCpuMhz
MemoryTotalGB = $MemoryTotalGB
MemoryUsageGB = $MemoryUsageGB
VMCount = $VMCount
EsxiVersion = $VMHost.Version
EsxiBuild = $VMHost.Build
UptimeDays = $UptimeDays
}
}
#endregion
#region --- Export CSV ---------------------------------------------------------
$OutputFile = Join-Path $OutputPath "VMHostMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) host records to: $OutputFile"
#endregion
#region --- SQL Insert ---------------------------------------------------------
$DataTable = [System.Data.DataTable]::new()
$ColDefs = [ordered]@{
ReportDate = [datetime]
HostName = [string]
Datacenter = [string]
Cluster = [string]
ConnectionState = [string]
PowerState = [string]
InMaintenanceMode = [bool]
Model = [string]
ProcessorType = [string]
CpuSockets = [int]
CoresPerSocket = [int]
TotalCpuCores = [int]
CpuMhz = [int]
TotalCpuMhz = [int]
MemoryTotalGB = [decimal]
MemoryUsageGB = [decimal]
VMCount = [int]
EsxiVersion = [string]
EsxiBuild = [string]
UptimeDays = [decimal]
}
foreach ($Col in $ColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$DataTable.Columns.Add($Column)
}
foreach ($Row in $Results) {
$DataRow = $DataTable.NewRow()
foreach ($Col in $ColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$DataTable.Rows.Add($DataRow)
}
$SqlParams = @{
ServerInstance = $ServerInstance
DatabaseName = $Database
SchemaName = 'dbo'
TableName = $Table
Credential = $SqlCredential
InputData = $DataTable
}
Write-SqlTableData @SqlParams
Write-Verbose "Inserted $($DataTable.Rows.Count) host records into [$Database].[dbo].[$Table]"
#endregion
#region --- Cleanup -------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,299 @@
<#
.SYNOPSIS
Daily VM metadata report for PowerBI trending and hardware capacity planning.
.DESCRIPTION
Collects VM metadata from vCenter including compute, storage, OS, and VMware Tools
information using only data available within vCenter (no direct guest connections).
Exports a timestamped CSV each run -- append daily runs to build a historical dataset
suitable for PowerBI trend analysis and physical hardware purchasing decisions.
.PARAMETER vCenterServers
One or more vCenter server hostnames. Defaults to itdvmvc1.nd.gov and itdvmvc2.nd.gov.
.PARAMETER DatacenterFilter
Wildcard filter applied to datacenter names. Defaults to 'Primary*'.
.PARAMETER OutputPath
Directory where CSV and log files are written.
Defaults to C:\ITDSCRIPT\Reports\VMMetadata.
.PARAMETER CredentialPath
Path to a saved PSCredential XML file for unattended/scheduled runs.
Create one interactively with:
Get-Credential | Export-Clixml -Path C:\ITDSCRIPT\Creds\vCenter.xml
When omitted the script prompts for credentials.
.EXAMPLE
# Interactive run
.\VMware-VMDailyMetadataReport.ps1
.EXAMPLE
# Scheduled / unattended run
.\VMware-VMDailyMetadataReport.ps1 -CredentialPath 'C:\ITDSCRIPT\Creds\vCenter.xml'
.NOTES
Run the following DDL once to create the destination table:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_VM]
CREATE TABLE [dbo].[VMware_Trends_VM] (
[ReportDate] DATETIME2 NOT NULL,
[VMName] NVARCHAR(255) NOT NULL,
[Datacenter] NVARCHAR(100) NULL,
[Cluster] NVARCHAR(100) NULL,
[PowerState] NVARCHAR(50) NULL,
[IsSRMPlaceholder] BIT NOT NULL,
[StoragePlatform] NVARCHAR(100) NULL,
[GuestOS] NVARCHAR(255) NULL,
[vCPUs] INT NULL,
[MemoryGB] DECIMAL(10,2) NULL,
[ProvisionedSpaceGB] DECIMAL(12,2) NULL,
[UsedSpaceGB] DECIMAL(12,2) NULL,
[GuestDiskCapacityGB] DECIMAL(12,2) NULL,
[GuestDiskUsedGB] DECIMAL(12,2) NULL,
[ToolsRunningStatus] NVARCHAR(100) NULL,
[ToolsVersionStatus] NVARCHAR(100) NULL,
[ToolsVersion] NVARCHAR(50) NULL,
[Tag_DRProtection] NVARCHAR(100) NULL,
[Tag_AppName] NVARCHAR(255) NULL,
[Tag_VRDatastores] NVARCHAR(255) NULL,
[Tag_VRRPO] NVARCHAR(100) NULL,
[Tag_DTAP] NVARCHAR(50) NULL,
[Tag_StartupPriority] NVARCHAR(100) NULL,
[Tag_SRMRecoveryType] NVARCHAR(100) NULL,
[Tag_LicensingRestrictions] NVARCHAR(255) NULL
)
Guest OS disk capacity / used columns are NULL for powered-off VMs and SRM placeholders.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string] $OutputPath = 'C:\temp\VM_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $Table = 'VMware_Trends_VM'
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1
[System.Management.Automation.PSCredential] $vCenterCredential = $PrvCred
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "VMMetadataReport_$DateStamp.log") -Append
#endregion
#region --- Build VMHost -> Cluster/Datacenter Lookups (avoids per-VM API calls) -
Write-Verbose 'Building host-to-cluster and host-to-datacenter maps...'
$HostClusterMap = @{}
$HostDatacenterMap = @{}
Get-Datacenter | ForEach-Object {
$DatacenterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostDatacenterMap[$_.Name] = $DatacenterName
}
}
Get-Cluster | ForEach-Object {
$ClusterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostClusterMap[$_.Name] = $ClusterName
}
}
#endregion
#region --- Collect VM Data -----------------------------------------------------
Write-Verbose "Gathering VMs"
# Include ALL VMs (SRM placeholders flagged via column, not excluded).
# vCLS agent VMs are excluded -- they are vSphere internal and not customer workloads.
$AllVMs = Get-VM | Where-Object { $_.Name -notlike 'vCLS*' }
#--- Pre-fetch all tag assignments in one API call (avoids per-VM Get-TagAssignment)
Write-Verbose 'Pre-fetching VM tag assignments...'
$TagLookup = @{}
Get-TagAssignment -Entity $AllVMs | ForEach-Object {
$VMId = $_.Entity.Id
$Cat = $_.Tag.Category.Name
$TagName = $_.Tag.Name
if (-not $TagLookup.ContainsKey($VMId)) { $TagLookup[$VMId] = @{} }
if ($TagLookup[$VMId].ContainsKey($Cat)) {
$TagLookup[$VMId][$Cat] += "; $TagName"
} else {
$TagLookup[$VMId][$Cat] = $TagName
}
}
Write-Verbose "Processing $($AllVMs.Count) VMs..."
$Results = foreach ($VM in $AllVMs) {
$Ext = $VM.ExtensionData # single API object -- reuse for all fields
#--- SRM placeholder detection
$IsSRMPlaceholder = $Ext.Summary.Config.ManagedBy.Type -eq 'placeholderVm'
#--- Cluster / Datacenter (null-safe: standalone hosts have no cluster entry)
$ClusterName = $HostClusterMap[$VM.VMHost.Name]
$DatacenterName = $HostDatacenterMap[$VM.VMHost.Name]
#--- Tag assignments (pre-fetched; null when category not assigned to this VM)
$VMTags = if ($TagLookup.ContainsKey($VM.Id)) { $TagLookup[$VM.Id] } else { @{} }
#--- Storage platform parsed from datastore name convention: VMCLUSTER_LUN_PLATFORM_Desc
# Segment 2 = storage platform identifier (e.g. FS92, A9K).
# Cluster grouping uses the compute Cluster column -- no need to re-derive it here.
$StoragePlatforms = foreach ($DSName in $Ext.Config.DatastoreUrl.Name) {
$Segments = $DSName -split '_'
if ($Segments.Count -ge 3) { $Segments[2] }
}
$StoragePlatform = ($StoragePlatforms | Sort-Object -Unique) -join '; '
#--- VMware Tools guest disk info
# Populated only when Tools is running; null otherwise.
$GuestDiskCapacityGB = $null
$GuestDiskUsedGB = $null
if ($Ext.Guest.Disk) {
$TotalCapBytes = ($Ext.Guest.Disk | Measure-Object -Property Capacity -Sum).Sum
$TotalFreeBytes = ($Ext.Guest.Disk | Measure-Object -Property FreeSpace -Sum).Sum
$GuestDiskCapacityGB = [Math]::Round($TotalCapBytes / 1GB, 2)
$GuestDiskUsedGB = [Math]::Round(($TotalCapBytes - $TotalFreeBytes) / 1GB, 2)
}
[PSCustomObject]@{
# --- Identity & grouping
ReportDate = $Timestamp # for PowerBI time-series/trend axis
VMName = $VM.Name
Datacenter = $DatacenterName
Cluster = $ClusterName
PowerState = $VM.PowerState
IsSRMPlaceholder = $IsSRMPlaceholder
StoragePlatform = $StoragePlatform
GuestOS = $Ext.Guest.GuestFullName
# --- Compute
vCPUs = $VM.NumCpu
MemoryGB = $VM.MemoryGB
# --- Datastore-level storage
# ProvisionedSpaceGB : maximum the VM could consume (thin disks counted at max size)
# UsedSpaceGB : bytes actually committed on datastores right now
ProvisionedSpaceGB = [Math]::Round($VM.ProvisionedSpaceGB, 2)
UsedSpaceGB = [Math]::Round($VM.UsedSpaceGB, 2)
# --- Guest OS-level storage (from VMware Tools; null when Tools not running)
# GuestDiskCapacityGB : sum of all volume capacities seen inside the guest
# GuestDiskUsedGB : sum of space consumed across those volumes
GuestDiskCapacityGB = $GuestDiskCapacityGB
GuestDiskUsedGB = $GuestDiskUsedGB
# --- VMware Tools
# ToolsRunningStatus : guestToolsRunning | guestToolsNotRunning | guestToolsExecutingScripts
# ToolsVersionStatus : guestToolsCurrent | guestToolsNeedUpgrade | guestToolsUnmanaged | guestToolsTooNew
# ToolsVersion : numeric build version string reported by vCenter
ToolsRunningStatus = $Ext.Guest.ToolsRunningStatus
ToolsVersionStatus = $Ext.Guest.ToolsVersionStatus
ToolsVersion = $Ext.Guest.ToolsVersion
# --- vCenter Tags
Tag_DRProtection = $VMTags['DR Protection']
Tag_AppName = $VMTags['AppName']
Tag_VRDatastores = $VMTags['VR Datastores']
Tag_VRRPO = $VMTags['VR RPO']
Tag_DTAP = $VMTags['DTAP']
Tag_StartupPriority = $VMTags['StartupPriority']
Tag_SRMRecoveryType = $VMTags['SRM Recovery Type']
Tag_LicensingRestrictions = $VMTags['LicensingRestrictions']
}
}
#endregion
<#region --- Export CSV ---------------------------------------------------------
$OutputFile = Join-Path $OutputPath "VMMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) VM records to: $OutputFile"
#endregion
#>
#region --- SQL Insert ---------------------------------------------------------
# Build a typed DataTable so Write-SqlTableData knows each column's type
# even when nullable columns contain null values. Type inference from raw
# PSCustomObjects fails when the first row has a null in a numeric column.
$DataTable = [System.Data.DataTable]::new()
$ColDefs = [ordered]@{
ReportDate = [datetime]
VMName = [string]
Datacenter = [string]
Cluster = [string]
PowerState = [string]
IsSRMPlaceholder = [bool]
StoragePlatform = [string]
GuestOS = [string]
vCPUs = [int]
MemoryGB = [decimal]
ProvisionedSpaceGB = [decimal]
UsedSpaceGB = [decimal]
GuestDiskCapacityGB = [decimal]
GuestDiskUsedGB = [decimal]
ToolsRunningStatus = [string]
ToolsVersionStatus = [string]
ToolsVersion = [string]
Tag_DRProtection = [string]
Tag_AppName = [string]
Tag_VRDatastores = [string]
Tag_VRRPO = [string]
Tag_DTAP = [string]
Tag_StartupPriority = [string]
Tag_SRMRecoveryType = [string]
Tag_LicensingRestrictions = [string]
}
foreach ($Col in $ColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$DataTable.Columns.Add($Column)
}
foreach ($Row in $Results) {
$DataRow = $DataTable.NewRow()
foreach ($Col in $ColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$DataTable.Rows.Add($DataRow)
}
$SqlParams = @{
ServerInstance = $ServerInstance
DatabaseName = $Database
SchemaName = 'dbo'
TableName = $Table
Credential = $SqlCredential
InputData = $DataTable
}
Write-SqlTableData @SqlParams
Write-Verbose "Inserted $($DataTable.Rows.Count) VM records into [$Database].[dbo].[$Table]"
#endregion
#region --- Cleanup -------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,95 @@
$VMs = Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$SettingName = @(
"tools.setInfo.sizeLimit",
"isolation.device.edit.disable",
"isolation.device.connectable.disable",
"isolation.tools.copy.disable",
"isolation.tools.dnd.disable",
"isolation.tools.setGUIOptions.enable",
"RemoteDisplay.vnc.enabled",
"isolation.tools.paste.disable",
"isolation.tools.diskShrink.disable",
"isolation.tools.diskWiper.disable",
"log.keepOld",
"log.rotateSize"
)
$Result = [System.Collections.ArrayList]@()
ForEach ($VM in $VMs) {
$GetAdvSetting = Get-AdvancedSetting -Entity $VM -Name $SettingName | select Entity, Name, Value
$obj = [PSCustomObject]@{
'Entity' = $VM.Name
"tools.setInfo.sizeLimit" = ($GetAdvSetting | Where-Object Name -EQ 'tools.setInfo.sizeLimit').Value
"isolation.device.edit.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.device.edit.disable').Value
"isolation.device.connectable.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.device.connectable.disable').Value
"isolation.tools.copy.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.copy.disable').Value
"isolation.tools.dnd.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.dnd.disable').Value
"isolation.tools.setGUIOptions.enable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.setGUIOptions.enable').Value
"RemoteDisplay.vnc.enabled" = ($GetAdvSetting | Where-Object Name -EQ 'RemoteDisplay.vnc.enabled').Value
"isolation.tools.paste.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.paste.disable').Value
"isolation.tools.diskShrink.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.diskShrink.disable').Value
"isolation.tools.diskWiper.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.diskWiper.disable').Value
"log.keepOld" = ($GetAdvSetting | Where-Object Name -EQ 'log.keepOld').Value
"log.rotateSize" = ($GetAdvSetting | Where-Object Name -EQ 'log.rotateSize').Value
}
$Result.Add($obj)
}
$Result
<# Blank Loop
ForEach-Object( ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'' -ne "VALUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name '' -Value TRUE -Confirm:$false -Force:$true
}
#>
# remediate VMs
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'tools.setInfo.sizeLimit' -ne 1048576 }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'tools.setInfo.sizeLimit' -Value '1048576' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.device.edit.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.device.edit.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.device.connectable.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.device.connectable.disable' -Value TRUE -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.copy.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.copy.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.dnd.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.dnd.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.setGUIOptions.enable' -ne "FALSE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.setGUIOptions.enable' -Value 'FALSE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'RemoteDisplay.vnc.enabled' -ne "FALSE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'RemoteDisplay.vnc.enabled' -Value 'FALSE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.paste.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.paste.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.diskShrink.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.diskShrink.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.diskWiper.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.diskWiper.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'log.keepOld' -ne "10" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'log.keepOld' -Value '10' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'log.rotateSize' -ne "1024000" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'log.rotateSize' -Value '1024000' -Confirm:$false -Force:$true
}
@@ -0,0 +1,56 @@
$VMHostNames = @"
itdbisvm-gen05.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
# set maintenance and disable alarms
Get-VMHost -Name $VMHostNames | Set-VMHost -State "Maintenance" -RunAsync
ForEach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost -Name $VMHostname
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
}
#Create Management Switch And Move Adapter
ForEach ($VMHostName in $VMHostNames) {
$vmnic0 = Get-VMHostNetworkAdapter -VMHost $VMHostName -Name "vmnic0"
$vmk0 = Get-VMHost $VMHostName | Get-VMHostNetworkAdapter -Name vmk0
New-VirtualSwitch -VMHost $VMHostName -Name "sSwitch-MGMT"
Get-VirtualSwitch -VMHost $VMHostName -Name "sSwitch-MGMT" | New-VirtualPortGroup -Name "sPG-MGMT"
$MGMTPG = Get-VirtualSwitch -VMHost $VMHostName -Name "sSwitch-MGMT" | Get-VirtualPortGroup -Name "sPG-MGMT"
$MGMTSwitch = Get-VirtualSwitch -VMHost $VMHostName -Name "sSwitch-MGMT"
Add-VirtualSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $vmnic0 -VirtualSwitch $MGMTSwitch -Confirm:$false
Add-VirtualSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $vmnic0 -VirtualSwitch $MGMTSwitch -VirtualNicPortgroup $MGMTPG -VMHostVirtualNic $vmk0 -Confirm:$false
}
# remove vmk1 and vmk2
ForEach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Get-VMHostNetworkAdapter -Name vmk1, vmk2 | Remove-VMHostNetworkAdapter -Confirm:$false
}
# remove distributed switches
$BackupVDSwitch = Get-VDSwitch -Name 'dvSwitch-SDC-Backup'
$DataVDSwitch = Get-VDSwitch -Name 'dvSwitch-SDC-Data-Server'
$vMotionVDSwitch = Get-VDSwitch -Name 'dvSwitch-SDC-VMotion'
$MgmtVDSwitch = Get-VDSwitch -Name 'dvSwitch-SDC-MGMT'
ForEach ($VMHostName in $VMHostNames) {
Remove-VDSwitchVMHost -VDSwitch $BackupVDSwitch -VMHost $VMHostName -Confirm:$false
Remove-VDSwitchVMHost -VDSwitch $DataVDSwitch -VMHost $VMHostName -Confirm:$false
Remove-VDSwitchVMHost -VDSwitch $vMotionVDSwitch -VMHost $VMHostName -Confirm:$false
Remove-VDSwitchVMHost -VDSwitch $MgmtVDSwitch -VMHost $VMHostName -Confirm:$false
}
# remove from inventory
ForEach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Remove-VMHost -Confirm:$false
}
# scrub DNS
# scrub Passwordstate
# scrub Active Directory
# send storage team request to remove SAN
# send cohesity team request to remove host mappings for backup vmkernels
@@ -0,0 +1,15 @@
$cluster = Get-Cluster
$hosti = $cluster | Get-VMHost
$report333 = foreach ($esxi in $hosti) {
Get-VMHosthba -VMHost $esxi -type FibreChannel | where{$_.STatus -eq 'online'} |
Select @{N="Host";E={$esxi.Name}},
@{N='HBA Node WWN';E={$wwn = "{0:X}" -f $_.NodeWorldWideName; (0..7 | %{$wwn.Substring($_*2,2)}) -join ':'}},
@{N='HBA Node WWP';E={$wwp = "{0:X}" -f $_.PortWorldWideName; (0..7 | %{$wwp.Substring($_*2,2)}) -join ':'}}
}
@@ -0,0 +1,188 @@
# VMhost Advanced Options -- see OneNote for documentation
# used to customize the first host of each model per datacenter (host profile will be extracted from this), run the entire code
# also used for customizations that made host profiles angry
# add to distributed switches first
# pre create the syslog folder for each host
# set the logdir datastore/path value using code below
# if this is not the first host per datacenter, stop after logdir value, host profile SHOULD do the rest
$VMHostName = 'itdvmmdntel08.nd.gov'
$VMHost = Get-VMHost -Name $VMHostName
$VMHostCluster = $VMHost | Get-Cluster
$VMHostDatacenter = $VMHost | Get-Datacenter
$EsxCli = Get-EsxCli -VMHost $VMHostName -V2
# set advanced settings
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name UserVars.ESXiShellInteractiveTimeOut | Set-AdvancedSetting -Value 300 -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name UserVars.ESXiShellTimeOut | Set-AdvancedSetting -Value 900 -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name UserVars.DcuiTimeOut | Set-AdvancedSetting -Value 600 -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Config.HostAgent.plugins.solo.enableMob | Set-AdvancedSetting -Value false -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Config.HostAgent.plugins.hostsvc.esxAdminsGroupAutoAdd | Set-AdvancedSetting -Value false -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Config.HostAgent.plugins.hostsvc.esxAdminsGroup | Set-AdvancedSetting -Value "" -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Config.HostAgent.plugins.vimsvc.authValidateInterval | Set-AdvancedSetting -Value 90 -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.certificate.strictX509Compliance | Set-AdvancedSetting -Value true -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logLevel | Set-AdvancedSetting -Value info -Confirm:$false
# scratch and syslog
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' {
$ScratchPath = '/vmfs/volumes/5ef4c13d-6318953e-620e-6cc217314910/scratch'
$LogDirDatastore = 'VMALL1_006_FS92_SCRATCH'
}
'Secondary Datacenter' {
$ScratchPath = '/vmfs/volumes/5ef4be61-1084f19b-ca0a-6cc217314690/scratch'
$LogDirDatastore = 'VMALL2_007_FS92_SCRATCH'
}
'DCN Datacenter' {
$ScratchPath = '/vmfs/volumes/6463c3f5-1ffe01b3-3837-e0071befea78/scratch'
$LogDirDatastore = 'VMDCN1_40_V5K'
}
'Grand Forks Vantis' {
$ScratchPath = '[VMVNTS_040_V5K] syslog/itdvmgfvnts02'
$LogDirDatastore = 'VMVNTS_040_V5K'
}
'Test Primary Datacenter' {
$ScratchPath = '/vmfs/volumes/5f36e52c-93f96f5c-3c43-6cc2172ed4d0/scratch'
$LogDirDatastore = 'VMTEST_001_FS92_SCRATCH'
}
'Test Secondary Datacenter' {
$ScratchPath = '/vmfs/volumes/5f36e52c-93f96f5c-3c43-6cc2172ed4d0/scratch'
$LogDirDatastore = 'VMTEST_001_FS92_SCRATCH'
}
}
#Get-VMHost -Name $VMHostname | Get-AdvancedSetting -Name ScratchConfig.ConfiguredScratchLocation | Set-AdvancedSetting -Value ($ScratchPath + $VMhostName.split('.')[0]) -Confirm:$false
#Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logDir | Set-AdvancedSetting -Value "$LogDirDatastore] syslog" -Confirm:$false
#Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logDirUnique | Set-AdvancedSetting -Value true -Confirm:$false
# 2024 syslog values
$VMHostNameShort = $VMHostName.split('.')[0]
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logDir | Set-AdvancedSetting -Value ("[$LogDirDatastore] syslog/$VMHostNameShort") -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logDirUnique | Set-AdvancedSetting -Value false -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logHost | Set-AdvancedSetting -Value "tcp://itdvmlogging1.nd.gov:514" -Confirm:$false
# Pub 1075 requirements, no longer included in host profile
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name "Security.PasswordQualityControl" | Set-AdvancedSetting -Value "retry=3 min=disabled,disabled,disabled,disabled,14" -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name "Security.AccountLockFailures" | Set-AdvancedSetting -Value "3" -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name "Security.PasswordHistory" | Set-AdvancedSetting -Value "24" -Confirm:$false
# static routes for backups
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' { $Environment = 'Production-General' }
'Secondary Datacenter' { $Environment = 'Production-General' }
'DCN Datacenter' { $Environment = 'Production-DCN' }
'Grand Forks Vantis' { $Environment = $null }
'Test Primary Datacenter' { $Environment = 'Sandbox' }
'Test Secondary Datacenter' { $Environment = 'Sandbox' }
}
switch ($Environment) {
'Production-General' {
$vmk0IP = (Resolve-DnsName -Name $VMHostName).IPAddress
$vmk1IP = '10.8.142.' + $vmk0IP.split('.')[3]
$vmk2IP = '10.2.170.' + $vmk0IP.split('.')[3]
}
}
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' {
Get-VMHost -Name $VMHostname | New-VMHostNetworkAdapter -VirtualSwitch 'dvSwitch-PDC-VMotion' -PortGroup 'dvPG_PDC_VMotion' -IP $vmk1IP -SubnetMask 255.255.254.0 -VMotionEnabled $true
Get-VMHost -Name $VMHostname | New-VMHostNetworkAdapter -VirtualSwitch 'dvSwitch-PDC-Backup' -PortGroup 'dvPG_3534_10.2.170.0_24' -IP $vmk2IP -SubnetMask 255.255.255.0
}
'Secondary Datacenter' {
Get-VMHost -Name $VMHostname | New-VMHostNetworkAdapter -VirtualSwitch 'dvSwitch-SDC-VMotion' -PortGroup 'dvPG_SDC_VMotion' -IP $vmk1IP -SubnetMask 255.255.254.0 -VMotionEnabled $true
Get-VMHost -Name $VMHostname | New-VMHostNetworkAdapter -VirtualSwitch 'dvSwitch-SDC-Backup' -PortGroup 'dvPG_3534_10.2.170.0_24' -IP $vmk2IP -SubnetMask 255.255.255.0
}
'DCN Datacenter' {
}
'Grand Forks Vantis' {
}
}
# set vmkernel capabilities
Get-VMHostNetworkAdapter -VMHost $VMHostName -Name vmk0 | Set-VMHostNetworkAdapter -VSphereReplicationEnabled $true -VSphereReplicationNfcEnabled $true -Confirm:$false
Get-VMHostNetworkAdapter -VMHost $VMHostName -Name vmk1 | Set-VMHostNetworkAdapter -VMotionEnabled $true -Confirm:$false
Get-VMHostNetworkAdapter -VMHost $VMHostName -Name vmk2 | Set-VMHostNetworkAdapter -VSphereBackupNfcEnabled $true -Confirm:$false
# core dump - disable coredump file, enable network coredump
$CoreDumpArgs = $EsxCli.system.coredump.file.set.CreateArgs()
$CoreDumpArgs.enable = $false
$EsxCli.system.coredump.file.set.invoke($CoreDumpArgs)
$CoreDumpArgs = $EsxCli.system.coredump.network.set.CreateArgs()
$CoreDumpArgs.serverport = 6500
$CoreDumpArgs.interfacename = 'vmk0'
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' { $CoreDumpArgs.serveripv4 = '10.8.145.25' }
'Secondary Datacenter' { $CoreDumpArgs.serveripv4 = '10.8.145.26' }
'DCN Datacenter' { $CoreDumpArgs.serveripv4 = '10.8.145.25' }
'Grand Forks Vantis' { $CoreDumpArgs.serveripv4 = '10.8.145.25' }
}
#$CoreDumpArgs.serveripv4 = '10.8.145.25'
$EsxCli.system.coredump.network.set.invoke($CoreDumpArgs)
$CoreDumpArgs = $EsxCli.system.coredump.network.set.CreateArgs()
$CoreDumpArgs.enable = $true
$EsxCli.system.coredump.network.set.invoke($CoreDumpArgs)
$EsxCli.system.coredump.network.get.invoke()
# ntp - set NTP server and set service to start/stop with host
Get-VMHost -Name $VMHostName | Add-VMHostNtpServer 10.2.7.40, 10.10.10.10
Get-VMHost -Name $VMHostName | Get-VMHostService | where { $_.Key -eq "ntpd" } | Set-VMHostService -Policy On
# static route for backups
$ParamsToAdd = @{
network = '10.2.169.0/24'
}
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' { $ParamsToAdd.gateway = '10.2.170.1' }
'Secondary Datacenter' { $ParamsToAdd.gateway = '10.2.170.1' }
'DCN Datacenter' { $CoreDumpArgs.serveripv4 = '10.2.118.241' }
'Grand Forks Vantis' { $CoreDumpArgs.serveripv4 = '' }
}
$EsxCli.network.ip.route.ipv4.add.Invoke($ParamsToAdd)
<#$params = @{
network = '10.2.169.0/24' ## check subnet mask, should be /24 after collapsing the Cohesity subnets
gateway = '10.2.170.1' ## General 10.2.170.1, VDI 10.2.15.1, TEST 10.2.168.241 # DCN 10.2.118.241
} #>
#$x = $esxcli.network.ip.route.ipv4.list.Invoke() | Where-Object {$_.Interface -eq 'vmk2' -and $_.Network -eq '10.2.169.128'}
#$x | Add-Member -Name "Name" -MemberType NoteProperty -Value $VMHost.Name
#$null = $result.Add($x)
<## to remove static route
$paramsToRemove = @{
network = '10.2.169.0/24'
gateway = '10.2.170.1'
}
$EsxCli.network.ip.route.ipv4.remove.Invoke($paramsToRemove)
##>
# sshServer firewall
### 10.8.145.46 itdvmutilp3, 10.29.40.0/23 adminvpn
Get-VMHost -Name $VMHostName | Get-VMHostFirewallException -Name 'SSH Server' | Set-VMHostFirewallException -Enabled $true
$sshArgs = $EsxCli.network.firewall.ruleset.set.CreateArgs()
$sshArgs.enabled = $true
$sshArgs.allowedall = $false
$sshArgs.rulesetid = 'sshServer'
$EsxCli.network.firewall.ruleset.set.invoke($sshArgs)
$AllowedIpArgs = $EsxCli.network.firewall.ruleset.allowedip.add.CreateArgs()
$AllowedIpArgs.ipaddress = "10.8.145.46"
$AllowedIpArgs.rulesetid = 'sshServer'
$EsxCli.network.firewall.ruleset.allowedip.add.invoke($AllowedIpArgs)
$AllowedIpArgs = $EsxCli.network.firewall.ruleset.allowedip.add.CreateArgs()
$AllowedIpArgs.ipaddress = "10.29.40.0/23"
$AllowedIpArgs.rulesetid = 'sshServer'
$EsxCli.network.firewall.ruleset.allowedip.add.invoke($AllowedIpArgs)
(Get-VMHost -Name $VMHostName | Get-View).EnterLockdownMode()
<#ForEach($VMHostName in $VMHostNames){
write-warning $VMHostName
$EsxCli = Get-EsxCli -VMHost $VMHostName -V2
$esxcli.network.ip.route.ipv4.list.Invoke() | Where-Object {$_.Interface -eq 'vmk2' -and $_.Network -eq '10.2.169.128'}
}#>
@@ -0,0 +1,38 @@
$VMHostNames = @"
itdvmmdnwin11.nd.gov
itdvmmdnwin12.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
ForEach ($VMHostName in $VMHostNames) {
$RootCred = $null
$RootCred = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred
Disable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
$null = Connect-VIServer $VMHostName -Credential $RootCred
If (-not ($?)) {
Write-Warning ($VMHostName + " password failed")
}
else {
Disconnect-VIServer $VMHostName -Force -Confirm:$false
}
Enable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
}
$VMHostNames = @"
itdvmmdnwin11.nd.gov
itdvmmdnwin12.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
$VmDefaultCred = Get-Secret VMDefault
ForEach($VMHostName in $VMHostNames){
Disable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
$VMHostCred = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred
Connect-VIServer -Server $VMHostName -Credential $VmDefaultCred
Set-VMHostAccount -Server $VMHostName -UserAccount root -Password $VMHostCred.GetNetworkCredential().Password
Disconnect-VIServer -Server $VMHostname -Confirm:$false
Enable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
}
@@ -0,0 +1,3 @@
Get-VMHost | Select-Object Name,Model,MemoryTotalGB,ProcessorType,@{n='NumCpuPackages';e={$_.ExtensionData.Hardware.CpuInfo.NumCpuPackages}},@{n='CoresPerSocket';e={$_.ExtensionData.Hardware.CpuInfo.NumCpuCores / $_.ExtensionData.Hardware.CpuInfo.NumCpuPackages}},@{n='NumCpuCores';e={$_.ExtensionData.Hardware.CpuInfo.NumCpuCores}}
Get-Cluster | Where-Object {$_.Name -notlike "WINDOWS*" -or $_.Name -notlike "PS*" -or $_.Name -notlike "SQL*"} | Get-VM | Where-Object {$_.Guest.OSFullName -match "Windows"}
@@ -0,0 +1,363 @@
#----------------------------------------------------------------------------------------------------------------------------------------------------
$creds = Get-Credential
#Connect VC1
Connect-VIServer 'itdvmvc1.nd.gov' -Credential $creds
#Connect VC2
Connect-VIServer 'itdvmvc2.nd.gov' -Credential $creds
#Connect VCT1
Connect-VIServer 'itdvmvct1.nd.gov' -Credential $creds
#Connect VCT2
Connect-VIServer 'itdvmvct2.nd.gov' -Credential $creds
#Connect OneView
Connect-HPOVMgmt -Hostname 'itdoneviewp1.nd.gov' -Credential $creds -LoginAcknowledge
#----------------------------------------------------------------------------------------------------------------------------------------------------
#VMHosts to Patch
$VMHostNames = @"
itdvmmdnav04.nd.gov
itdvmmdnav05.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Disable Alarms and Disconnect CDROM
foreach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost $VMHostName
#$VMHostParent = $GetVMHost.Parent
$HostCluster = Get-Cluster -VMHost $VMHostName
<#$NewSpec = New-Object VMware.Vim.ClusterConfigSpec
$NewSpec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
$NewSpec.DasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
$NewSpec.DasConfig.AdmissionControlPolicy.AutoComputePercentages = $true
$HostCluster.ExtensionData.ReconfigureCluster($NewSpec, $true)
#>
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
$VMs = $GetVMHost | Get-VM
#Disconnect CDROM and/or VMtools ISO
foreach ($VM in $VMs) {
$GetVM = Get-VM $VM
$CDDrive = $GetVM | Get-CDDrive
if ($CDDrive | Where-Object { $_.IsoPath -Like "*vmware/isoimages*" }) {
$GetVM | Dismount-Tools
#$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
elseif ($CDDrive.HostDevice -Like "*drive*") {
$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
}
$GetVMHost = $null
}
#Move Powered Off VMs
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostParent = $VMHostDetails.Parent.Name
$VMHostMigrate = Get-Cluster $VMHostParent | Get-VMHost | Where-Object Name -NE $VMHostName | Select-Object -First 1
$VMsPoweredOff = Get-VMHost $VMHostName | Get-VM | Where-Object PowerState -EQ "PoweredOff"
If ($VMsPoweredOff) { Move-VM -VM $VMsPoweredOff -Destination $VMHostMigrate }
}
#Enter Maintenance Mode
Set-VMHost -VMHost $VMHostNames -State "Maintenance" -RunAsync
Start-Sleep -Seconds 10
#Monitor
Get-VMHost -Name $VMHostNames | Select-Object Name, ConnectionState, @{Name = "VM.count"; E = { @($_ | Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -NE "placeholderVm" }).Count } }
# Move to HostUpgradesInProgress Folder
Get-VMHost -Name $VMHostNames | Move-VMHost -Destination "HostUpgradesInProgress"
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Shutdown Host
Stop-VMHost -VMHost $VMHostNames -Confirm:$false
#Monitor
Get-VMHost $VMHostNames | Select-Object -Property Name, ConnectionState, CpuUsageMhz
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Verify OneView Server Profile Power State -EQ Off
<#foreach ($VMHostName in $VMHostNames){
$HPOVServerProfile = Get-HPOVServerProfile -Name $VMHostName
$HPOVServer = $HPOVServerProfile | Get-HPOVServer
if ($HPOVServer.powerState -EQ "On"){
$HPOVServer | Update-HPOVServer -Async
}
}#>
# ensure server power is off
foreach ($VMHostName in $VMHostNames) {
$HPOVServerProfile = Get-OVServerProfile -Name $VMHostName
$HPOVServer = $HPOVServerProfile | Get-OVServer
if ($HPOVServer.powerState -EQ "On") {
$HPOVServer | Update-OVServer -Async
}
}
#Monitor
foreach ($VMHostName in $VMHostNames) {
Get-OVServer -ServerName $VMHostName | Select-Object serverName, powerState
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Join OneView Template to Host
$HPOVtemplates = Get-OVServerProfileTemplate
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostVIserver = $VMHostDetails.Uid.Split('@')[1].Split(':')[0]
switch ($VMHostVIserver) {
itdvmvc1.nd.gov { $HPOVtemplDataCenter = "BIS" }
Default { $HPOVtemplDataCenter = "MDN" }
}
$VMHostParent = $VMHostDetails.Parent.Name
<#switch ($VMHostParent.substring(0, $VMHostParent.Length - 1)) {
Avaya { $HPOVtemplType = "Avaya" }
TEL { $HPOVtemplType = "Avaya" }
DCN { $HPOVtemplType = "DCN" }
DES { $HPOVtemplType = "DES" }
Oracle { $HPOVtemplType = "Oracle" }
SQL { $HPOVtemplType = "SQL" }
SQL2-D { $HPOVtemplType = "SQL" }
TEST { $HPOVtemplType = "Test" }
Default { $HPOVtemplType = "General" }
}#>
If($VMHostName -like "*sql*" -or $VMHostName -like "*ora*"){
$HPOVtemplType = "SQL"
}
Else{
$HPOVtemplType = "General"
}
$HPOVtemplModel = $VMHostDetails.Model.Split()[2]
$NewHPOVtempl = $HPOVtemplates | Where-Object { $_.Name -Like "*$HPOVtemplDataCenter*" -and $_.Name -Like "*$HPOVtemplType*" -and $_.Name -Like "*$HPOVtemplModel*" } | Sort-Object Name | Select-Object -Last 1
Join-OVServerProfileToTemplate -Template $NewHPOVtempl -ServerProfile $VMHostName
}
#Monitor
foreach ($VMHostName in $VMHostNames) {
Get-OVServerProfile -Name $VMHostName
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Check iLO Health Status
<#
foreach ($VMHostName in $VMHostNames){
$iLOHostName = ($VMHostName.split(".")[0])+"lo.nd.gov"
$iLoConnection = Connect-HPEiLO $iLOHostName -Credential $creds
Get-HPEiLOHealthSummary -Connection $iLoConnection | Select-Object Hostname,Status
Disconnect-HPEiLO -Connection $iLoConnection
}#>
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Update OneView Server Template
foreach ($VMHostName in $VMHostNames) {
Get-OVServerProfile -Name $VMHostName | Update-OVServerProfile -Confirm:$false -Async
Start-Sleep -Seconds 30
}
#powershell finished in 20m, but continued to run for 36min
#Monitor
foreach ($VMHostName in $VMHostNames) {
Get-OVServerProfile -Name $VMHostName | Select-Object Name, State
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Start OneView Server Profile
foreach ($VMHostName in $VMHostNames) {
$wait = $true
While ($wait -EQ $true) {
$HPOVServerProfile = Get-OVServerProfile -Name $VMHostName
if ($HPOVServerProfile.Status -NE "OK") {
$wait = $true
Start-Sleep -Seconds 60
}
else {
$wait = $false
$HPOVServerProfile | Start-OVServer -Async
}
}
}
#Monitor
foreach ($VMHostName in $VMHostNames) {
Get-OVServerProfile -Name $VMHostName
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
# manual full install of v7.0u3 now
<# ISO connected from workstation via iLO -
boot @ 9:43
initial install screen @ 10:00
ISO connect from vmutil
boot @ 10:01
initial install screen @ 10:10
#>
# remove old from vcenter inventory
ForEach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Remove-VMHost -Confirm:$false
start-sleep -Seconds 3
}
# add to vcenter
$VmDefaultCred = Get-Secret VMDefault
ForEach ($VMHostName in $VMHostNames) {
Add-VMHost -Name $VMHostName -Credential $VmDefaultCred -Location "HostUpgradesInProgress" -Force -Server $ViServer
Start-Sleep -Seconds 3
}
# license host
Get-VMHost -Name $VMHostNames | Set-VMHost -LicenseKey '2M63H-8T391-P8YG4-00MR4-ARNP0'
# set maintenance and disable alarms
Get-VMHost -Name $VMHostNames | Set-VMHost -State "Maintenance" -RunAsync
ForEach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost -Name $VMHostname
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
}
# Set root password
ForEach ($VMHostName in $VMHostNames) {
$VMHostCred = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred
Connect-VIServer -Server $VMHostName -Credential $VmDefaultCred
Set-VMHostAccount -Server $VMHostName -UserAccount root -Password $VMHostCred.GetNetworkCredential().Password
Disconnect-VIServer -Server $VMHostname -Confirm:$false
<#$EsxCli = Get-EsxCli -VMHost $VMHostName
/vmfs/volumes/5a737d2f-b45bb27d-7f74-e0071befea78/Scratch/itdbisvm-dcn01
$args = $EsxCli.system.account.set.CreateArgs()
$args.id = "root"
$args.password = $VMHostCred.GetNetworkCredential().Password
$args.passwordconfirmation = $VMHostCred.GetNetworkCredential().Password
$output = $EsxCli.system.account.set.invoke(@{
id = $VMHostCred.UserName;
password = $VMHostCred.GetNetworkCredential().Password;
passwordconfirmation = $VMHostCred.GetNetworkCredential().Password;
})#>
}
#Patch via Update Manager
#Monitor ConnectionState
foreach ($VMHostName in $VMHostNames) {
$VMHost = Get-VMHost $VMHostName
$VMHost | Select-Object -Property Name, ConnectionState
}
foreach ($VMHostName in $VMHostNames) {
$VMHost = Get-VMHost $VMHostName
$VMHostVIserver = $VMHost.Uid.Split('@')[1].Split(':')[0]
#$VMHostBaseline = Get-Baseline -Server $VMHostVIserver | Where-Object Name -Like "*ESXi 6.5.0*"
$VMHostBaselineUpgrade = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-ProLiant" }
$VMHostBaselinePatch = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3 Patch" }
$VMHostBaselineAll = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-ProLiant" -or $_.Name -EQ "7.0U3 Patch"}
Attach-Baseline -Baseline $VMHostBaselineUpgrade -Entity $VMHost
Attach-Baseline -Baseline $VMHostBaselinePatch -Entity $VMHost
}
#Remediate Baseline --- Do this in the GUI with all hosts in the same folder
<#
ForEach($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Scan-Inventory -Entity $VMHost
}
ForEach($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Stage-Patch -Entity $VMHost -Baseline $VMhostBaselineUpgrade
Stage-Patch -Entity $VMHost -Baseline $VMhostBaselinePatch -RunASync
}
ForEach($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Remediate-Inventory -Entity $VMHost -Baseline $VMHostBaselineAll -RunAsync -Confirm:$false
}#>
#Monitor
Get-Task | Where-Object Name -Like "*Remediate*"
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Attach Host Profile and Test Compliance
foreach ($VMHostName in $VMHostNames) {
$CurrentHostProfiles = Get-VMHostProfile
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostVIserver = $VMHostDetails.Uid.Split('@')[1].Split(':')[0]
switch ($VMHostVIserver) {
itdvmvc1.nd.gov { $VMHostVIserver = "BIS" }
Default { $VMHostVIServer = "MDN" }
}
$VMHostParent = $VMHostDetails.Parent.Name
switch ($VMHostParent.substring(0, $VMHostParent.Length - 1)) {
Avaya { $VMHostProfile = "Avaya" }
TEL { $VMHostProfile = "TEL" }
Default { $VMHostProfile = "General" }
}
#$VMHostBuild = $VMHostDetails.Build
#$VMHostVersion = $VMHostDetails.Version
#$VMHostProfileName = $CurrentHostProfiles | Where-Object {$_.Name -Like "*$VMHostVIserver*" -and $_.Name -Like "*$VMHostVersion*" -and $_.Name -Like "*$VMHostBuild*" -and $_.Name -Like "*$VMHostProfile*"} | Sort-Object Name | Select-Object -First 1
$VMHostProfileName = $CurrentHostProfiles | Where-Object { $_.Name -like "*$VMHostVIserver*" -and $_.Name -Like "*7.0.3*" -and $_.Name -like "*$VMHostProfile*" -and $_.Name -like "*BL460c*" }
Invoke-VMHostProfile -Entity $VMHostDetails -Profile $VMHostProfileName -AssociateOnly -Confirm:$false
}
# import host customization csv
foreach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Test-VMHostProfileCompliance
}
#Remediate Host Profile
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostProfileCompliance = $VMhostDetails | Test-VMHostProfileCompliance #### ???????
if ($VMHostProfileCompliance.ExtensionData.ComplianceStatus -Like "*non*") {
Invoke-VMHostProfile -Entity $VMhostDetails -Confirm:$false
}
$VMhostDetails | Test-VMHostProfileCompliance
}
# reboot hosts 0_Offline, Before Upgrade v7.0U3h
Get-VMHost -Name $VMHostNames | Restart-VMHost -Confirm:$false
#Test Host Profile Compliance
foreach ($VMHostName in $VMHostNames) {
Get-VMHost $VMHostName | Test-VMHostProfileCompliance
}
# maybe reboot again sometimes maybe
Get-VMHost -Name $VMHostNames | Restart-VMHost -Confirm:$false
#Exit Maintenance Mode and Enable Alarms
Set-VMHost -VMHost $VMHostNames -State "Connected" -RunAsync
Start-Sleep -Seconds 30
foreach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost $VMHostName
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $true)
}
$GetVMHost = $null
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#$VMCluster = Get-Cluster $VMHostParent #| Set-Cluster -HAAdmissionControlEnabled:$false -Confirm:$false
#$HAFailoverHost = Get-VMHost | Where-Object {$_.Id -Match ((Get-Cluster $VMHostParent).extensiondata.configuration.dasconfig.admissioncontrolpolicy.failoverhosts.value)}
#get-vmhost | where-object {$_.id -eq ($vmcluster.extensiondata.configuration.dasconfig.admissioncontrolpolicy.failoverhosts.value)}
<#
foreach ($VMHostProfile in $VMHostProfiles){
Export-VMHostProfile -FilePath $FilePath$Profile".xml" -Profile $VMHostProfile
}
Import-VMHostProfile -FilePath $FilePath"TestHostProfile.xml" -Name "Test Scripting"
#>
@@ -0,0 +1,481 @@
#----------------------------------------------------------------------------------------------------------------------------------------------------
$creds = Get-Credential
#Connect VC1
Connect-VIServer 'itdvmvc1.nd.gov' -Credential $creds
#Connect VC2
Connect-VIServer 'itdvmvc2.nd.gov' -Credential $creds
#Connect VCT1
Connect-VIServer 'itdvmvct1.nd.gov' -Credential $creds
#Connect VCT2
Connect-VIServer 'itdvmvct2.nd.gov' -Credential $creds
#Connect OneView
Connect-HPOVMgmt -Hostname 'itdoneviewp1.nd.gov' -Credential $creds -LoginAcknowledge
#----------------------------------------------------------------------------------------------------------------------------------------------------
#VMHosts to Patch
$VMHostNames = @"
itdvmbiswin19.nd.gov
itdvmbislin10.nd.gov
itdvmbiswas08.nd.gov
itdvmbissql14.nd.gov
itdvmbissql15.nd.gov
itdvmbistel09.nd.gov
itdvmbisvapp04.nd.gov
itdvmbissqla02.nd.gov
itdvmbiswas09.nd.gov
itdvmbiswin08.nd.gov
itdvmbiswin14.nd.gov
itdvmbisps18.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Disable Alarms and Disconnect CDROM
foreach ($VMHostName in $VMHostNames) {
Write-Warning -Message ("Start $VMHostName")
$GetVMHost = Get-VMHost $VMHostName
#$VMHostParent = $GetVMHost.Parent
#$HostCluster = Get-Cluster -VMHost $VMHostName
<#$NewSpec = New-Object VMware.Vim.ClusterConfigSpec
$NewSpec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
$NewSpec.DasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
$NewSpec.DasConfig.AdmissionControlPolicy.AutoComputePercentages = $true
$HostCluster.ExtensionData.ReconfigureCluster($NewSpec, $true)
#>
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
$VMs = $GetVMHost | Get-VM
#Disconnect CDROM and/or VMtools ISO
foreach ($VM in $VMs) {
$GetVM = Get-VM $VM
$CDDrive = $GetVM | Get-CDDrive
if ($CDDrive | Where-Object { $_.IsoPath -Like "*vmware/isoimages*" }) {
$GetVM | Dismount-Tools
#$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
elseif ($CDDrive.HostDevice -Like "*drive*") {
$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
}
$GetVMHost = $null
}
#Move Powered Off VMs
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostParent = $VMHostDetails.Parent.Name
$VMHostMigrate = Get-Cluster $VMHostParent | Get-VMHost | Where-Object Name -NE $VMHostName | Select-Object -First 1
$VMsPoweredOff = Get-VMHost $VMHostName | Get-VM | Where-Object PowerState -EQ "PoweredOff"
If ($VMsPoweredOff) { Move-VM -VM $VMsPoweredOff -Destination $VMHostMigrate }
}
#Enter Maintenance Mode
Set-VMHost -VMHost $VMHostNames -State "Maintenance" -RunAsync
#Monitor
Get-VMHost -Name $VMHostNames | Sort-Object Name | Select-Object Name, ConnectionState, @{Name = "VM.count"; E = { @($_ | Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -NE "placeholderVm" }).Count } }
# Move to HostUpgradesInProgress Folder ??? -- if host is moved out of the cluster, may break affinity rules
#Get-VMHost -Name $VMHostNames | Move-VMHost -Destination "HostUpgradesInProgress"
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Shutdown Host
Stop-VMHost -VMHost $VMHostNames -Confirm:$false
#Monitor
Get-VMHost $VMHostNames | Select-Object -Property Name, ConnectionState, CpuUsageMhz
#----------------------------------------------------------------------------------------------------------------------------------------------------
##Verify OneView Server Profile Power State -EQ Off
#<#foreach ($VMHostName in $VMHostNames){
# $HPOVServerProfile = Get-HPOVServerProfile -Name $VMHostName
# $HPOVServer = $HPOVServerProfile | Get-HPOVServer
# if ($HPOVServer.powerState -EQ "On"){
# $HPOVServer | Update-HPOVServer -Async
# }
# }#>
#
## ensure server power is off
#foreach ($VMHostName in $VMHostNames) {
# $HPOVServerProfile = Get-OVServerProfile -Name $VMHostName.Split('.')[0]
# $HPOVServer = $HPOVServerProfile | Get-OVServer
# if ($HPOVServer.powerState -EQ "On") {
# $HPOVServer | Update-OVServer -Async
# }
#}
##Monitor
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServer -ServerName $VMHostName.split('.')[0] | Select-Object serverName, powerState
#}
##----------------------------------------------------------------------------------------------------------------------------------------------------
##Join OneView Template to Host
#$HPOVtemplates = Get-OVServerProfileTemplate
#foreach ($VMHostName in $VMHostNames) {
# $VMHostDetails = Get-VMHost -Name $VMHostName
# <#$VMHostVIserver = $VMHostDetails.Uid.Split('@')[1].Split(':')[0]
# switch ($VMHostVIserver) {
# itdvmvc1.nd.gov { $HPOVtemplDataCenter = "BIS" }
# Default { $HPOVtemplDataCenter = "MDN" }
# }#>
# $VMHostParent = $VMHostDetails.Parent.Name
# switch ($VMHostParent.substring(0, $VMHostParent.Length - 1)) {
# Avaya { $HPOVtemplType = "Avaya" }
# TEL { $HPOVtemplType = "Avaya" }
# DCN { $HPOVtemplType = "DCN" }
# DES { $HPOVtemplType = "DES" }
# Oracle { $HPOVtemplType = "Oracle" }
# SQL { $HPOVtemplType = "SQL" } # database
# SQL2-D { $HPOVtemplType = "SQL" }
# TEST { $HPOVtemplType = "Test" }
# Default { $HPOVtemplType = "General" }
# }
# $HPOVtemplModel = $VMHostDetails.Model.Split()[2]
# $NewHPOVtempl = $HPOVtemplates | Where-Object { $_.Name -Like "*$HPOVtemplDataCenter*" -and $_.Name -Like "*$HPOVtemplType*" -and $_.Name -Like "*$HPOVtemplModel*" } | Sort-Object Name | Select-Object -Last 1
# Join-OVServerProfileToTemplate -Template $NewHPOVtempl -ServerProfile $VMHostName.Split('.')[0]
#}
##Monitor
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServerProfile -Name $VMHostName.Split('.')[0]
#}
##----------------------------------------------------------------------------------------------------------------------------------------------------
##Check iLO Health Status
#<#
# foreach ($VMHostName in $VMHostNames){
# $iLOHostName = ($VMHostName.split(".")[0])+"lo.nd.gov"
# $iLoConnection = Connect-HPEiLO $iLOHostName -Credential $creds
# Get-HPEiLOHealthSummary -Connection $iLoConnection | Select-Object Hostname,Status
# Disconnect-HPEiLO -Connection $iLoConnection
# }#>
##----------------------------------------------------------------------------------------------------------------------------------------------------
##Update OneView Server Template
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServerProfile -Name $VMHostName.Split('.')[0] | Update-OVServerProfile -Confirm:$false -Async
# Start-Sleep -Seconds 30
#}
##powershell finished in 20m, but continued to run for 36min
##Monitor
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServerProfile -Name $VMHostName | Select-Object Name, State
#}
##----------------------------------------------------------------------------------------------------------------------------------------------------
##Start OneView Server Profile
#foreach ($VMHostName in $VMHostNames) {
# #$wait = $true
# #While ($wait -EQ $true) {
# $HPOVServerProfile = Get-OVServerProfile -Name $VMHostName.split('.')[0]
# #if ($HPOVServerProfile.Status -NE "OK") {
# #$wait = $true
# #Start-Sleep -Seconds 60
# #}
# #else {
# #$wait = $false
# $HPOVServerProfile | Start-OVServer -Async
# Start-Sleep -Seconds 5
# #}
# #}
#}
#
## mount ISO in iLO
#
##Monitor
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServerProfile -Name $VMHostName.Split('.')[0]
#}
##----------------------------------------------------------------------------------------------------------------------------------------------------
## manual full install of v7.0u3 now
#<# ISO connected from workstation via iLO -
# boot @ 9:43
# initial install screen @ 10:00
# ISO connect from vmutil
# boot @ 10:01
# initial install screen @ 10:10
##>
# remove old from vcenter inventory
ForEach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostNames | Remove-VMHost -Confirm:$false
}
# add to vcenter
$VmDefaultCred = Get-Secret VMDefault
ForEach ($VMHostName in $VMHostNames) {
Add-VMHost -Name $VMHostName -Credential $VmDefaultCred -Location "Secondary Datacenter" -Server $VIServer -Force
}
# license host
Get-VMHost -Name $VMHostNames | Set-VMHost -LicenseKey 'M04W3-FEJ0H-P8J61-LMRKH-C4D1K'
# not avaya '2M63H-8T391-P8YG4-00MR4-ARNP0'
# avaya '3001L-FT19L-28PGX-099A2-2XQNH'
# VDI Desktop 'L56AQ-0VH1K-488GT-0NQU2-ADG64'
Start-Sleep -seconds 3
# set maintenance and disable alarms
Get-VMHost -Name $VMHostNames | Set-VMHost -State "Maintenance" -RunAsync
ForEach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost -Name $VMHostname
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
}
# Set root password
ForEach ($VMHostName in $VMHostNames) {
$VMHostCred = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred
Connect-VIServer -Server $VMHostName -Credential $VmDefaultCred
Set-VMHostAccount -Server $VMHostName -UserAccount root -Password $VMHostCred.GetNetworkCredential().Password
Disconnect-VIServer -Server $VMHostname -Confirm:$false
<#
$EsxCli = Get-EsxCli -VMHost $VMHostName
$args = $EsxCli.system.account.set.CreateArgs()
$args.id = "root"
$args.password = $VMHostCred.GetNetworkCredential().Password
$args.passwordconfirmation = $VMHostCred.GetNetworkCredential().Password
$output = $EsxCli.system.account.set.invoke(@{
id = $VMHostCred.UserName;
password = $VMHostCred.GetNetworkCredential().Password;
passwordconfirmation = $VMHostCred.GetNetworkCredential().Password;
})
#>
}
# M.2 drives only, remove datastore1 from vmhost .... will get errors but still work
ForEach($VMHostName in $VMHostNames){
Remove-Datastore -Datastore "datastore1*" -VMHost $VMHostName -Confirm:$false
}
#Patch via Update Manager
#Monitor ConnectionState
foreach ($VMHostName in $VMHostNames) {
$VMHost = Get-VMHost $VMHostName
$VMHost | Select-Object -Property Name, ConnectionState
}
foreach ($VMHostName in $VMHostNames) {
$VMHost = Get-VMHost $VMHostName
$VMHostVIserver = $VMHost.Uid.Split('@')[1].Split(':')[0]
#$VMHostBaseline = Get-Baseline -Server $VMHostVIserver | Where-Object Name -Like "*ESXi 6.5.0*"
$VMHostBaselineUpgrade = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-Synergy" }
$VMHostBaselinePatch = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-Patch" }
$VMHostBaselineTools = Get-Baseline -Server $VMHostVIserver | Where-Object {$_.Name -EQ "VMware Tools"}
$VMHostBaselineAll = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-Synergy" -or $_.Name -EQ "vSphere 7.0U3-Patch" -or $_.Name -EQ "VMware Tools"}
Attach-Baseline -Baseline $VMHostBaselineUpgrade -Entity $VMHost
Attach-Baseline -Baseline $VMHostBaselinePatch -Entity $VMHost
Attach-Baseline -Baseline $VMHostBaselineTools -Entity $VMHost
}
#Remediate Baseline # do manually with VUM on the Host Folder
ForEach($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Scan-Inventory -Entity $VMHost -RunASync
}
Foreach ($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
#Stage-Patch -Entity $VMHost -Baseline $VMhostBaselineUpgrade -RunAsync
Stage-Patch -Entity $VMHost -Baseline $VMhostBaselinePatch -RunASync
Stage-Patch -Entity $VMHost -Baseline $VMHostBaselineTools -RunASync
}
ForEach ($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Remediate-Inventory -Entity $VMHost -Baseline $VMHostBaselinePatch -RunAsync -Confirm:$false
}
ForEach ($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Remediate-Inventory -Entity $VMHost -Baseline $VMHostBaselineTools -RunAsync -Confirm:$false
}#>
ForEach ($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Remediate-Inventory -Entity $VMHost -Baseline $VMHostBaselineAll -RunAsync -Confirm:$false
}
#Monitor
Get-Task | Where-Object Name -Like "*Remediate*"
#----------------------------------------------------------------------------------------------------------------------------------------------------
<# 2024/07/30 attach, test, invoke that works
$VMHosts = Get-Datacenter -Name Primary* | Get-VMHost | where-object Name -notlike "*av*"
ForEach($VMHost in $VMHosts){
Write-Warning -Message ("Start" + $VMHost.Name)
$VMHost | Invoke-VMHostProfile -Profile $HostProfile -AssociateOnly -Confirm:$false
$VMHost | Test-VMHostProfileCompliance
}
ForEach($VMHost in $VMHosts){
$VMHost | Invoke-VMHostProfile -Confirm:$false
}
#>
#Attach Host Profile and Test Compliance
foreach ($VMHostName in $VMHostNames) {
$CurrentHostProfiles = Get-VMHostProfile
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostVIserver = $VMHostDetails.Uid.Split('@')[1].Split(':')[0]
switch ($VMHostVIserver) {
itdvmvc1.nd.gov { $VMHostVIserver = "BIS" }
Default { $VMHostVIServer = "MDN" }
}
$VMHostParent = $VMHostDetails.Parent.Name
switch ($VMHostParent.substring(0, $VMHostParent.Length - 1)) {
Avaya { $VMHostProfile = "Avaya" }
TEL { $VMHostProfile = "TEL" }
Default { $VMHostProfile = "General" }
}
#$VMHostBuild = $VMHostDetails.Build
#$VMHostVersion = $VMHostDetails.Version
#$VMHostProfileName = $CurrentHostProfiles | Where-Object {$_.Name -Like "*$VMHostVIserver*" -and $_.Name -Like "*$VMHostVersion*" -and $_.Name -Like "*$VMHostBuild*" -and $_.Name -Like "*$VMHostProfile*"} | Sort-Object Name | Select-Object -First 1
$VMHostProfileName = $CurrentHostProfiles | Where-Object { $_.Name -like "*$VMHostVIserver*" -and $_.Name -Like "*7.0.3*" -and $_.Name -like "*$VMHostProfile*" -and $_.Name -like "*Synergy*" } | Sort-Object -Descending Name | Select -First 1
Invoke-VMHostProfile -Entity $VMHostDetails -Profile $VMHostProfileName -AssociateOnly -Confirm:$false
}
# import host customization csv now
# then continue
foreach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Test-VMHostProfileCompliance
}
#Remediate Host Profile
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostProfileCompliance = $VMhostDetails | Test-VMHostProfileCompliance #### ???????
if ($VMHostProfileCompliance.ExtensionData.ComplianceStatus -Like "*non*") {
Invoke-VMHostProfile -Entity $VMhostDetails -Confirm:$false
}
$VMhostDetails | Test-VMHostProfileCompliance
}
#Test Host Profile Compliance
foreach ($VMHostName in $VMHostNames) {
Get-VMHost $VMHostName | Test-VMHostProfileCompliance
}
# Host requires reboot before previously applied configuration changes will take effect
Get-VMHost -Name $VMHostNames | Restart-VMHost -Confirm:$false
#Test Host Profile Compliance again
foreach ($VMHostName in $VMHostNames) {
Get-VMHost $VMHostName | Test-VMHostProfileCompliance
}
# move hosts back to their clusters
ForEach($VMHostName in $VMHostNames){
switch ($VMHostName.substring(8).split('.')[0].substring(0,2)){
'ps' {$ClusterStr = "PS"}
}
switch ($VMHostVIserver){
'itdvmvc1.nd.gov' {$ClusterInt = 1}
'itdvmvc2.nd.gov' {$ClusterInt = 2}
}
$ClusterName = $ClusterStr + $ClusterInt
Move-VMHost -VMHost $VMHostName -Destination (Get-Cluster -Name $ClusterName)
}
# restart again because HA is being weird
Get-VMHost -Name $VMHostNames | Restart-VMHost -Confirm:$false
# monitor
Get-VMHost -Name $VMHostNames
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Monitor
Get-VMHost -Name $VMHostNames | Sort-Object Name | Select-Object Name, ConnectionState, @{Name = "VM.count"; E = { @($_ | Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -NE "placeholderVm" }).Count } }
#Exit Maintenance Mode and Enable Alarms
ForEach($VMHostName in $VMHostNames){
Set-VMHost -VMHost $VMHostName -State "Connected" -RunAsync
Start-Sleep -Seconds 2
}
foreach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost $VMHostName
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $true)
}
$GetVMHost = $null
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#$VMCluster = Get-Cluster $VMHostParent #| Set-Cluster -HAAdmissionControlEnabled:$false -Confirm:$false
#$HAFailoverHost = Get-VMHost | Where-Object {$_.Id -Match ((Get-Cluster $VMHostParent).extensiondata.configuration.dasconfig.admissioncontrolpolicy.failoverhosts.value)}
#get-vmhost | where-object {$_.id -eq ($vmcluster.extensiondata.configuration.dasconfig.admissioncontrolpolicy.failoverhosts.value)}
<#
foreach ($VMHostProfile in $VMHostProfiles){
Export-VMHostProfile -FilePath $FilePath$Profile".xml" -Profile $VMHostProfile
}
Import-VMHostProfile -FilePath $FilePath"TestHostProfile.xml" -Name "Test Scripting"
#>
#Get-OVServer -ov x
#$x | select Name,processorType,processorCount,processorCoreCount,serialnumber,memorymb,generation
## disable alarms entire datacenter
$VMHostNames=(Get-Datacenter primary* | Get-VMHost).Name
foreach ($VMHostName in $VMHostNames) {
Write-Warning -Message ("Start $VMHostName")
$GetVMHost = Get-VMHost $VMHostName
#$VMHostParent = $GetVMHost.Parent
#$HostCluster = Get-Cluster -VMHost $VMHostName
<#$NewSpec = New-Object VMware.Vim.ClusterConfigSpec
$NewSpec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
$NewSpec.DasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
$NewSpec.DasConfig.AdmissionControlPolicy.AutoComputePercentages = $true
$HostCluster.ExtensionData.ReconfigureCluster($NewSpec, $true)
#>
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
}
## enable alarms for entire datacenter
$VMHostNames = (Get-VMHost).Name
foreach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost $VMHostName
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $true)
}
$GetVMHost = $null
}
@@ -0,0 +1,971 @@
$IaasAuto = Get-Credential -UserName ndgov\svcitdiaasauto
$StdCred = $IaasAuto
$PrvCred = $IaasAuto
$FQDNs = @"
itdzmtest111.ndtestdev.nd.dev
"@
$FQDNs = ConvertTo-Array -MultiLineString $FQDNs
ForEach ($FQDN in $FQDNs) {
Write-Warning "[$FQDN]:Start"
$SPCred = $StdCred
$ADCred = $PrvCred
$PSCred = $PrvCred
$VMCred = $PrvCred
$CcmCred = $PrvCred
#>
<# Get Credentials
$SPCred = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite'
$ADCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation'
$PSCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation'
$IBCred = New-Object System.Management.Automation.PSCredential ($PSCred.UserName.split('\')[1], $ADCred.Password)
$VMCred = Get-AutomationPSCredential -Name 'VMware Auto'
$CcmCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation'#>
#>
Clear-DnsClientCache
$SharePointList = Get-ITDVMwareSharePointVMGuestList -Credential $SPCred
Write-Warning ("SPList count: " + $SharePointList.count)
$SPItem = $SharePointList | Where-Object Title -EQ $FQDN
If ($null -eq $SPItem.Cluster) {
Write-Error "VMware Cluster not specified in SharePoint"
Stop
}
Write-Warning $SPItem
$HostName = $FQDN.split('.')[0]
# Infoblox
[Net.IpAddress]$NetworkId = $SPItem.CIDR.split('/')[0]
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
$SubnetMaskInt = $SPItem.Cidr.split('/')[1]
$Int64 = ([convert]::ToInt64(('1' * $SubnetMaskInt + '0' * (32 - $SubnetMaskInt)), 2))
[Net.IPAddress]$SubnetMask = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($Int64 / 16777216)).ToString(),
([math]::Truncate(($Int64 % 16777216) / 65536)).ToString(),
([math]::Truncate(($Int64 % 65536) / 256)).ToString(),
([math]::Truncate($Int64 % 256)).ToString()
$IPSplit = $SPItem.Cidr.Split('.')
[Net.IPAddress]$DefaultGateway = ($IPSplit[0] + '.' + $IPSplit[1] + '.' + $IPSplit[2] + '.' + (($SPItem.Cidr.split('/')[0].split('.')[-1] -as [int]) + 1) )
<#
If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) {
Write-Verbose "IP Address and CIDR Block match"
}
Else {
Write-Error "DNS record already exists, and does not match CIDR Block" -ErrorAction Stop
}
#>
If ($IpAddress) {
If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) {
Write-Warning "DNS record already exists, CIDR Block match"
}
else {
Write-Error "DNS record already exists, and does not match CIDR Block"
Break
}
}
Else {
New-ITDIbDNSRecordNextAvailableIP -Hostname $SPItem.Title -CIDR $SPItem.CIDR -Credential $RadiusCred
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
}
#>
If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) {
Write-Error "IP Address already in use." -ErrorAction Stop
}
# Passwordstate BB before baseline, AB after baseline
If ($FQDN -like "itdcnd*") {
$PasswordStateList = "Peoplesoft Share PW"
}
Else {
$PasswordStateList = "CSRC"
}
$LocalCredential = New-ITDPassword -Title $FQDN -UserName itdadmin -Description 'Local Administrator' -PasswordList $PasswordStateList -Credential $PSCred
#$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
#$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ($LocalCredential.UserName, ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ('itdadmin', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
#$GuestCredential = $GuestCredentialBB
# VMware
Connect-ITDvCenter -Credential $VMCred
If (Get-VM -Name $FQDN -ErrorAction SilentlyContinue) {
Write-Error "Virtual machine with the name $FQDN already exists." -ErrorAction Stop
Stop
Stop
}
switch ($SPItem.Cluster) {
"WINDOWS1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster WINDOWS1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'Thin'
If ($SPItem.LicensingRestrictions -like "*SQL*") {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_SQL"
}
Else {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_Gen"
}
}
"WINDOWS2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster WINDOWS2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'Thin'
If ($SPItem.LicensingRestrictions -like "*SQL*") {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_SQL"
}
Else {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_Gen"
}
}
"SQL1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster SQL1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'EagerZeroedThick'
$DatastoreCluster = Get-DatastoreCluster -Name "SQL1_FS92_Gen"
}
"SQL2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster SQL2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'EagerZeroedThick'
$DatastoreCluster = Get-DatastoreCluster -Name "SQL2_FS92_Gen"
}
"WAS1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster WAS1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "WAS1_FS92_Gen"
}
"WAS2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster WAS2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "WAS2_FS92_Gen"
}
"PS1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster PS1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "PS1_FS92_Gen"
}
"PS2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster PS2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "PS2_FS92_Gen"
}
"TEL1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster TEL1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL1-Data"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "TEL1_FS92_Gen"
}
"TEL2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster TEL2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL2-Data"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "TEL2_FS92_Gen"
}
Default {
Write-Error "Cluster not found" -ErrorAction Stop
}
<#
"DCN1" {
$ViServer = 'itdvmvc1.nd.gov'
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-DCN-vMotion-Data"
$DiskStorageFormat = 'Thin'
}
#>
}
# verify disk will fit
$DiskTotal = $SPItem.Disk1 + $SPItem.Disk2 + $SPItem.Disk3
If ($DatastoreCluster) {
}
Else {
$DatastoreCluster = Get-DatastoreCluster | Where-Object Name -Like ("*" + $SPItem.Cluster + "*")
}
$ClusterDatastoreWithHighestFreeSpaceGB = ($DatastoreCluster | Get-Datastore | Sort-Object FreeSpaceGB -Descending | Select-Object -First 1)
If ($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB -gt $DiskTotal) {
Write-Warning ("VM DiskTotal " + $DiskTotal + "GB, will fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)")
}
else {
Write-Warning ("VM DiskTotal " + $DiskTotal + "GB, will not fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)")
Write-Error ("New VM " + $FQDN + " needs " + $DiskTotal + "GB of free space on a single datastore in the " + $DatastoreCluster.Name + " datastore cluster.") -ErrorAction Stop
}
$FolderLocation = $ComputeCluster | Get-Datacenter | Get-Folder -Name "_New Builds"
switch ($SPItem.OS) {
"Windows Server 2012R2 Standard (64-Bit)" { $Template = "Windows Server 2012R2 Standard" }
"Windows Server 2016 Standard (64-Bit)" { $Template = "Windows Server 2016 Standard" }
"Windows Server 2019 Standard (64-Bit)" { $Template = "Windows Server 2019 Standard" }
"Windows Server 2019 Datacenter (64-Bit)" { $Template = "Windows Server 2019 Standard" }
"Windows Server 2022 Datacenter (64-Bit)" { $Template = "Windows Server 2022 Standard" }
Default { Write-Error "Invalid template" -ErrorAction Stop }
}
$PortGroupsAvailable = Get-VDPortgroup -Server $ViServer -VDSwitch $VirtualSwitch
$PortGroup = $PortGroupsAvailable | Where-Object Name -Like ("dvPG_" + $SPItem.Vlan_Id + "*")
If (!($PortGroup)) {
Write-Error "Virtual port group not found" -ErrorAction Stop
Stop
}
If (@($PortGroup).count -gt 1) {
Write-Error "Multiple port groups found" -ErrorAction Stop
Stop
}
$NewOSSpecName = ("AutoBuild-$Hostname-" + (Get-Date -UFormat "%Y%m%d%H%M%S"))
Write-Warning "NewOSSpecName = $NewOSSpecName"
Get-OSCustomizationSpec -Name "Windows (Auto)" -Server $ViServer | New-OSCustomizationSpec -Name $NewOSSpecName -Type Persistent -Server $ViServer
Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer | `
Set-OSCustomizationSpec `
-NamingScheme fixed `
-NamingPrefix $Hostname `
-AdminPassword $GuestCredentialBB.GetNetworkCredential().Password
Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer | `
Get-OSCustomizationNicMapping | `
Set-OSCustomizationNicMapping `
-IpMode UseStaticIP `
-IpAddress $IpAddress.IPAddressToString `
-SubnetMask $SubnetMask.IPAddressToString `
-DefaultGateway $DefaultGateway.IPAddressToString `
-Dns "10.2.7.40", "10.10.10.10"
$OSSpec = Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer
<#
$NewVMParams = @{
Name = $FQDN;
ResourcePool = $SPItem.Cluster;
Datastore = $DatastoreCluster;
DiskStorageFormat = $DiskStorageFormat;
Template = $Template;
Location = $FolderLocation;
OSCustomizationSpec = $OSSpec;
}
$NewVMParams
New-VM @NewVMParams
#>
#Set-Location C:\Temp # required to make New-VM work, https://communities.vmware.com/thread/591294
# seems fixed on 2022/07/01
try {
Write-Warning $FQDN
Write-Warning $ComputeCluster.Name
Write-Warning $DatastoreCluster
Write-Warning $DiskStorageFormat
Write-Warning $Template
Write-Warning $FolderLocation
Write-Warning $OSSpec
New-VM -Name $FQDN -ResourcePool $ComputeCluster.Name -Datastore $DatastoreCluster -DiskStorageFormat $DiskStorageFormat -Template $Template -Location $FolderLocation -OSCustomizationSpec $OSSpec
}
catch {
Stop
Stop
}
#If (!($BuildError)) {
$VM = Get-VM -Name $FQDN
# Ensure CPU/Memory Hot-Add Enabled
$vmView = $VM | Get-View
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmOptValCPU = New-Object VMware.Vim.OptionValue
$vmOptValMem = New-Object VMware.Vim.OptionValue
$vmOptValCPU.Key = "vcpu.hotadd"
$vmOptValMem.Key = "mem.hotadd"
$vmOptValCPU.Value = "true"
$vmOptValMem.Value = "true"
$vmConfigSpec.ExtraConfig += $vmOptValCPU
$vmConfigSpec.ExtraConfig += $vmOptValMem
$vmView.ReconfigVM($vmConfigSpec)
# Set CPU, Memory, Network
$VM | Set-VM -NumCpu $SPItem.Processors -MemoryGB $SPItem.RAM -Confirm:$false
$VM | Get-NetworkAdapter | Set-NetworkAdapter -Portgroup $PortGroup -Confirm:$false
# Power On VM
$VM | Start-VM
# Wait for Customization to finish
$VMStarted = $false
$VMCustomizationStarted = $false
$VMCustomizationResult = $false
While ($VMStarted -eq $false -or $VMCustomizationStarted -eq $false -or $VMCustomizationResult -eq $false) {
Write-Warning ("Customization wait loop started " + (Get-Date))
Write-Verbose "Current Status:"
Write-Verbose ("VMStarted: " + $VMStarted)
Write-Verbose ("VMCustomizationStarted: " + $VMCustomizationStarted)
Write-Verbose ("VMCustomizationResult: " + $VMCustomizationResult)
$GetVIEventRuntime = Measure-Command -Expression { $VMEvents = Get-VIEvent -Entity $VM -Server $ViServer -ErrorAction SilentlyContinue }
Write-Verbose ("Get-VIEvent last run time: " + $GetVIEventRuntime.TotalSeconds + " seconds")
If ($VMStarted -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "VMStartingEvent" })) {
$VMStarted = $true
Write-Warning "[$FQDN]:Virtual machine started"
}
}
If ($VMCustomizationStarted -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationStartedEvent" })) {
$VMCustomizationStarted = $true
Write-Warning "[$FQDN]:Virtual machine customization started"
}
}
If ($VMCustomizationResult -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationFailed" })) {
$VMCustomizationResult = $true
Write-Error "[$FQDN]:Virtual machine customization failed"
Exit
Exit
}
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationSucceeded" })) {
$VMCustomizationResult = $true
Write-Warning "[$FQDN]:Virtual machine customization completed"
}
}
}
# Delete OS Customization Spec
# Get-OSCustomizationSpec -Name $NewOSSpecName | Remove-OSCustomizationSpec -Confirm:$false
# Add/Expand Disks
Write-Warning -Message "[$FQDN]:Modify disks 1,2,3"
$VMDisk = $VM | Get-HardDisk
$VMDisk1 = $VMDisk | Where-Object Name -EQ "Hard disk 1"
$VMDisk2 = $VMDisk | Where-Object Name -EQ "Hard disk 2"
$VMDisk3 = $VMDisk | Where-Object Name -EQ "Hard disk 3"
If ($SPItem.Disk1) {
If (!$VMDisk1) {
$VM | New-HardDisk `
-CapacityGB $SPItem.Disk1 `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk1 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 1"
If ($VMDisk1.CapacityGB -lt $SPItem.Disk1) {
Set-HardDisk -HardDisk $VMDisk1 -CapacityGB $SPItem.Disk1 -Confirm:$false
}
}
If ($SPItem.Disk2) {
If (!$VMDisk2) {
$VM | New-HardDisk `
-CapacityGB $SPItem.Disk2 `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk2 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 2"
If ($VMDisk2.CapacityGB -lt $SPItem.Disk2) {
Set-HardDisk -HardDisk $VMDisk2 -CapacityGB $SPItem.Disk2 -Confirm:$false
}
}
If ($SPItem.Disk3) {
If (!$VMDisk3) {
$VM | New-HardDisk `
-CapacityGB $SPItem.Disk3 `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk3 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 3"
If ($VMDisk3.CapacityGB -lt $SPItem.Disk3) {
Set-HardDisk -HardDisk $VMDisk3 -CapacityGB $SPItem.Disk3 -Confirm:$false
}
}
# skipping tag assignment for now
# Set-ITDVMwareVMTagFromSharePoint -ComputerName $FQDN -SharePointCredential $SPCred -Verbose
# Run Guest OS code
# Enable RDP with NLA - can be done with GPO
# Enable WinRM - ITD WinRM enable
# Configure Power Plan - ITD-PowerPlan-HighPerformance
# Activate Windows, KMS on-premise, Azure to Azure
# DVD Drive to Z:
# Expand C:
# Partition/Format the rest, GPT/NTFS
# Configure Page File Disk
# Enabling server manager performance monitors
# Configure Time Zone and NTP - no GPO available
# Disable Windows Firewall
# Join AD
#Initialize-ITDServer -Credential $ADCred
Write-Warning -Message "[$FQDN]:Assigning WMI Tag 000-Prod, SCCM will change it later if required"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Move DVD Drive Mount
try {
Write-Verbose "Create new Class"
$Class = New-Object System.Management.ManagementClass("root\cimv2", [String]::Empty, $null);
$Class["__CLASS"] = "ITD";
$Class.Qualifiers.Add("Static", $true)
$Class.Properties.Add("MyKey", [System.Management.CimType]::String, $false)
$Class.Properties["MyKey"].Qualifiers.Add("Key", $true)
$Class.Properties.Add("LastModified", [System.Management.CimType]::String, $false)
$Class.Properties.Add("DTAP", [System.Management.CimType]::String, $false)
$Class.Properties.Add("Baseline", [System.Management.CimType]::String, $false)
$Class.Put()
Write-Verbose "Create single ITD Object"
Set-WmiInstance -Class ITD -Arguments @{LastModified = (Get-Date); DTAP = "Prod"; Baseline = "000" }
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking for DVD drive..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Move DVD Drive Mount
try {
$dvd_letter = 'Z'
$dvd = Get-WmiObject -Class Win32_Volume -Filter "DriveType=5" | Select-Object -First 1
if ($dvd.Name -notmatch $dvd_letter) {
Write-Verbose -Message "Found DVD drive, switching to $dvd_letter`:"
Set-WmiInstance -InputObject $dvd -Arguments @{DriveLetter = "$dvd_letter`:" } | Out-Null
Write-Verbose -Message "DVD drive moved to drive letter $dvd_letter`:"
}
else {
Write-Verbose -Message "No DVD drive changes required, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking for unpartitioned space on C: disk..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Expand C: Partition To Maximum Extent
try {
$cSize = ( Get-Partition -DriveLetter C ).Size
$cMaxSize = ( Get-PartitionSupportedSize -DriveLetter C ).SizeMax
if ($cSize -lt $cMaxSize) {
Write-Verbose -Message "Expanding C: from $($csize / 1GB)GB to $($cMaxSize / 1GB)GB..."
Resize-Partition -DriveLetter C -Size $cMaxSize
Write-Verbose -Message "C: expanded to $($cMaxSize / 1GB)GB."
}
else {
Write-Verbose -Message "C: is already at maximum size, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning "[$FQDN]:Start Extra Disk(s) config"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Initialize Additional Disks
try {
# Non-initialized and MBR-initialized disks will have 0 partitions by default, but GPT-initialized disks will have 1 system reserved partition by default
$disks = Get-Disk | Where-Object { $_.NumberOfPartitions -eq 0 -or ( $_.PartitionStyle -eq 'GPT' -and $_.NumberOfPartitions -eq 1 ) } | Sort-Object -Property Number
if ($disks) {
Write-Verbose -Message "Found $(@($disks).Count) unpartitioned disks."
# Prevent the "You must format this partition before using it." popup
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Stop-Service ShellHWDetection -ErrorAction SilentlyContinue }
foreach ($disk in $disks) {
if ($disk.IsOffline) {
Set-Disk $disk.Number -IsOffline $false
Write-Verbose -Message "Brought disk $($disk.Number)($("{0:n0}GB" -f ($disk.Size / 1GB))) online..."
}
if ($disk.IsReadOnly) { Set-Disk $disk.Number -IsReadOnly $false }
if ($disk.PartitionStyle -eq 'RAW') { Initialize-Disk $disk.Number -PartitionStyle GPT -ErrorAction SilentlyContinue }
$diskParam = @{
FileSystem = 'NTFS'
Confirm = $false
}
$driveLetter = [Int][Char]'D'
while (Get-Volume -DriveLetter $([Char]$driveLetter) -ErrorAction SilentlyContinue) {
$driveLetter++
}
$diskParam.DriveLetter = [Char]$driveLetter
if (@($disks).IndexOf($disk) -eq 0 -and (-not (Get-Volume -DriveLetter D -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Temporary Storage'
}
elseif (@($disks).IndexOf($disk) -eq 1 -and (-not (Get-Volume -DriveLetter E -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Data'
}
[void](New-Partition -DiskNumber $disk.Number -DriveLetter $diskParam.DriveLetter -UseMaximumSize)
[void](Format-Volume @diskParam)
}
}
else {
Write-Verbose -Message "No unpartitioned disks found, continuing..."
}
}
catch {
Throw $_
Break
}
finally {
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Start-Service ShellHWDetection -ErrorAction SilentlyContinue }
}
}
Write-Warning "[$FQDN]:Start Page File Configuration"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Page File
if (Get-Partition -DriveLetter D -ErrorAction SilentlyContinue) {
Write-Verbose -Message "Setting up pagefile.sys on D:..."
try {
if (-not [IO.File]::Exists('D:\pagefile.sys')) {
$autoPage = Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges
$autoPage.AutomaticManagedPagefile = $false
[void]$autoPage.Put()
Write-Verbose -Message "Disabled automatic pagefile management."
$pageFile = Get-WmiObject -Class Win32_PageFileSetting -EnableAllPrivileges
$pageFile.Delete()
Write-Verbose -Message "Deleted C:\pagefile.sys."
Set-WmiInstance -Class Win32_PageFileSetting -Arguments @{ Name = "D:\pagefile.sys"; InitialSize = 0; MaximumSize = 0; } -EnableAllPrivileges | Out-Null
Write-Verbose -Message "System managed page file created on D:\pagefile.sys."
}
else {
Write-Verbose -Message "Pagefile already configured on D:, continuing..."
}
}
catch {
Throw $_
Break
}
}
else {
Write-Verbose -Message "Page file drive not found, cannot set up page file. Continuing server configuration..."
Write-Warning "Page file drive not found, cannot set up page file. Continuing server configuration..."
}
}
Write-Warning -Message "[$FQDN]:Enabling Remote Management..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Remote Management (RDP/PoSH)
try {
Write-Verbose -Message "Checking WinRM..."
if (Test-WSMan -ErrorAction SilentlyContinue) {
Write-Verbose -Message "WinRM is already enabled."
}
else {
Enable-PSRemoting -Force
Write-Verbose -Message "WinRM is now enabled."
}
Write-Verbose -Message "Checking RDP..."
$RDP = Get-WmiObject Win32_TerminalServiceSetting -Namespace root\cimv2\TerminalServices
$NLA = Get-WmiObject Win32_TSGeneralSetting -Namespace root\cimv2\TerminalServices -Filter "TerminalName='RDP-tcp'"
if ($RDP.AllowTSConnections -eq 0) {
Write-Verbose -Message "RDP is disabled, enabling..."
$RDP.SetAllowTSConnections(1, 1) | Out-Null
Write-Verbose -Message "RDP is enabled."
}
else {
Write-Verbose -Message "RDP is already enabled, checking NLA security..."
}
if ($NLA.UserAuthenticationRequired -eq 0) {
Write-Verbose -Message "RDP is not NLA secured, enabling..."
$NLA.SetUserAuthenticationRequired(1) | Out-Null
Write-Verbose -Message "RDP is now NLA secured."
}
else {
Write-Verbose -Message "RDP is already NLA secured."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking current power plan..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Power Plan
try {
$powerPlans = powercfg -l
if ($powerPlans -match '\*$' -notmatch 'High performance') {
$currentPlan = [regex]::Match($powerPlans, '(?<=(\())[^)]+(?=(\)\s\*))').Value
Write-Verbose -Message "Power plan is currently set to $currentPlan, changing to High Performance..."
$highPerformance = [regex]::Match($powerPlans, '([\d\w-\S]+)(?=\s+\(High performance\))').Value
[void](powercfg -setactive $highPerformance)
Write-Verbose -Message "Power plan set to High Performance."
}
else {
Write-Verbose -Message "Power plan already configured for High Performance."
}
[void](& w32tm.exe /resync /nowait)
}
catch {
Throw $_
Break
}
}
$TimeSyncFunc = {
# Configure Time/Date Settings
Write-Verbose -Message "Checking current time/date settings..."
$Domain = "<DomainName>"
try {
if ((Get-TimeZone).Id -ne 'Central Standard Time') {
Write-Verbose -Message "Current time zone set to $((Get-TimeZone).Id), setting to Central Standard Time."
Set-TimeZone -Id 'Central Standard Time'
Write-Verbose -Message "Time zone set to Central Standard Time."
}
else {
Write-Verbose -Message "Time zone is already set to Central Standard Time."
}
<#
Write-Verbose -Message "Beginning a time synchronization..."
if ((Get-Service W32Time).Status -eq 'Stopped') {
Start-Service W32Time
}
[void](& w32tm.exe /config /manualpeerlist:$Domain /syncfromflags:all /update)
[void](& w32tm.exe /resync /nowait)
# Start background job to check time service
$tmJob = Start-Job -Name 'ManualTimeSync' -ScriptBlock {
do {
$tmOut = & w32tm.exe /query /status /verbose
Start-Sleep -Seconds 10
} until($tmOut -match '^Last Sync Error: 0\D+$')
}
# If after three minutes time still has not synched, move on. This usually causes no problems.
if ((Wait-Job -Job $tmJob -Timeout 180).State -eq 'Completed') {
Write-Warning -Message "Time synchronization with $($Domain.ToLower()) successful."
}
else {
[void](Stop-Job -Job $tmJob)
Write-Warning -Message "Time synchronization with $($Domain.ToLower()) failed."
}
#>
}
catch {
Throw $_
Break
}
}
$TimeSyncScriptBlock = $TimeSyncFunc -replace '<DomainName>', $DomainName
$VM | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText $TimeSyncScriptBlock
#>
Write-Warning -Message "[$FQDN]:Enabling the server manager performance monitors..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Enable Performance Counters
try {
if (Get-ScheduledTask -TaskName "Server Manager Performance Monitor" | Where-Object State -NE "Running" -ErrorAction SilentlyContinue) {
Enable-ScheduledTask -TaskPath "\Microsoft\Windows\PLA\" -TaskName "Server Manager Performance Monitor" | Start-ScheduledTask
Write-Verbose -Message "Performance monitors enabled."
}
else {
Write-Verbose -Message "Performance monitors already enabled, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Disable Windows Firewall"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Disable Windows Firewall
Write-Verbose -Message "Checking for active Windows Firewall..."
if ((Get-NetFirewallProfile).Enabled -contains 'True') {
Write-Verbose -Message "Windows Firewall is still enabled, disabling it..."
Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False
Write-Verbose -Message "Windows Firewall disabled."
}
else {
Write-Verbose -Message "Windows Firewall already disabled, continuing..."
}
}
# Active Directory
Write-Warning "[$FQDN]:Join Active Directory (if required)"
$DomainName = $FQDN.Substring($FQDN.IndexOf(".") + 1)
$AppName = $SPItem.AppName
switch ($DomainName) {
'nd.gov' {
$SearchBaseDomain = "dc=nd,dc=gov"
}
'ndcloud.gov' {
$SearchBaseDomain = "dc=ndcloud,dc=gov"
}
}
If ($DomainName -eq "nd.gov") {
$OUAppName = Get-ADOrganizationalUnit -Server $DomainName -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq $AppName }
If (!($OUAppName)) {
$OUAppName = Get-ADOrganizationalUnit -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq 'All-General' }
}
$ExistingADComputer = Get-ADComputer -Filter { Name -eq $Hostname }
If ($ExistingADComputer) {
If ($ExistingADComputer.DistinguishedName -like ("*" + $SPItem.AppName + "*") -or $ExistingADComputer.DistinguishedName -like "*All-General*") {
Write-Warning "AD object already exists, OU path does match"
$OuFinal = $ExistingADComputer.DistinguishedName -replace '^.+?(?<!\\),', ''
}
Else {
Write-Error "AD object already exists, OU path mismatch"
Exit
Exit
}
}
Else {
switch ($SPItem.Environment) {
'Test' {
If ($AppName -like "Shared-Peoplesoft*") { $EnvString = "Non-Prod" }
Else { $EnvString = "Test" }
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -Like "*$EnvString*"
}
'Production' {
$EnvString = "Prod"
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -Like "*$EnvString*"
}
}
If ($OuAppNameEnv) { $OUFinal = $OUAppNameEnv.DistinguishedName }
Else { $OuFinal = $OUAppName.DistinguishedName }
#New-ADComputer -Name $HostName.ToUpper() -Path $OUFinal -Credential $ADCred -Description ($SPItem | Select-Object AppName, Environment | ConvertTo-Json)
}
$FirstScriptBlock = { $DomainJoinCred = New-Object System.Management.Automation.PSCredential('svcitdvmdomainjoin', ('hypes-Vgv8h89' | ConvertTo-SecureString -AsPlainText -Force)) }
$SecondScriptText = 'Add-Computer -DomainName <DomainName> -OUPath "<OuPath>" -Credential $DomainJoinCred'
$SecondScriptText = $SecondScriptText -replace '<DomainName>', $DomainName
$SecondScriptText = $SecondScriptText -replace '<OuPath>', $OuFinal
$SecondScriptText = $SecondScriptText -replace '<OuPath>', ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain)
Write-Warning -Message "[$FQDN]:Invoke-VMScript to AD join"
$InvokeVMScriptFunc = [System.Management.Automation.ScriptBlock]::Create("$FirstScriptBlock ; $SecondScriptText")
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText $InvokeVMScriptFunc
Write-Warning -Message "[$FQDN]:Restart VMGuest, wait for Tools, then 90 seconds after"
Get-VM -Name $FQDN | Restart-VMGuest -Confirm:$false
Wait-Tools -VM (Get-VM -Name $FQDN)
Start-Sleep -Seconds 90
}
Write-Warning ("[$FQDN]:Copying SCCM client installer to C:\temp... " + (Get-Date))
Copy-VMGuestFile -Source C:\SCCM_Client\ -Destination C:\temp\SCCM_Client -VM (Get-VM -Name $FQDN) -LocalToGuest -GuestCredential $GuestCredentialAB -Force
Write-Warning ("[$FQDN]:SCCM client copy complete " + (Get-Date))
#E:\AutoBuild\SCCM_Client\
# Check if SCCM automatically installed the SCCM client and registered it
$CcmRegistered = $false
$CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log
}
If ($CcmRegistration.ScriptOutput -match "Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") {
Write-Warning "Client is already registered."
$CcmRegistered = $true
}
If ($CcmRegistered -eq $false) {
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
If (Get-Process -Name ccmsetup -ErrorAction SilentlyContinue) {
Write-Warning "CCM client is already installing"
$CcmRegistered = $true
}
ElseIf (Get-Process -Name ccmexec -ErrorAction SilentlyContinue) {
Write-Warning "CCM client is already installed"
$CcmRegistered = $true
}
Else {
Write-Warning -Message "Installing SCCM Client..."
Invoke-Expression -Command "C:\temp\SCCM_Client\ccmsetup.exe SMSSITECODE=ITD SMSMP=itdsccmp2.nd.gov DNSSUFFIX=nd.gov"
}
}
}
Write-Warning "[$FQDN]:Register SCCM Client"
While ($CcmRegistered -eq $false) {
$CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log
}
If ($CcmRegistration.ScriptOutput -match "Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") {
Write-Warning "Client is already registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistered -eq $false) { Start-Sleep -Seconds 30 }
}
Write-Warning -Message "[$FQDN]:Approve SCCM Client"
#Start-Sleep -Seconds 30 # ADD LOOP/SMARTS TO WAIT FOR DISCOVERY AND ANOTHER FOR APPROVAL
Invoke-Command -ComputerName itdsccmp2.nd.gov -Credential $CcmCred -ArgumentList $Hostname -ScriptBlock {
Import-Module 'D:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1'
$PSDrives = Get-PSDrive
If ($PSDrives | Where-Object Name -EQ "ITD") {
# ITD Drive exists, do nothing
}
else {
New-PSDrive -Name "ITD" -PSProvider AdminUI.PS.Provider\CMSite -Root itdsccmp2.nd.gov
}
Set-Location ITD:\
$Device = Get-CMDevice -Name $args[0]
If ($Device.IsApproved -eq 0) {
Approve-CMDevice -DeviceName $args[0]
}
}
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
#Start-Sleep -Seconds 180
Write-Warning -Message '[$FQDN]:Waiting for network connectivity / Then KVM Activation...'
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
# Pause until network connectivity is available
$KMS = 'kms.nd.gov'
try {
$nwJob = Start-Job -Name 'NetworkCheck' -ScriptBlock {
Param ( [String]$KMS )
do {
$nwStatus = Test-NetConnection -ComputerName $KMS -Port 1688 -InformationLevel Quiet
Start-Sleep -Seconds 10
} until($nwStatus)
} -ArgumentList $KMS
# If after 30 seconds the network connection is not responding continue on
if ((Wait-Job -Job $nwJob -Timeout 30).State -eq 'Completed') {
Write-Verbose -Message 'Network connectivity has been verified.'
}
else {
[void](Stop-Job -Job $nwJob)
Write-Verbose -Message 'Network connectivity could not be verified.'
}
}
catch {
Throw $_
Break
}
# Activate via KMS
Write-Verbose -Message "Activating windows against $KMS..."
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit
}
try {
cscript C:\Windows\System32\slmgr.vbs /skms $KMS | Out-Null
cscript C:\Windows\System32\slmgr.vbs /ato | Out-Null
Write-Verbose -Message "Checking activation status..."
$kmsOut = cscript C:\Windows\System32\slmgr.vbs /dli
if (($kmsOut | Select-String -Pattern '^License Status:') -match 'Licensed') {
Write-Verbose -Message "Windows successfully activated."
}
else {
Write-Verbose -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct."
Write-Warning -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct."
}
}
catch {
Throw $_
Break
}
}
Write-Warning "[$FQDN]:End"
}
Invoke-Command -ComputerName $FQDNs -Credential $PrvCred -ScriptBlock { Get-Process -Name ccmexec*, cohesity*, cyserver*, nessus*, vmtoolsd* }
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in"
Invoke-Command -ComputerName $FQDNs -Credential $PrvCred -ScriptBlock {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
@@ -0,0 +1,41 @@
[CmdletBinding()]
param (
)
begin {
}
process {
Connect-ITDvCenter -Credential $Secret:ndgov_svcitdvmvcauto
$VMHosts = Get-Datacenter -Name "Grand Forks Vantis" | Get-VMHost
ForEach ($VMHost in $VMHosts) {
Write-Verbose -Message ("Start: " + $VMHost.Name) -Verbose
$VMHostStatus = Get-ITDVMwareVMHostStatus -Name $VMHost.Name
# if accurate, enable lockdown
If ($VMHostStatus.LockdownMode -eq 'lockdowndisabled') {
Write-Verbose -Message ("Lockdown is already disabled on " + $VMHost.Name + ", no change") -Verbose
$NoChange = $true
}
Else {
Write-Verbose -Message ("Lockdown is enabled on " + $VMHost.Name + ", disabling now") -Verbose
Disable-ITDVMwareVMHostFeature -Name $VMHost.Name -LockdownMode
}
Start-Sleep -Seconds 5
# confirm lockdown is enabled
$VMHostStatusCheck = Get-ITDVMwareVMHostStatus -Name $VMHost.Name
}
Disconnect-ITDvCenter
}
end {
}
@@ -0,0 +1,86 @@
[CmdletBinding()]
param (
[switch]
$IncludeInProgress
)
begin {
}
process {
New-ITDServiceNowSession -Credential $Secret:snow_vmcred -Environment Production
Connect-ITDvCenter -Credential $Secret:ndgov_svcitdvmvcauto
If($PSBoundParameters.ContainsKey("IncludeInProgress")){
$Filter = 'short_descriptionSTARTSWITHLockdown mode is disabled on VMware host^state=1^ORstate=2'
} Else {
$Filter = 'state=1^short_descriptionSTARTSWITHLockdown Mode is disabled on VMware host'
}
$Incidents = Get-ITDServiceNowRecord -ItemType Incident -Filter $Filter | Sort-Object {$_.number.value}
ForEach ($Incident in $Incidents) {
# reset variables for each loop
$VMHostName = $null
$VMHostStatus = $null
$VMHostStatusCheck = $null
$NoChange = $null
$VMHostName = $Incident.short_description.display_value.split(' ')[-1]
Write-Verbose -Message ("Start " + $Incident.number.display_value + " for host " + $VMHostName) -Verbose
# confirm ticket is accurate, that host has lockdown mode disabled
$VMHostStatus = Get-ITDVMwareVMHostStatus -Name $VMHostName
# if accurate, enable lockdown
If ($VMHostStatus.LockdownMode -eq 'lockdowndisabled') {
Write-Verbose -Message ("Lockdown is still disabled on " + $VMHostName + ", enabling lockdown mode") -Verbose
Enable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
}
Else {
Write-Verbose -Message ("Lockdown is already enabled on " + $VMHostName + ", no change") -Verbose
$NoChange = $true
}
Start-Sleep -Seconds 5
# confirm lockdown is enabled
$VMHostStatusCheck = Get-ITDVMwareVMHostStatus -Name $VMHostName
# update ticket with current status
If ($VMHostStatusCheck.LockdownMode -eq 'lockdowndisabled') {
# update work notes if disabled
Write-Verbose -Message ("Lockdown is still disabled on " + $VMHostName + ", update incident work notes") -Verbose
$WorkNotesMsg = ("Lockdown is still disabled on " + $VMHostName + " after attempted remediation, manual review required.")
Update-ITDServiceNowRecord -ItemType Incident -Number $Incident.number.display_value -Values @{
work_notes = $WorkNotesMsg
state = 'On Hold'
}
}
Else {
# close if enabled
If ($NoChange) {
Write-Verbose -Message ("Lockdown was already enabled on " + $VMHostName + ", closing incident") -Verbose
$close_notes = ("Lockdown was already enabled on " + $VMHostName + " when checked, closing incident")
}
Else {
Write-Verbose -Message ("Lockdown successfully enabled on " + $VMHostName + ", closing incident") -Verbose
$close_notes = ("Lockdown successfully auto-enabled on " + $VMHostName);
}
Write-Verbose -Message ("Lockdown successfully enabled on " + $VMHostName + ", closing incident") -Verbose
Update-ITDServiceNowRecord -ItemType Incident -Number $Incident.number.display_value -Values @{
close_code = 'Solved (Permanently)'
close_notes = $close_notes
u_underlying_cause = 'Configuration';
state = 'Closed'
}
}
}
Disconnect-ITDvCenter
}
end {
}
@@ -0,0 +1,59 @@
<#
.SYNOPSIS
Checks VMware host lockdown mode status and creates incidents for disabled hosts.
.DESCRIPTION
Recurring PSU schedule task, ~8am.
This script connects to the ITD vCenter, retrieves all VMware hosts, and checks their lockdown mode status.
If lockdown mode is disabled on any hosts, it creates a ServiceNow incident for review.
.EXAMPLE
.\VMware-LockdownTickets.ps1
.NOTES
Requires VMware PowerCLI and ITD ServiceNow modules.
Service account credentials must be available via $PrvCred and $Secret:ndgov_svcitdvmvcro.
#>
[CmdletBinding()]
param (
)
begin {
}
process {
New-ITDServiceNowSession -Credential $Secret:snow_vmcred -Environment Production
Connect-ITDvCenter -Credential $Secret:ndgov_svcitdvmvcro
$AllVMHosts = Get-VMHost
$CurrentState = Get-ITDVMwareVMHostStatus -Name $AllVMHosts
$LockdownDisabled = $CurrentState | where-object lockdownmode -eq lockdowndisabled
If ($LockdownDisabled) {
ForEach ($VMHost in ($LockdownDisabled | Select -First 2)) {
Write-Verbose -Message "Start $($VMHost.Name) incident creation"
$NewIncidentParams = @{
CallerUsername = 'svcvmwareadm';
ShortDescription = ("Lockdown Mode is disabled on VMware host " + $VMHost.Name);
Description = ("Lockdown Mode is disabled on VMware host " + $VMHost.Name + ". Lockdown mode is a required for CIS hardening compliance 3.20 (L1)");
Impact = 3;
Urgency = 1;
Category = 'Cloud Platforms'
Subcategory = 'Virtualization'
AssignmentGroup = 'NDIT-Cloud Platforms'
}
New-ITDServiceNowIncident @NewIncidentParams
}
}
Disconnect-ITDvCenter
}
end {
}
@@ -0,0 +1,982 @@
#$IaasAuto = Get-Credential -UserName ndgov\svcitdiaasauto
#$StdCred = $IaasAuto
#$PrvCred = $IaasAuto
$FQDN = "itdzmtest001.nd.gov"
$CPU = 1
$MemoryGB = 4
$OS = "Windows Server 2019 Standard (64-Bit)"
$Environment = "Production"
$AppName = "Shared-PowerSchool"
$LicensingRestrictions = "Powerschool"
$VLAN = 1161
$Datacenter = "Bismarck"
Write-Warning "[$FQDN]:Start"
$SPCred = $StdCred
$ADCred = $IaasAuto
$PSCred = $PrvCred
$VMCred = $PrvCred
$CcmCred = $PrvCred
#$RadiusCred = $RadiusCred
$RadiusCred = New-Object System.Management.Automation.PSCredential($PrvCred.username.split('\')[1], ($PrvCred.Password))
Clear-DnsClientCache
$HostName = $FQDN.split('.')[0]
# Infoblox
$InfobloxVlanMetadata = Get-ITDIbVlan -Vlan $VLAN -Credential $RadiusCred
$CIDR = $InfobloxVlanMetadata.AssignedTo
[Net.IpAddress]$NetworkId = $Cidr.split('/')[0]
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
$SubnetMaskInt = $CIDR.split('/')[1]
$Int64 = ([convert]::ToInt64(('1' * $SubnetMaskInt + '0' * (32 - $SubnetMaskInt)), 2))
[Net.IPAddress]$SubnetMask = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($Int64 / 16777216)).ToString(),
([math]::Truncate(($Int64 % 16777216) / 65536)).ToString(),
([math]::Truncate(($Int64 % 65536) / 256)).ToString(),
([math]::Truncate($Int64 % 256)).ToString()
$IPSplit = $CIDR.Split('.')
[Net.IPAddress]$DefaultGateway = ($IPSplit[0] + '.' + $IPSplit[1] + '.' + $IPSplit[2] + '.' + (($CIDR.split('/')[0].split('.')[-1] -as [int]) + 1) )
<#
If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) {
Write-Verbose "IP Address and CIDR Block match"
}
Else {
Write-Error "DNS record already exists, and does not match CIDR Block" -ErrorAction Stop
}
#>
If ($IpAddress) {
If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) {
Write-Warning "DNS record already exists, CIDR Block match"
}
else {
Write-Error "DNS record already exists, and does not match CIDR Block"
Break
}
}
Else {
New-ITDIbDNSRecordNextAvailableIP -Hostname $FQDN -CIDR $CIDR -Credential $RadiusCred
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
}
#>
If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) {
Write-Error "IP Address already in use." -ErrorAction Stop
}
# Passwordstate BB before baseline, AB after baseline
If ($FQDN -like "itdcnd*") {
$PasswordStateList = "Peoplesoft Share PW"
}
Else {
$PasswordStateList = "CSRC"
}
# Passwordstate validation WIP
<#$ExistingPassword = Get-ITDPassword -Title $FQDN -UserName itdadmin -Credential $PSCred -ErrorAction SilentlyContinue
If($ExistingPassword){
$LocalCredential = $ExistingPassword
}#>
$LocalCredential = New-ITDPassword -Title $FQDN -UserName itdadmin -Description 'Local Administrator' -PasswordList $PasswordStateList -Credential $PSCred
#$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
#$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ($LocalCredential.UserName, ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ('itdadmin', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
#$GuestCredential = $GuestCredentialBB
# VMware
Connect-ITDvCenter -Credential $VMCred
If (Get-VM -Name $FQDN -ErrorAction SilentlyContinue) {
Write-Error "Virtual machine with the name $FQDN already exists." -ErrorAction Stop
Stop
Stop
}
switch ($LicensingRestrictions) {
"No Licensing Restrictions" { $ClusterRoot = "WINDOWS" }
"Microsoft SharePoint Server" { $ClusterRoot = "WINDOWS" }
"Microsoft SharePoint Server (Academic)" { $ClusterRoot = "WINDOWS" }
"Microsoft SQL Developer" { $ClusterRoot = "WINDOWS" }
"Microsoft SQL MSDN" { $ClusterRoot = "WINDOWS" }
"Microsoft SQL Standard" { $ClusterRoot = "WINDOWS" }
"Microsoft SQL Standard (Academic)" { $ClusterRoot = "WINDOWS" }
"Microsoft SQL Standard (Vendor Provided)" { $ClusterRoot = "WINDOWS" }
"Microsoft SQL Enterprise" { $ClusterRoot = "SQL" }
"Microsoft SQL Enterprise (Academic)" { $ClusterRoot = "WINDOWS" }
"IBM Websphere" { $ClusterRoot = "WAS" }
"Powerschool" { $ClusterRoot = "PS" }
"Pexip" { $ClusterRoot = "TEL" }
}
switch ($Datacenter) {
"Bismarck" { $ClusterInt = 1 }
"Mandan" { $ClusterInt = 2 }
}
$Cluster = $ClusterRoot + $ClusterInt
switch ($Cluster) {
"WINDOWS1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster WINDOWS1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
If ($LicensingRestrictions -like "*SQL*") {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_SQL"
$DiskStorageFormat = 'EagerZeroThick'
}
Else {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_Gen"
$DiskStorageFormat = 'Thin'
}
}
"WINDOWS2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster WINDOWS2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'Thin'
If ($LicensingRestrictions -like "*SQL*") {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_SQL"
$DiskStorageFormat = 'EagerZeroThick'
}
Else {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_Gen"
$DiskStorageFormat = 'Thin'
}
}
"SQL1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster SQL1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'EagerZeroedThick'
$DatastoreCluster = Get-DatastoreCluster -Name "SQL1_FS92_Gen"
}
"SQL2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster SQL2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'EagerZeroedThick'
$DatastoreCluster = Get-DatastoreCluster -Name "SQL2_FS92_Gen"
}
"WAS1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster WAS1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "WAS1_FS92_Gen"
}
"WAS2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster WAS2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "WAS2_FS92_Gen"
}
"PS1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster PS1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "PS1_FS92_Gen"
}
"PS2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster PS2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "PS2_FS92_Gen"
}
"TEL1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster TEL1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL1-Data"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "TEL1_FS92_Gen"
}
"TEL2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster TEL2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL2-Data"
$DiskStorageFormat = 'Thin'
$DatastoreCluster = Get-DatastoreCluster -Name "TEL2_FS92_Gen"
}
Default {
Write-Error "Cluster not found" -ErrorAction Stop
}
}
# verify disk will fit
$DiskTotal = 70
If ($DatastoreCluster) {
}
Else {
$DatastoreCluster = Get-DatastoreCluster | Where-Object Name -Like ("*" + $SPItem.Cluster + "*")
}
$ClusterDatastoreWithHighestFreeSpaceGB = ($DatastoreCluster | Get-Datastore | Sort-Object FreeSpaceGB -Descending | Select-Object -First 1)
If ($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB -gt $DiskTotal) {
Write-Warning ("VM DiskTotal " + $DiskTotal + "GB, will fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)")
}
else {
Write-Warning ("VM DiskTotal " + $DiskTotal + "GB, will not fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)")
Write-Error ("New VM " + $FQDN + " needs " + $DiskTotal + "GB of free space on a single datastore in the " + $DatastoreCluster.Name + " datastore cluster.") -ErrorAction Stop
}
$FolderLocation = $ComputeCluster | Get-Datacenter | Get-Folder -Name "_New Builds"
switch ($OS) {
"Windows Server 2012R2 Standard (64-Bit)" { $Template = "Windows Server 2012R2 Standard" }
"Windows Server 2016 Standard (64-Bit)" { $Template = "Windows Server 2016 Standard" }
"Windows Server 2019 Standard (64-Bit)" { $Template = "Windows Server 2019 Standard" }
"Windows Server 2019 Datacenter (64-Bit)" { $Template = "Windows Server 2019 Standard" }
"Windows Server 2022 Datacenter (64-Bit)" { $Template = "Windows Server 2022 Standard" }
Default { Write-Error "Invalid template" -ErrorAction Stop }
}
$PortGroupsAvailable = Get-VDPortgroup -Server $ViServer -VDSwitch $VirtualSwitch
$PortGroup = $PortGroupsAvailable | Where-Object Name -Like ("dvPG_" + $VLAN + "*")
If (!($PortGroup)) {
Write-Error "Virtual port group not found" -ErrorAction Stop
Stop
}
If (@($PortGroup).count -gt 1) {
Write-Error "Multiple port groups found" -ErrorAction Stop
Stop
}
$NewOSSpecName = ("AutoBuild-$Hostname-" + (Get-Date -UFormat "%Y%m%d%H%M%S"))
Write-Warning "NewOSSpecName = $NewOSSpecName"
Get-OSCustomizationSpec -Name "Windows (Auto)" -Server $ViServer | New-OSCustomizationSpec -Name $NewOSSpecName -Type Persistent -Server $ViServer
Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer | `
Set-OSCustomizationSpec `
-NamingScheme fixed `
-NamingPrefix $Hostname `
-AdminPassword $GuestCredentialBB.GetNetworkCredential().Password
Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer | `
Get-OSCustomizationNicMapping | `
Set-OSCustomizationNicMapping `
-IpMode UseStaticIP `
-IpAddress $IpAddress.IPAddressToString `
-SubnetMask $SubnetMask.IPAddressToString `
-DefaultGateway $DefaultGateway.IPAddressToString `
-Dns "10.2.7.40", "10.10.10.10"
$OSSpec = Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer
<#
$NewVMParams = @{
Name = $FQDN;
ResourcePool = $SPItem.Cluster;
Datastore = $DatastoreCluster;
DiskStorageFormat = $DiskStorageFormat;
Template = $Template;
Location = $FolderLocation;
OSCustomizationSpec = $OSSpec;
}
$NewVMParams
New-VM @NewVMParams
#>
#Set-Location C:\Temp # required to make New-VM work, https://communities.vmware.com/thread/591294
# seems fixed on 2022/07/01
try {
Write-Warning $FQDN
Write-Warning $ComputeCluster.Name
Write-Warning $DatastoreCluster
Write-Warning $DiskStorageFormat
Write-Warning $Template
Write-Warning $FolderLocation
Write-Warning $OSSpec
New-VM -Name $FQDN -ResourcePool $ComputeCluster.Name -Datastore $DatastoreCluster -DiskStorageFormat $DiskStorageFormat -Template $Template -Location $FolderLocation -OSCustomizationSpec $OSSpec
}
catch {
Stop
Stop
}
#If (!($BuildError)) {
$VM = Get-VM -Name $FQDN
# Ensure CPU/Memory Hot-Add Enabled
$vmView = $VM | Get-View
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmOptValCPU = New-Object VMware.Vim.OptionValue
$vmOptValMem = New-Object VMware.Vim.OptionValue
$vmOptValCPU.Key = "vcpu.hotadd"
$vmOptValMem.Key = "mem.hotadd"
$vmOptValCPU.Value = "true"
$vmOptValMem.Value = "true"
$vmConfigSpec.ExtraConfig += $vmOptValCPU
$vmConfigSpec.ExtraConfig += $vmOptValMem
$vmView.ReconfigVM($vmConfigSpec)
# Set CPU, Memory, Network
$VM | Set-VM -NumCpu $CPU -MemoryGB $MemoryGB -Confirm:$false
$VM | Get-NetworkAdapter | Set-NetworkAdapter -Portgroup $PortGroup -Confirm:$false
# Power On VM
$VM | Start-VM
# Wait for Customization to finish
$VMStarted = $false
$VMCustomizationStarted = $false
$VMCustomizationResult = $false
While ($VMStarted -eq $false -or $VMCustomizationStarted -eq $false -or $VMCustomizationResult -eq $false) {
Write-Warning ("Customization wait loop started " + (Get-Date))
Write-Verbose "Current Status:"
Write-Verbose ("VMStarted: " + $VMStarted)
Write-Verbose ("VMCustomizationStarted: " + $VMCustomizationStarted)
Write-Verbose ("VMCustomizationResult: " + $VMCustomizationResult)
$GetVIEventRuntime = Measure-Command -Expression { $VMEvents = Get-VIEvent -Entity $VM -Server $ViServer -ErrorAction SilentlyContinue }
Write-Verbose ("Get-VIEvent last run time: " + $GetVIEventRuntime.TotalSeconds + " seconds")
If ($VMStarted -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "VMStartingEvent" })) {
$VMStarted = $true
Write-Warning "[$FQDN]:Virtual machine started"
}
}
If ($VMCustomizationStarted -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationStartedEvent" })) {
$VMCustomizationStarted = $true
Write-Warning "[$FQDN]:Virtual machine customization started"
}
}
If ($VMCustomizationResult -eq $false) {
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationFailed" })) {
$VMCustomizationResult = $true
Write-Error "[$FQDN]:Virtual machine customization failed"
Exit
Exit
}
If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationSucceeded" })) {
$VMCustomizationResult = $true
Write-Warning "[$FQDN]:Virtual machine customization completed"
}
}
}
# Delete OS Customization Spec
# Get-OSCustomizationSpec -Name $NewOSSpecName | Remove-OSCustomizationSpec -Confirm:$false
# Add/Expand Disks
Write-Warning -Message "[$FQDN]:Modify disks 1,2,3"
$VMDisk = $VM | Get-HardDisk
$VMDisk1 = $VMDisk | Where-Object Name -EQ "Hard disk 1"
$VMDisk2 = $VMDisk | Where-Object Name -EQ "Hard disk 2"
$VMDisk3 = $VMDisk | Where-Object Name -EQ "Hard disk 3"
$VMDisk1 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 1"
If ($VMDisk1.CapacityGB -lt 60) {
Set-HardDisk -HardDisk $VMDisk1 -CapacityGB 60 -Confirm:$false
}
If (!$VMDisk2) {
$VM | New-HardDisk `
-CapacityGB ($MemoryGB + 1) `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk2 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 2"
If ($VMDisk2.CapacityGB -lt ($MemoryGB + 1)) {
Set-HardDisk -HardDisk $VMDisk2 -CapacityGB ($MemoryGB + 1) -Confirm:$false
}
If (!$VMDisk3) {
$VM | New-HardDisk `
-CapacityGB 20 `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk3 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 3"
If ($VMDisk3.CapacityGB -lt 20) {
Set-HardDisk -HardDisk $VMDisk3 -CapacityGB 20 -Confirm:$false
}
# skipping tag assignment for now
# Set-ITDVMwareVMTagFromSharePoint -ComputerName $FQDN -SharePointCredential $SPCred -Verbose
# Run Guest OS code
# Enable RDP with NLA - can be done with GPO
# Enable WinRM - ITD WinRM enable
# Configure Power Plan - ITD-PowerPlan-HighPerformance
# Activate Windows, KMS on-premise, Azure to Azure
# DVD Drive to Z:
# Expand C:
# Partition/Format the rest, GPT/NTFS
# Configure Page File Disk
# Enabling server manager performance monitors
# Configure Time Zone and NTP - no GPO available
# Disable Windows Firewall
# Join AD
#Initialize-ITDServer -Credential $ADCred
Write-Warning -Message "[$FQDN]:Assigning WMI Tag 000-Prod, SCCM will change it later if required"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Move DVD Drive Mount
try {
Write-Verbose "Create new Class"
$Class = New-Object System.Management.ManagementClass("root\cimv2", [String]::Empty, $null);
$Class["__CLASS"] = "ITD";
$Class.Qualifiers.Add("Static", $true)
$Class.Properties.Add("MyKey", [System.Management.CimType]::String, $false)
$Class.Properties["MyKey"].Qualifiers.Add("Key", $true)
$Class.Properties.Add("LastModified", [System.Management.CimType]::String, $false)
$Class.Properties.Add("DTAP", [System.Management.CimType]::String, $false)
$Class.Properties.Add("Baseline", [System.Management.CimType]::String, $false)
$Class.Put()
Write-Verbose "Create single ITD Object"
Set-WmiInstance -Class ITD -Arguments @{LastModified = (Get-Date); DTAP = "Prod"; Baseline = "000" }
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking for DVD drive..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Move DVD Drive Mount
try {
$dvd_letter = 'Z'
$dvd = Get-WmiObject -Class Win32_Volume -Filter "DriveType=5" | Select-Object -First 1
if ($dvd.Name -notmatch $dvd_letter) {
Write-Verbose -Message "Found DVD drive, switching to $dvd_letter`:"
Set-WmiInstance -InputObject $dvd -Arguments @{DriveLetter = "$dvd_letter`:" } | Out-Null
Write-Verbose -Message "DVD drive moved to drive letter $dvd_letter`:"
}
else {
Write-Verbose -Message "No DVD drive changes required, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking for unpartitioned space on C: disk..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Expand C: Partition To Maximum Extent
try {
$cSize = ( Get-Partition -DriveLetter C ).Size
$cMaxSize = ( Get-PartitionSupportedSize -DriveLetter C ).SizeMax
if ($cSize -lt $cMaxSize) {
Write-Verbose -Message "Expanding C: from $($csize / 1GB)GB to $($cMaxSize / 1GB)GB..."
Resize-Partition -DriveLetter C -Size $cMaxSize
Write-Verbose -Message "C: expanded to $($cMaxSize / 1GB)GB."
}
else {
Write-Verbose -Message "C: is already at maximum size, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning "[$FQDN]:Start Extra Disk(s) config"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Initialize Additional Disks
try {
# Non-initialized and MBR-initialized disks will have 0 partitions by default, but GPT-initialized disks will have 1 system reserved partition by default
$disks = Get-Disk | Where-Object { $_.NumberOfPartitions -eq 0 -or ( $_.PartitionStyle -eq 'GPT' -and $_.NumberOfPartitions -eq 1 ) } | Sort-Object -Property Number
if ($disks) {
Write-Verbose -Message "Found $(@($disks).Count) unpartitioned disks."
# Prevent the "You must format this partition before using it." popup
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Stop-Service ShellHWDetection -ErrorAction SilentlyContinue }
foreach ($disk in $disks) {
if ($disk.IsOffline) {
Set-Disk $disk.Number -IsOffline $false
Write-Verbose -Message "Brought disk $($disk.Number)($("{0:n0}GB" -f ($disk.Size / 1GB))) online..."
}
if ($disk.IsReadOnly) { Set-Disk $disk.Number -IsReadOnly $false }
if ($disk.PartitionStyle -eq 'RAW') { Initialize-Disk $disk.Number -PartitionStyle GPT -ErrorAction SilentlyContinue }
$diskParam = @{
FileSystem = 'NTFS'
Confirm = $false
}
$driveLetter = [Int][Char]'D'
while (Get-Volume -DriveLetter $([Char]$driveLetter) -ErrorAction SilentlyContinue) {
$driveLetter++
}
$diskParam.DriveLetter = [Char]$driveLetter
if (@($disks).IndexOf($disk) -eq 0 -and (-not (Get-Volume -DriveLetter D -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Temporary Storage'
}
elseif (@($disks).IndexOf($disk) -eq 1 -and (-not (Get-Volume -DriveLetter E -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Data'
}
[void](New-Partition -DiskNumber $disk.Number -DriveLetter $diskParam.DriveLetter -UseMaximumSize)
[void](Format-Volume @diskParam)
}
}
else {
Write-Verbose -Message "No unpartitioned disks found, continuing..."
}
}
catch {
Throw $_
Break
}
finally {
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Start-Service ShellHWDetection -ErrorAction SilentlyContinue }
}
}
Write-Warning "[$FQDN]:Start Page File Configuration"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Page File
if (Get-Partition -DriveLetter D -ErrorAction SilentlyContinue) {
Write-Verbose -Message "Setting up pagefile.sys on D:..."
try {
if (-not [IO.File]::Exists('D:\pagefile.sys')) {
$autoPage = Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges
$autoPage.AutomaticManagedPagefile = $false
[void]$autoPage.Put()
Write-Verbose -Message "Disabled automatic pagefile management."
$pageFile = Get-WmiObject -Class Win32_PageFileSetting -EnableAllPrivileges
$pageFile.Delete()
Write-Verbose -Message "Deleted C:\pagefile.sys."
Set-WmiInstance -Class Win32_PageFileSetting -Arguments @{ Name = "D:\pagefile.sys"; InitialSize = 0; MaximumSize = 0; } -EnableAllPrivileges | Out-Null
Write-Verbose -Message "System managed page file created on D:\pagefile.sys."
}
else {
Write-Verbose -Message "Pagefile already configured on D:, continuing..."
}
}
catch {
Throw $_
Break
}
}
else {
Write-Verbose -Message "Page file drive not found, cannot set up page file. Continuing server configuration..."
Write-Warning "Page file drive not found, cannot set up page file. Continuing server configuration..."
}
}
Write-Warning -Message "[$FQDN]:Enabling Remote Management..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Remote Management (RDP/PoSH)
try {
Write-Verbose -Message "Checking WinRM..."
if (Test-WSMan -ErrorAction SilentlyContinue) {
Write-Verbose -Message "WinRM is already enabled."
}
else {
Enable-PSRemoting -Force
Write-Verbose -Message "WinRM is now enabled."
}
Write-Verbose -Message "Checking RDP..."
$RDP = Get-WmiObject Win32_TerminalServiceSetting -Namespace root\cimv2\TerminalServices
$NLA = Get-WmiObject Win32_TSGeneralSetting -Namespace root\cimv2\TerminalServices -Filter "TerminalName='RDP-tcp'"
if ($RDP.AllowTSConnections -eq 0) {
Write-Verbose -Message "RDP is disabled, enabling..."
$RDP.SetAllowTSConnections(1, 1) | Out-Null
Write-Verbose -Message "RDP is enabled."
}
else {
Write-Verbose -Message "RDP is already enabled, checking NLA security..."
}
if ($NLA.UserAuthenticationRequired -eq 0) {
Write-Verbose -Message "RDP is not NLA secured, enabling..."
$NLA.SetUserAuthenticationRequired(1) | Out-Null
Write-Verbose -Message "RDP is now NLA secured."
}
else {
Write-Verbose -Message "RDP is already NLA secured."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking current power plan..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Power Plan
try {
$powerPlans = powercfg -l
if ($powerPlans -match '\*$' -notmatch 'High performance') {
$currentPlan = [regex]::Match($powerPlans, '(?<=(\())[^)]+(?=(\)\s\*))').Value
Write-Verbose -Message "Power plan is currently set to $currentPlan, changing to High Performance..."
$highPerformance = [regex]::Match($powerPlans, '([\d\w-\S]+)(?=\s+\(High performance\))').Value
[void](powercfg -setactive $highPerformance)
Write-Verbose -Message "Power plan set to High Performance."
}
else {
Write-Verbose -Message "Power plan already configured for High Performance."
}
[void](& w32tm.exe /resync /nowait)
}
catch {
Throw $_
Break
}
}
$TimeSyncFunc = {
# Configure Time/Date Settings
Write-Verbose -Message "Checking current time/date settings..."
$Domain = "<DomainName>"
try {
if ((Get-TimeZone).Id -ne 'Central Standard Time') {
Write-Verbose -Message "Current time zone set to $((Get-TimeZone).Id), setting to Central Standard Time."
Set-TimeZone -Id 'Central Standard Time'
Write-Verbose -Message "Time zone set to Central Standard Time."
}
else {
Write-Verbose -Message "Time zone is already set to Central Standard Time."
}
<#
Write-Verbose -Message "Beginning a time synchronization..."
if ((Get-Service W32Time).Status -eq 'Stopped') {
Start-Service W32Time
}
[void](& w32tm.exe /config /manualpeerlist:$Domain /syncfromflags:all /update)
[void](& w32tm.exe /resync /nowait)
# Start background job to check time service
$tmJob = Start-Job -Name 'ManualTimeSync' -ScriptBlock {
do {
$tmOut = & w32tm.exe /query /status /verbose
Start-Sleep -Seconds 10
} until($tmOut -match '^Last Sync Error: 0\D+$')
}
# If after three minutes time still has not synched, move on. This usually causes no problems.
if ((Wait-Job -Job $tmJob -Timeout 180).State -eq 'Completed') {
Write-Warning -Message "Time synchronization with $($Domain.ToLower()) successful."
}
else {
[void](Stop-Job -Job $tmJob)
Write-Warning -Message "Time synchronization with $($Domain.ToLower()) failed."
}
#>
}
catch {
Throw $_
Break
}
}
$TimeSyncScriptBlock = $TimeSyncFunc -replace '<DomainName>', $DomainName
$VM | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText $TimeSyncScriptBlock
#>
Write-Warning -Message "[$FQDN]:Enabling the server manager performance monitors..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Enable Performance Counters
try {
if (Get-ScheduledTask -TaskName "Server Manager Performance Monitor" | Where-Object State -NE "Running" -ErrorAction SilentlyContinue) {
Enable-ScheduledTask -TaskPath "\Microsoft\Windows\PLA\" -TaskName "Server Manager Performance Monitor" | Start-ScheduledTask
Write-Verbose -Message "Performance monitors enabled."
}
else {
Write-Verbose -Message "Performance monitors already enabled, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Disable Windows Firewall"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Disable Windows Firewall
Write-Verbose -Message "Checking for active Windows Firewall..."
if ((Get-NetFirewallProfile).Enabled -contains 'True') {
Write-Verbose -Message "Windows Firewall is still enabled, disabling it..."
Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False
Write-Verbose -Message "Windows Firewall disabled."
}
else {
Write-Verbose -Message "Windows Firewall already disabled, continuing..."
}
}
# Active Directory
Write-Warning "[$FQDN]:Join Active Directory (if required)"
$DomainName = $FQDN.Substring($FQDN.IndexOf(".") + 1)
switch ($DomainName) {
'nd.gov' {
$SearchBaseDomain = "dc=nd,dc=gov"
}
'ndcloud.gov' {
$SearchBaseDomain = "dc=ndcloud,dc=gov"
}
}
If ($DomainName -eq "nd.gov") {
$OUAppName = Get-ADOrganizationalUnit -Server $DomainName -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter {Name -eq $AppName}
If (!($OUAppName)) {
$OUAppName = Get-ADOrganizationalUnit -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq 'All-General' }
}
$ExistingADComputer = Get-ADComputer -Filter { Name -eq $Hostname }
If ($ExistingADComputer) {
If ($ExistingADComputer.DistinguishedName -like ("*" + $SPItem.AppName + "*") -or $ExistingADComputer.DistinguishedName -like "*All-General*") {
Write-Warning "AD object already exists, OU path does match"
$OuFinal = $ExistingADComputer.DistinguishedName -replace '^.+?(?<!\\),', ''
}
Else {
Write-Error "AD object already exists, OU path mismatch"
Exit
Exit
}
}
Else {
switch ($SPItem.Environment) {
'Test' {
If ($AppName -like "Shared-Peoplesoft*") { $EnvString = "Non-Prod" }
Else { $EnvString = "Test" }
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -Like "*$EnvString*"
}
'Production' {
$EnvString = "Prod"
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -Like "*$EnvString*"
}
}
If ($OuAppNameEnv) { $OUFinal = $OUAppNameEnv.DistinguishedName }
Else { $OuFinal = $OUAppName.DistinguishedName }
#New-ADComputer -Name $HostName.ToUpper() -Path $OUFinal -Credential $ADCred -Description ($SPItem | Select-Object AppName, Environment | ConvertTo-Json)
}
$FirstScriptBlock = { $DomainJoinCred = New-Object System.Management.Automation.PSCredential('svcitdvmdomainjoin', ('hypes-Vgv8h89' | ConvertTo-SecureString -AsPlainText -Force)) }
$SecondScriptText = 'Add-Computer -DomainName <DomainName> -OUPath "<OuPath>" -Credential $DomainJoinCred'
$SecondScriptText = $SecondScriptText -replace '<DomainName>', $DomainName
$SecondScriptText = $SecondScriptText -replace '<OuPath>', $OuFinal
$SecondScriptText = $SecondScriptText -replace '<OuPath>', ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain)
Write-Warning -Message "[$FQDN]:Invoke-VMScript to AD join"
$InvokeVMScriptFunc = [System.Management.Automation.ScriptBlock]::Create("$FirstScriptBlock ; $SecondScriptText")
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText $InvokeVMScriptFunc
Write-Warning -Message "[$FQDN]:Restart VMGuest, wait for Tools, then 90 seconds after"
Get-VM -Name $FQDN | Restart-VMGuest -Confirm:$false
Wait-Tools -VM (Get-VM -Name $FQDN)
Start-Sleep -Seconds 90
}
Write-Warning ("[$FQDN]:Copying SCCM client installer to C:\temp... " + (Get-Date))
Copy-VMGuestFile -Source C:\SCCM_Client\ -Destination C:\temp\SCCM_Client -VM (Get-VM -Name $FQDN) -LocalToGuest -GuestCredential $GuestCredentialAB -Force
Write-Warning ("[$FQDN]:SCCM client copy complete " + (Get-Date))
#E:\AutoBuild\SCCM_Client\
# Check if SCCM automatically installed the SCCM client and registered it
$CcmRegistered = $false
$CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log
}
If ($CcmRegistration.ScriptOutput -match "Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") {
Write-Warning "Client is already registered."
$CcmRegistered = $true
}
If ($CcmRegistered -eq $false) {
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
If (Get-Process -Name ccmsetup -ErrorAction SilentlyContinue) {
Write-Warning "CCM client is already installing"
$CcmRegistered = $true
}
ElseIf (Get-Process -Name ccmexec -ErrorAction SilentlyContinue) {
Write-Warning "CCM client is already installed"
$CcmRegistered = $true
}
Else {
Write-Warning -Message "Installing SCCM Client..."
Invoke-Expression -Command "C:\temp\SCCM_Client\ccmsetup.exe SMSSITECODE=ITD SMSMP=itdsccmp2.nd.gov DNSSUFFIX=nd.gov"
}
}
}
Write-Warning "[$FQDN]:Register SCCM Client"
While ($CcmRegistered -eq $false) {
$CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log
}
If ($CcmRegistration.ScriptOutput -match "Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") {
Write-Warning "Client is already registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistered -eq $false) { Start-Sleep -Seconds 30 }
}
Write-Warning -Message "[$FQDN]:Approve SCCM Client"
#Start-Sleep -Seconds 30 # ADD LOOP/SMARTS TO WAIT FOR DISCOVERY AND ANOTHER FOR APPROVAL
Invoke-Command -ComputerName itdsccmp2.nd.gov -Credential $CcmCred -ArgumentList $Hostname -ScriptBlock {
Import-Module 'D:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1'
$PSDrives = Get-PSDrive
If ($PSDrives | Where-Object Name -EQ "ITD") {
# ITD Drive exists, do nothing
}
else {
New-PSDrive -Name "ITD" -PSProvider AdminUI.PS.Provider\CMSite -Root itdsccmp2.nd.gov
}
Set-Location ITD:\
$Device = Get-CMDevice -Name $args[0]
If ($Device.IsApproved -eq 0) {
Approve-CMDevice -DeviceName $args[0]
}
}
# vcenter tags
#AppName Tag
New-TagAssignment -Entity (Get-VM $FQDN -server $VIServer) -Tag (Get-Tag -Server $VIServer -Category AppName -Name $AppName) -Server $VIServer
New-TagAssignment -Entity (Get-VM $FQDN -server $VIServer) -Tag (Get-Tag -Server $VIServer -Category DTAP -Name $Environment) -Server $VIServer
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
#Start-Sleep -Seconds 180
Write-Warning -Message '[$FQDN]:Waiting for network connectivity / Then KVM Activation...'
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
# Pause until network connectivity is available
$KMS = 'kms.nd.gov'
try {
$nwJob = Start-Job -Name 'NetworkCheck' -ScriptBlock {
Param ( [String]$KMS )
do {
$nwStatus = Test-NetConnection -ComputerName $KMS -Port 1688 -InformationLevel Quiet
Start-Sleep -Seconds 10
} until($nwStatus)
} -ArgumentList $KMS
# If after 30 seconds the network connection is not responding continue on
if ((Wait-Job -Job $nwJob -Timeout 30).State -eq 'Completed') {
Write-Verbose -Message 'Network connectivity has been verified.'
}
else {
[void](Stop-Job -Job $nwJob)
Write-Verbose -Message 'Network connectivity could not be verified.'
}
}
catch {
Throw $_
Break
}
# Activate via KMS
Write-Verbose -Message "Activating windows against $KMS..."
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit
}
try {
cscript C:\Windows\System32\slmgr.vbs /skms $KMS | Out-Null
cscript C:\Windows\System32\slmgr.vbs /ato | Out-Null
Write-Verbose -Message "Checking activation status..."
$kmsOut = cscript C:\Windows\System32\slmgr.vbs /dli
if (($kmsOut | Select-String -Pattern '^License Status:') -match 'Licensed') {
Write-Verbose -Message "Windows successfully activated."
}
else {
Write-Verbose -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct."
Write-Warning -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct."
}
}
catch {
Throw $_
Break
}
}
Write-Warning "[$FQDN]:End"
<#
Invoke-Command -ComputerName $FQDNs -Credential $PrvCred -ScriptBlock { Get-Process -Name ccmexec*, cohesity*, cyserver*, nessus*, vmtoolsd* }
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in"
Invoke-Command -ComputerName $FQDNs -Credential $PrvCred -ScriptBlock {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}#>
@@ -0,0 +1,18 @@
$OVServers = Get-OVServer
ForEach($OVServer in $OVServers){
$Enclosure = $OVServer.Name.split('_')[0]
$VMHost = Get-VMHost -Name $OVServer.ServerName
$ViServer = $VMHost.Uid.Split("@")[1].Split(':')[0]
$OldTagAssignment = $VMhost | Get-TagAssignment
$OldTag = $OldTagAssignment.Tag
$NewTag = Get-Tag -Category "HPE Enclosure" -Name $Enclosure -Server $ViServer
If ($OldTag -eq $NewTag){
}
Else{
$OldTagAssignment | Remove-TagAssignment -Confirm:$false
$VMHost | New-TagAssignment -Tag $NewTag
}
}
@@ -0,0 +1,245 @@
function Set-ITDVMwareVMTag {
[CmdletBinding()]
param
(
[string]
$ComputerName,
[string]
$AppName,
[string]
$Dtap,
[string]
$OperatingSystem,
[string]
$StartupPriority
)
begin {
}
process {
$VMs = Get-VM -Name $ComputerName | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
If ($VMs) {
ForEach ($VM in $VMs) {
#AppName Tag
Write-Verbose ($VM.Name + ": AppName Tag Start")
$OldTag = Get-TagAssignment -Category AppName -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $AppName
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " AppName old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") } #Errors with Remove-TagAssignment : Cannot bind argument to parameter 'TagAssignment' because it is null. --- but still works
#Get-Tag -Category AppName -Name $NewTagName -Server $VIServer
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category AppName -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)#
}
Write-Verbose ($VM.Name + ": AppName Tag End")
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
#DTAP Tag
Write-Verbose ($VM.Name + ": DTAP Tag Start")
$OldTag = Get-TagAssignment -Category DTAP -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $DTAP
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " DTAP old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") } #Errors with Remove-TagAssignment : Cannot bind argument to parameter 'TagAssignment' because it is null. --- but still works
#Get-Tag -Category AppName -Name $NewTagName -Server $VIServer
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category DTAP -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
Write-Verbose ($VM.Name + ": DTAP Tag End")
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
#Startup Priority
Write-Verbose ($VM.Name + ": StartupPriority Tag Start")
$OldTag = Get-TagAssignment -Category 'StartupPriority' -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $StartupPriority
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " StartupPriority old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") } #Errors with Remove-TagAssignment : Cannot bind argument to parameter 'TagAssignment' because it is null. --- but still works
#Get-Tag -Category AppName -Name $NewTagName -Server $VIServer
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'StartupPriority' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
Write-Verbose ($VM.Name + ": StartupPriority Tag End")
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
# OS Tag
Write-Verbose ($VM.Name + ": OS Tag Start")
$OldTag = Get-TagAssignment -Category "Operating System" -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $OperatingSystem
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " OS old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$False -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") }
If ($NewTagName -ne "None") {
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'Operating System' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
else {
Write-Verbose ($VM.Name + " tag invalid or None " + $VIServer)
}
}
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
Write-Verbose ($VM.Name + ": OS Tag End")
# Licensing Tag
Write-Verbose ($VM.Name + ": Licensing Restrictions Tag Start")
$OldTag = Get-TagAssignment -Category "LicensingRestrictions" -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $LicensingRestrictions
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " Licensing old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$False -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") }
If ($NewTagName -ne "None") {
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'LicensingRestrictions' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
else {
Write-Verbose ($VM.Name + " tag invalid or None " + $VIServer)
}
}
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
Write-Verbose ($VM.Name + ": Licensing Tag End")
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
<# SRM Recovery Type Tags
Write-Verbose ($VM.Name + ": SRM Recovery Type Tag Start")
$OldTag = Get-TagAssignment -Category "SRM Recovery Type" -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
If ($VM.ExtensionData.summary.config.ManagedBy.Type -eq "placeholderVm" ) {
#If VM is placeholder
$NewTagName = "Placeholder"
}
Else {
$NewTagName = $SPItem.SRM_RecoveryVMtype
}
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " SRM Recovery Type old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$False -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") }
If ($NewTagName -ne "None") {
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'SRM Recovery Type' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
else {
Write-Verbose ($VM.Name + " tag invalid or None " + $VIServer)
}
}
Write-Verbose ($VM.Name + ": SRM Recovery Type Tag End")#>
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
<#VR RPO Tag
Write-Verbose ($VM.Name + ": SRM Tag Start")
$OldTag = Get-TagAssignment -Category 'VR RPO' -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $SPItem.DR_Protection -replace "VMware: "
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " SRM old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") } #Errors with Remove-TagAssignment : Cannot bind argument to parameter 'TagAssignment' because it is null. --- but still works
#Get-Tag -Category AppName -Name $NewTagName -Server $VIServer
If ($NewTagName -ne "None") {
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'VR RPO' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
else {
Write-Verbose ($VM.Name + " tag invalid or None " + $VIServer)
}
}#>
}
}
Else {
}
#}
<#catch {
Write-Error ($VM.Name + " tag errored")
Write-Error $error[-1]
}#>
}
end {
}
}
@@ -0,0 +1,3 @@
$AllVMs = Get-Datacenter -Name Primary* | Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" -and $_.Name -notlike "vCLS*" }
$AllVMs | Select Name,NumCpu,MemoryGB,@{n='Cluster';e={$_.VMHost | Get-Cluster}},@{n='SRM Recovery Type';e={($_ | Get-TagAssignment -Category "SRM Recovery Type").Tag.Name}} -OutVariable result
@@ -0,0 +1,177 @@
<#
.SYNOPSIS
Daily VM metadata report for PowerBI trending and hardware capacity planning.
.DESCRIPTION
Collects VM metadata from vCenter including compute, storage, OS, and VMware Tools
information using only data available within vCenter (no direct guest connections).
Exports a timestamped CSV each run -- append daily runs to build a historical dataset
suitable for PowerBI trend analysis and physical hardware purchasing decisions.
.PARAMETER vCenterServers
One or more vCenter server hostnames. Defaults to itdvmvc1.nd.gov and itdvmvc2.nd.gov.
.PARAMETER DatacenterFilter
Wildcard filter applied to datacenter names. Defaults to 'Primary*'.
.PARAMETER OutputPath
Directory where CSV and log files are written.
Defaults to C:\ITDSCRIPT\Reports\VMMetadata.
.PARAMETER CredentialPath
Path to a saved PSCredential XML file for unattended/scheduled runs.
Create one interactively with:
Get-Credential | Export-Clixml -Path C:\ITDSCRIPT\Creds\vCenter.xml
When omitted the script prompts for credentials.
.EXAMPLE
# Interactive run
.\VMware-VMDailyMetadataReport.ps1
.EXAMPLE
# Scheduled / unattended run
.\VMware-VMDailyMetadataReport.ps1 -CredentialPath 'C:\ITDSCRIPT\Creds\vCenter.xml'
.NOTES
Scheduled Task suggestion (run as service account that owns the credential XML):
Program : powershell.exe
Args : -NonInteractive -ExecutionPolicy Bypass -File "C:\ITDSCRIPT\VMware-VMDailyMetadataReport.ps1" -CredentialPath "C:\ITDSCRIPT\Creds\vCenter.xml"
Trigger : Daily at 06:00
Guest OS disk capacity / used columns are populated only for powered-on VMs with
VMware Tools running; they will be empty for powered-off VMs and SRM placeholders.
#>
[CmdletBinding()]
param(
[string] $OutputPath = 'C:\temp\VM_Trends\'
)
#region --- Setup ---------------------------------------------------------------
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd HH:mm:ss')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "VMMetadataReport_$DateStamp.log") -Append
#endregion
#region --- Build VMHost -> Cluster/Datacenter Lookups (avoids per-VM API calls) -
Write-Verbose 'Building host-to-cluster and host-to-datacenter maps...'
$HostClusterMap = @{}
$HostDatacenterMap = @{}
Get-Datacenter | ForEach-Object {
$DatacenterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostDatacenterMap[$_.Name] = $DatacenterName
}
}
Get-Cluster | ForEach-Object {
$ClusterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostClusterMap[$_.Name] = $ClusterName
}
}
#endregion
#region --- Collect VM Data -----------------------------------------------------
Write-Verbose "Gathering VMs"
# Include ALL VMs (SRM placeholders flagged via column, not excluded).
# vCLS agent VMs are excluded -- they are vSphere internal and not customer workloads.
$AllVMs = Get-VM | Where-Object { $_.Name -notlike 'vCLS*' }
Write-Verbose "Processing $($AllVMs.Count) VMs..."
$Results = foreach ($VM in $AllVMs) {
$Ext = $VM.ExtensionData # single API object -- reuse for all fields
#--- SRM placeholder detection
$IsSRMPlaceholder = $Ext.Summary.Config.ManagedBy.Type -eq 'placeholderVm'
#--- Cluster / Datacenter (null-safe: standalone hosts have no cluster entry)
$ClusterName = $HostClusterMap[$VM.VMHost.Name]
$DatacenterName = $HostDatacenterMap[$VM.VMHost.Name]
#--- Storage platform parsed from datastore name convention: VMCLUSTER_LUN_PLATFORM_Desc
# Segment 2 = storage platform identifier (e.g. FS92, A9K).
# Cluster grouping uses the compute Cluster column -- no need to re-derive it here.
$StoragePlatforms = foreach ($DSName in $Ext.Config.DatastoreUrl.Name) {
$Segments = $DSName -split '_'
if ($Segments.Count -ge 3) { $Segments[2] }
}
$StoragePlatform = ($StoragePlatforms | Sort-Object -Unique) -join '; '
#--- VMware Tools guest disk info
# Populated only when Tools is running; null otherwise.
$GuestDiskCapacityGB = $null
$GuestDiskUsedGB = $null
if ($Ext.Guest.Disk) {
$TotalCapBytes = ($Ext.Guest.Disk | Measure-Object -Property Capacity -Sum).Sum
$TotalFreeBytes = ($Ext.Guest.Disk | Measure-Object -Property FreeSpace -Sum).Sum
$GuestDiskCapacityGB = [Math]::Round($TotalCapBytes / 1GB, 2)
$GuestDiskUsedGB = [Math]::Round(($TotalCapBytes - $TotalFreeBytes) / 1GB, 2)
}
[PSCustomObject]@{
# --- Identity & grouping
ReportDate = $Timestamp # for PowerBI time-series/trend axis
VMName = $VM.Name
Datacenter = $DatacenterName
Cluster = $ClusterName
PowerState = $VM.PowerState
IsSRMPlaceholder = $IsSRMPlaceholder
StoragePlatform = $StoragePlatform
GuestOS = $Ext.Guest.GuestFullName
# --- Compute
vCPUs = $VM.NumCpu
MemoryGB = $VM.MemoryGB
# --- Datastore-level storage
# ProvisionedSpaceGB : maximum the VM could consume (thin disks counted at max size)
# UsedSpaceGB : bytes actually committed on datastores right now
ProvisionedSpaceGB = [Math]::Round($VM.ProvisionedSpaceGB, 2)
UsedSpaceGB = [Math]::Round($VM.UsedSpaceGB, 2)
# --- Guest OS-level storage (from VMware Tools; null when Tools not running)
# GuestDiskCapacityGB : sum of all volume capacities seen inside the guest
# GuestDiskUsedGB : sum of space consumed across those volumes
GuestDiskCapacityGB = $GuestDiskCapacityGB
GuestDiskUsedGB = $GuestDiskUsedGB
# --- VMware Tools
# ToolsRunningStatus : guestToolsRunning | guestToolsNotRunning | guestToolsExecutingScripts
# ToolsVersionStatus : guestToolsCurrent | guestToolsNeedUpgrade | guestToolsUnmanaged | guestToolsTooNew
# ToolsVersion : numeric build version string reported by vCenter
ToolsRunningStatus = $Ext.Guest.ToolsRunningStatus
ToolsVersionStatus = $Ext.Guest.ToolsVersionStatus
ToolsVersion = $Ext.Guest.ToolsVersion
}
}
#endregion
#region --- Export --------------------------------------------------------------
$OutputFile = Join-Path $OutputPath "VMMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) VM records to: $OutputFile"
#endregion
#region --- Cleanup -------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,42 @@
# report current status
$AllVMs = Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$WS2022VMs = $AllVMs | Where-Object { $_.ExtensionData.Guest.GuestFullName -like "*2022*" } | Sort-Object Name
$WS2022VMs | select Name, @{n = 'EfiSecureBootEnabled'; e = { $_.ExtensionData.Config.BootOptions.EfiSecureBootEnabled } }
$VMNames = @"
itdexchtest1.testnd.gov
itdexchtest2.testnd.gov
itdexch1.nd.gov
itdexch2.nd.gov
"@
$VMNames = ConvertTo-Array -MultiLineString $VMNames
# power off VMs
ForEach ($VMName in $VMNames) {
Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Stop-VMGuest -Confirm:$false
}
# wait for all to be powered off
Get-VM -Name $VMNames
# disable secure boot on all of them
ForEach ($VMname in $VMNames) {
$vm = Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::efi
$boot = New-Object VMware.Vim.VirtualMachineBootOptions
$boot.EfiSecureBootEnabled = $false # false to disable obviously
$spec.BootOptions = $boot
$vm.ExtensionData.ReconfigVM($spec)
}
# validate
Get-VM -Name $VMNames | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }| select Name, @{n = 'EfiSecureBootEnabled'; e = { $_.ExtensionData.Config.BootOptions.EfiSecureBootEnabled } }
# power on
ForEach($VMName in $VMNames){
Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Start-VM
}
@@ -0,0 +1,42 @@
# report current status
$AllVMs = Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$WS2022VMs = $AllVMs | Where-Object { $_.ExtensionData.Guest.GuestFullName -like "*2022*" } | Sort-Object Name
$WS2022VMs | select Name, @{n = 'EfiSecureBootEnabled'; e = { $_.ExtensionData.Config.BootOptions.EfiSecureBootEnabled } }
$VMNames = @"
itdaddressprot2.nd.gov
itdqlikreptst1.ndcloud.gov
itdqlikrepprd1.ndcloud.gov
itdexch1.nd.gov
itdexch2.nd.gov
itdexchtest1.testnd.gov
itdexchtest2.testnd.gov
"@
$VMNames = ConvertTo-Array -MultiLineString $VMNames
# power off VMs
ForEach ($VMName in $VMNames) {
Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Stop-VMGuest -Confirm:$false
}
# wait for all to be powered off
Get-VM -Name $VMNames
# disable secure boot on all of them
ForEach ($VMname in $VMNames) {
$vm = Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::efi
$boot = New-Object VMware.Vim.VirtualMachineBootOptions
$boot.EfiSecureBootEnabled = $true # false to disable obviously
$spec.BootOptions = $boot
$vm.ExtensionData.ReconfigVM($spec)
}
# power on
ForEach($VMName in $VMNames){
Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Start-VM
}
@@ -0,0 +1,71 @@
# Dump list of VMs from ServiceNow
Get-ITDServiceNowRecord -Table cmdb_ci_server -Filter "serial_numberSTARTSWITHvmware" -IncludeTotalCount | Export-Csv "C:\temp\CMDB_VMwareDump.csv"
# Disable DRS on all clusters
Get-Cluster LINUX*, MGMT*, ORACLE1, PS*, SQLa*, SQLe*, VAPP*, WAS*, WINDOWS* | Set-Cluster -DrsEnabled $false
# Dump location of all VMs to CSV
Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | select Name, PowerState, NumCpu, MemoryGB, VMHost, @{n = 'Datastores'; e = { ($_ | Get-Datastore).Name } } | Export-Csv "D:\State of North Dakota\-Tm-ITD-Virtualization - Documents\VMinfo.csv"
# VM array
$VMHosts = @(
'itdvmbismgmt02.nd.gov',
'itdvmbismgmt03.nd.gov',
'itdvmmdnmgmt01.nd.gov',
'itdvmbismgmt02.nd.gov'
)
# Disable lockdown on MGMT hosts
$VMHosts | ForEach-Object {
(Get-VMHost -Name $_ | Get-View).ExitLockdownMode()
}
# connect to mgmt cluster
$VMHosts | ForEach-Object {
Connect-VIServer -Server $_ -Credential (Get-ITDPassword -Title $_ -UserName root -Credential $PrvCred)
}
## verify lockdown mode is disabled manually
# get list of VMs | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$VMs = Get-VM | Where-Object { $_.Name -notlike "vCLS*" -and $_.PowerState -eq "PoweredOn" -and $_.Name -notlike "itdvmutil*" -and $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm"} | Sort-Object Name
# Cleanup snapshots on MGMT cluster
$VMs | Get-Snapshot | Where-Object Name -NotLike "*9.0.2*" | Remove-Snapshot -RunAsync
# Shutdown all appliance VMs on MGMT cluster
$VMs | Stop-VMGuest -Confirm:$false #-RunAsync
# Wait for VMs to power off
Get-VM -Name $VMs.Name | Sort-Object Name
#Get-Cluster MGMT1, MGMT2 | Get-VM | Where-Object { $_.Name -notlike "itdvmutil*" } | Sort-Object Name
# Create offline snapshots
$VMs | New-Snapshot -Name "9_Before 8.0 U3e Upgrade" -Description "9_Before 8.0 U3e Upgrade" -Confirm:$false -RunAsync
# Power on all VMs on MGMT cluster
$VMs | Start-VM -Confirm:$false
Break
## online mid-upgrade snapshots
$VMs | New-Snapshot -Name "1_vc_upgrade_complete" -Description "2_vc1_stage2_complete" -Confirm:$false -RunAsync -Memory
Get-VM -Name itdvmvc*,itdvmsrm*, itdvmvra* | Where-Object {$_.Name -notlike "*7.0*"} | Stop-VMGuest -Confirm:$false
# post upgrade snapshot
Get-VM -Name itdvmvc*,itdvmsrm*, itdvmvra* | New-Snapshot -Name "2_vc_upgrade_complete" -Description "2_vc1_stage2_complete" -Confirm:$false -RunAsync -Memory
Get-VM -Name itdvmvc*,itdvmsrm*, itdvmvra* | Start-VM
##### after upgrade
# Enable DRS on clusters that should have it
Get-Cluster LINUX*, MGMT*, ORACLE1, PS*, SQLa*, SQLe*, VAPP*, WAS*, WINDOWS* | Set-Cluster -DrsEnabled $true
# Enable lockdown on MGMT hosts
(Get-VMHost itdvmbismgmt01.nd.gov | Get-View).EnterLockdownMode()
(Get-VMHost itdvmbismgmt02.nd.gov | Get-View).EnterLockdownMode()
(Get-VMHost itdvmmdnmgmt01.nd.gov | Get-View).EnterLockdownMode()
(Get-VMHost itdvmmdnmgmt02.nd.gov | Get-View).EnterLockdownMode()
# reconfigure distributed switch to use both vnics
#### manual
@@ -0,0 +1,13 @@
$AllVMs = Get-VM | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
$data = $AllVMs | `
Select-Object Name, `
VMHost, `
UsedSpaceGB, `
ProvisionedSpaceGB #, `
#@{n = 'Disks'; e = { $_ | Get-HardDisk | Select Name, FileName, CapacityGB } }, `
#@{n = 'VRDatastore'; e = { ($_ | Get-TagAssignment | Where-Object Tag -like "*_VR").Tag } } `
#@{n = 'PortGroups'; e = { $_ | Get-VirtualPortGroup } }
$data | export-csv "C:\users\zmeier\desktop\VMs_20200122.csv"
get-vm itdvmpsc1*,itdvmvc1*,itdvmpsc2*,itdvmvc2* | new-snapshot -name "VC1-6.7 U3-Stage1 Complete"
@@ -0,0 +1,8 @@
$TimeStamp = Get-Date -UFormat "%Y%m%d-%H%M%S"
$TranscriptPath = "D:\PowerShellTasks\CompareVMSRMList\Logs\CompareVMSRMList-$Timestamp.log"
Start-Transcript $TranscriptPath
$result = Compare-ITDVMwareVMSRMList -vCenterCredential $svcitdvmvcauto -SharePointCredential $svcitdiaassprw -Verbose
$body = "" + ($result | ConvertTo-Html)
Send-MailMessage -To itdvctremailalerts@nd.gov -From itdvmvcp1script@nd.gov -Body $body -SmtpServer apprelay1.nd.gov -BodyAsHtml -Subject "VMware SRM conflicts" -Verbose
@@ -0,0 +1,146 @@
<# Scheduled Task metadata
General
GetAzureVMGuestIPsForPA
run as ndgov\svcitdiaasauto
run whether user is logged on or not
Triggers
Daily, 2pm - repeat every 1 hour indefinitely
Actions
"C:\Program Files\PowerShell\7\pwsh.exe" -noninteractive -file "F:\GetAzureVMGuestIPsForPA\GetAzureVMGuestIPsForPA.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 1 hour -eq $true
if the running task does not end when requested, force it to stop
#>
$TimeStamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Start-Transcript F:\GetAzureVMGuestIPsForPA\Logs\GetAzureVMGuestIPsForPA-$Timestamp.log
$VerbosePerfrence = "Continue"
#[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$OutputPath = "C:\inetpub\wwwroot"
$WindowsIPs = ""
$LinuxIPs = ""
$OutFileWin = $OutputPath + "\AzureWin.txt"
$OutFileLin = $OutputPath + "\AzureLin.txt"
Remove-Item $OutFileWin
Remove-Item $OutFileLin
$WindowsIpArray = [string]@()
$LinuxIpArray = [string]@()
# replace with PowerShell.SecretManagement
#$username="svcitdazurescript@nd.gov"
#$usernameg="svcitdazurescript@ndstate.onmicrosoft.com"
#Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat
#$password=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat | ConvertTo-SecureString
#$passwordg=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sacg.bat | ConvertTo-SecureString
#$AdminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$password
#$AdminCredg=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $usernameg,$passwordg
# Prepare credentials
$svcitdazurescript = Get-Secret -Name svcitdazurescript
$MacCred = New-Object System.Management.Automation.PSCredential("svcitdazurescript@nd.gov", $svcitdazurescript.Password)
# no VMs or PAs in AzureGov yet (2023/09/26) $MagCred = Get-Secret -Name svcitdazurescriptgov
# Azure Commercial
$AzAccount = Connect-AzAccount -Credential $MacCred -Environment AzureCloud -Verbose
$Subscriptions = Get-AzSubscription | Where-Object { $_.Name -ne "sandbox" -and $_.Name -notlike "Visual Studio*" -and $_.Name -notlike "Azure subscription*" -and $_.Name -notlike "Access to Azure Active Directory*"}
foreach ($subscription in $subscriptions) {
Set-AzContext -Subscription $subscription
$WindowsVMs = Get-AzVM | Where-Object { $_.StorageProfile.osdisk.ostype -match "Windows" }
$LinuxVMs = Get-AzVM | Where-Object { $_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks" }
$nics = Get-AzNetworkInterface | Where-Object { $_.VirtualMachine -NE $null }
foreach ($vm in $WindowsVMs) {
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach ($vmnicinterface in $vmnicinterfaces) {
$nic = $nics | Where-Object { $_.Id -eq $vmnicinterface }
$privateip = $nic.IpConfigurations | select PrivateIPAddress
If ($privateip.count -gt 1) {
foreach ($private in $privateip) {
Write-Warning -Message ($VM.Name + "zzzzz")
$WindowsIPs += $private.privateIPAddress + "`n"
}
}
elseIf ($privateip.privateIPAddress -ne $null) {
Write-Warning -Message ($VM.Name + "xxxxx")
$WindowsIPs += $privateip.privateIPAddress + "`n"
}
}
}
foreach ($vm in $LinuxVMs) {
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach ($vmnicinterface in $vmnicinterfaces) {
$nic = $nics | Where-Object { $_.Id -eq $vmnicinterface }
$privateip = $nic.IpConfigurations | select PrivateIPAddress
If ($privateip.count -gt 1) {
foreach ($private in $privateip) {
$LinuxIPs += $private.privateIPAddress + "`n"
}
}
elseif ($privateip.privateIPAddress -ne $null) {
$LinuxIps += $privateip.privateIPAddress + "`n"
}
}
}
}
#Azure Gov
<# no VMs or PAs in AzureGov yet (2023/09/26)
$AzAccount = Connect-AzAccount -Credential $MagCred -Environment AzureUSGovernment -Verbose
$Subscriptions = Get-AzureRMSubscription | Where-Object { $_.Name -ne "sandbox" }
foreach ($subscription in $subscriptions) {
Set-AzContext -Subscription $subscription
$WindowsVMs = Get-AzVM | Where-Object { $_.StorageProfile.osdisk.ostype -match "Windows" }
$LinuxVMs = Get-AzVM | Where-Object { $_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks" }
$nics = Get-AzNetworkInterface | Where-Object { $_.VirtualMachine -NE $null }
foreach ($vm in $WindowsVMs) {
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach ($vmnicinterface in $vmnicinterfaces) {
$nic = $nics | Where-Object { $_.Id -eq $vmnicinterface }
$privateip = $nic.IpConfigurations | select PrivateIPAddress
If ($privateip.count -gt 1) {
foreach ($private in $privateip) {
$WindowsIPs += $private.privateIPAddress + "`n"
}
}
elseIf ($privateip.privateIPAddress -ne $null) {
$WindowsIPs += $privateip.privateIPAddress + "`n"
}
}
}
foreach ($vm in $LinuxVMs) {
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach ($vmnicinterface in $vmnicinterfaces) {
$nic = $nics | Where-Object { $_.Id -eq $vmnicinterface }
$privateip = $nic.IpConfigurations | select PrivateIPAddress
If ($privateip.count -gt 1) {
foreach ($private in $privateip) {
$LinuxIPs += $private.privateIPAddress + "`n"
}
}
elseif ($privateip.privateIPAddress -ne $null) {
$LinuxIps += $privateip.privateIPAddress + "`n"
}
}
}
}
#>
#If ($WindowsIPs -ne "" -and $WindowsIPs.Length -gt 150) { $WindowsIPs | Out-File $OutFileWin -Encoding ASCII -NoNewline -Force }
#If ($LinuxIPs -ne "" -and $LinuxIPs.Length -gt 150) { $LinuxIPs | Out-File $OutFileLin -Encoding ASCII -NoNewline -Force }
$WindowsIPs | Out-File $OutFileWin -Encoding ASCII -NoNewline -Force
$LinuxIPs | Out-File $OutFileLin -Encoding ASCII -NoNewline -Force
@@ -0,0 +1,122 @@
<# Scheduled Task metadata
General
Get IPs for PA
run as ndgov\!itdvcenterppa
run whether user is logged on or not
Triggers
Daily, 11am
Daily, 11pm
Actions
old-C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noninteractive -file "C:\itdscript\GetIPs.ps1"
new-"C:\Program Files\PowerShell\7\pwsh.exe" -noninteractive -file "F:\GetVMwareVMGuestIPsForPA\GetVMwareVMGuestIPsForPA.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 1 hour -eq $true
if the running task does not end when requested, force it to stop
#>
$TimeStamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Start-Transcript F:\GetVMwareVMGuestIPsForPA\Logs\GetVMwareVMGuestIPsForPA-$Timestamp.log
#Set-PowerCLIConfiguration -Scope User -ParticipateInCEIP $false
#Set-PowerCLIConfiguration -DefaultVIServerMode multiple -Scope Session -Confirm:$false
#Connect
Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov
##Windows
#Output File
$OutFileWin = "c:\inetpub\wwwroot\Win.txt"
#$Date = Get-Date -UFormat "%Y%m%d%H%M%S"
Get-Item -Path $OutFileWin | Copy-Item -Destination "F:\GetVMwareVMGuestIPsForPA\Backup\Win\$Timestamp-Win.txt"
Remove-Item $OutFileWin
Start-Sleep -Seconds 5
#Get Powered On VM's
$vmwin = get-VM | Where-Object { $_.PowerState -eq "PoweredOn" `
-and ($_.GuestID -eq "windows7Guest" `
-or $_.GuestID -eq "windows7_64Guest" `
-or $_.GuestID -eq "windows7Server64Guest" `
-or $_.GuestID -eq "windows8_64Guest" `
-or $_.GuestID -eq "windows8Server64Guest" `
-or $_.GuestID -eq "windows9Server64Guest" `
-or $_.GuestID -eq "winLonghorn64Guest" `
-or $_.GuestID -eq "winLonghornGuest" `
-or $_.GuestID -eq "winNetStandardGuest" `
-or $_.GuestID -eq "winNetEnterpriseGuest" `
-or $_.GuestID -eq "windows9_64Guest" `
-or $_.GuestID -eq "windows2019srv_64Guest" `
-or $_.GuestID -eq "windows2019srvNext_64Guest" `
-or $_.GuestID -eq "windows2022srvNext_64Guest"
) }
$vmviewwin = $vmwin | Get-View
$Outputwin = ""
#Loop through VM's, NIC's, and IP addresses.
Foreach ($v in $vmviewwin) {
Foreach ($nic in $v.Guest.Net) {
Foreach ($IP in $nic.IPAddress) {
If ($IP -notlike "fe80*" -and $IP -notlike "192.168.*" -and $IP -notlike "172.16*") {
$OutputWin += $IP + "`n"
}
}
}
}
#If ($Outputwin -ne "") {$OutputWin | Out-File $OutFileWin -Encoding utf8 -NoNewline}
If ($Outputwin -ne "") { $OutputWin | Out-File $OutFileWin -Encoding ASCII -NoNewline }
##Linux
#Output File
$OutFileLin = "c:\inetpub\wwwroot\Lin.txt"
$Date = Get-Date -UFormat "%Y%m%d%H%M%S"
Get-Item -Path $OutFileLin | Copy-Item -Destination "F:\GetVMwareVMGuestIPsForPA\Backup\Lin\$Timestamp-Lin.txt"
Remove-Item $OutFileLin
Start-Sleep -Seconds 5
#Get Powered On VM's
$vmLin = get-VM | Where-Object { $_.PowerState -eq "PoweredOn" `
-and ($_.GuestID -eq "centos6_64Guest" `
-or $_.GuestID -eq "centos64Guest" `
-or $_.GuestID -eq "centos7_64Guest" `
-or $_.GuestID -eq "oracleLinux64Guest" `
-or $_.GuestID -eq "oracleLinux7_64Guest" `
-or $_.GuestID -eq "other26xLinux64Guest" `
-or $_.GuestID -eq "rhel4Guest" `
-or $_.GuestID -eq "rhel5Guest" `
-or $_.GuestID -eq "rhel5_64Guest" `
-or $_.GuestID -eq "rhel6Guest" `
-or $_.GuestID -eq "rhel6_64Guest" `
-or $_.GuestID -eq "rhel7_64Guest" `
-or $_.GuestID -eq "rhel8_64Guest" `
-or $_.GuestID -eq "rhel9_64Guest" `
-or $_.GuestID -eq "sles11_64Guest" `
-or $_.GuestID -eq "sles12_64Guest" `
-or $_.GuestID -eq "ubuntu64Guest") }
$vmviewlin = $vmLin | Get-View
$OutputLin = ""
#Loop through VM's, NIC's, and IP addresses.
Foreach ($v in $vmviewlin) {
Foreach ($nic in $v.Guest.Net) {
Foreach ($IP in $nic.IPAddress) {
If ($IP -notlike "fe80*" -and $IP -notlike "192.168.*" -and $IP -notlike "172.16*") {
$OutputLin += $IP + "`n"
}
}
}
}
#If ($OutputLin -ne "") {$OutputLin | Out-File $OutFileLin -Encoding utf8 -NoNewline}
If ($OutputLin -ne "") { $OutputLin | Out-File $OutFileLin -Encoding ASCII -NoNewline }
Disconnect-Viserver -Server itdvmvc1.nd.gov,itdvmvc2.nd.gov -Confirm:$false
Stop-Transcript
@@ -0,0 +1,116 @@
<# Scheduled Task metadata
General
Get IPs for PA
run as ndgov\!itdvcenterppa
run whether user is logged on or not
Triggers
Daily, 11am
Daily, 11pm
Actions
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noninteractive -file "C:\itdscript\GetIPs.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 1 hour -eq $true
if the running task does not end when requested, force it to stop
#>
Start-Transcript C:\ITDSCRIPT\Logs\GetIPs.txt -Append
#Add-PSSnapin VMware.VimAutomation.Core
Set-PowerCLIConfiguration -DefaultVIServerMode multiple -Scope Session -Confirm:$false
#Connect
Connect-VIServer itdvmvc1.nd.gov, itdvmvc2.nd.gov
##Windows
#Output File
$OutFileWin = "c:\inetpub\wwwroot\Win.txt"
$Date = Get-Date -UFormat "%Y%m%d%H%M%S"
Get-Item -Path $OutFileWin | Copy-Item -Destination "D:\Backup\Win\$Date-Win.txt"
Remove-Item $OutFileWin
Start-Sleep -Seconds 5
#Get Powered On VM's
$vmwin = get-VM | Where-Object { $_.PowerState -eq "PoweredOn" `
-and ($_.GuestID -eq "windows7Guest" `
-or $_.GuestID -eq "windows7_64Guest" `
-or $_.GuestID -eq "windows7Server64Guest" `
-or $_.GuestID -eq "windows8_64Guest" `
-or $_.GuestID -eq "windows8Server64Guest" `
-or $_.GuestID -eq "windows9Server64Guest" `
-or $_.GuestID -eq "winLonghorn64Guest" `
-or $_.GuestID -eq "winLonghornGuest" `
-or $_.GuestID -eq "winNetStandardGuest" `
-or $_.GuestID -eq "winNetEnterpriseGuest" `
-or $_.GuestID -eq "windows9_64Guest" `
-or $_.GuestID -eq "windows2019srv_64Guest" `
-or $_.GuestID -eq "windows2019srvNext_64Guest") }
$vmviewwin = $vmwin | Get-View
$Outputwin = ""
#Loop through VM's, NIC's, and IP addresses.
Foreach ($v in $vmviewwin) {
Foreach ($nic in $v.Guest.Net) {
Foreach ($IP in $nic.IPAddress) {
If ($IP -notlike "fe80*" -and $IP -notlike "192.168.*" -and $IP -notlike "172.16*") {
$OutputWin += $IP + "`n"
}
}
}
}
#If ($Outputwin -ne "") {$OutputWin | Out-File $OutFileWin -Encoding utf8 -NoNewline}
If ($Outputwin -ne "") { $OutputWin | Out-File $OutFileWin -Encoding ASCII -NoNewline }
##Linux
#Output File
$OutFileLin = "c:\inetpub\wwwroot\Lin.txt"
$Date = Get-Date -UFormat "%Y%m%d%H%M%S"
Get-Item -Path $OutFileLin | Copy-Item -Destination "D:\Backup\Lin\$Date-Lin.txt"
Remove-Item $OutFileLin
Start-Sleep -Seconds 5
#Get Powered On VM's
$vmLin = get-VM | Where-Object { $_.PowerState -eq "PoweredOn" `
-and ($_.GuestID -eq "centos6_64Guest" `
-or $_.GuestID -eq "centos64Guest" `
-or $_.GuestID -eq "centos7_64Guest" `
-or $_.GuestID -eq "oracleLinux64Guest" `
-or $_.GuestID -eq "oracleLinux7_64Guest" `
-or $_.GuestID -eq "rhel4Guest" `
-or $_.GuestID -eq "rhel5Guest" `
-or $_.GuestID -eq "rhel5_64Guest" `
-or $_.GuestID -eq "rhel6Guest" `
-or $_.GuestID -eq "rhel6_64Guest" `
-or $_.GuestID -eq "rhel7_64Guest" `
-or $_.GuestID -eq "sles11_64Guest" `
-or $_.GuestID -eq "sles12_64Guest" `
-or $_.GuestID -eq "ubuntu64Guest") }
$vmviewlin = $vmLin | Get-View
$OutputLin = ""
#Loop through VM's, NIC's, and IP addresses.
Foreach ($v in $vmviewlin) {
Foreach ($nic in $v.Guest.Net) {
Foreach ($IP in $nic.IPAddress) {
If ($IP -notlike "fe80*" -and $IP -notlike "192.168.*" -and $IP -notlike "172.16*") {
$OutputLin += $IP + "`n"
}
}
}
}
#If ($OutputLin -ne "") {$OutputLin | Out-File $OutFileLin -Encoding utf8 -NoNewline}
If ($OutputLin -ne "") { $OutputLin | Out-File $OutFileLin -Encoding ASCII -NoNewline }
Stop-Transcript
@@ -0,0 +1,149 @@
<# Scheduled Task metadata
General
Get IPs for PA - Azure
run as ndgov\svcitdazurescript
run whether user is logged on or not
Triggers
Daily, 2pm - repeat every 1 hour indefinitely
Actions
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noninteractive -file "C:\itdscript\GetIPsAzure.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 1 hour -eq $true
if the running task does not end when requested, force it to stop
#>
Start-Transcript C:\itdscript\Logs\GetIPsAzureB.txt -Append
$VerbosePerfrence = "Continue"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$OutputPath = "C:\inetpub\wwwroot"
$WindowsIPs = ""
$LinuxIPs = ""
$OutFileWin = $OutputPath + "\AzureWin.txt"
$OutFileLin = $OutputPath + "\AzureLin.txt"
Remove-Item $OutFileWin
Remove-Item $OutFileLin
$username="svcitdazurescript@nd.gov"
$usernameg="svcitdazurescript@ndstate.onmicrosoft.com"
#Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat
$password=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat | ConvertTo-SecureString
$passwordg=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sacg.bat | ConvertTo-SecureString
$AdminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$password
$AdminCredg=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $usernameg,$passwordg
Login-AzureRMAccount -Credential $AdminCred -Environment AzureCloud -Verbose
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$WindowsVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Windows"}
$LinuxVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $WindowsVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$WindowsIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$WindowsIPs += $privateip.privateIPAddress + "`n"
}
}
}
foreach($vm in $LinuxVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$LinuxIPs += $private.privateIPAddress + "`n"
}
}
elseif($privateip.privateIPAddress -ne $null)
{
$LinuxIps += $privateip.privateIPAddress + "`n"
}
}
}
}
Login-AzureRMAccount -EnvironmentName AzureUSGovernment -Credential $AdminCredg
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$WindowsVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Windows"}
$LinuxVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $WindowsVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$WindowsIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$WindowsIPs += $privateip.privateIPAddress + "`n"
}
}
}
foreach($vm in $LinuxVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$LinuxIPs += $private.privateIPAddress + "`n"
}
}
elseif($privateip.privateIPAddress -ne $null)
{
$LinuxIps += $privateip.privateIPAddress + "`n"
}
}
}
}
If ($WindowsIPs -ne "" -and $WindowsIPs.Length -gt 150) {$WindowsIPs | Out-File $OutFileWin -Encoding ASCII -NoNewline -Force}
If ($LinuxIPs -ne ""-and $LinuxIPs.Length -gt 150) {$LinuxIPs | Out-File $OutFileLin -Encoding ASCII -NoNewline -Force}
@@ -0,0 +1,104 @@
<# Scheduled Task metadata
General
Get IPs for PA - Azure Backup
run as ndgov\svcitdazurescript
run whether user is logged on or not
Triggers
Daily, 4:12pm - repeat every 1 hour indefinitely
Actions
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noninteractive -file "C:\itdscript\GetIPsAzureBackup.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 1 hour -eq $true
if the running task does not end when requested, force it to stop
#>
start-transcript D:\zm.log -force
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$OutputPath = "C:\inetpub\wwwroot"
$OutputBackupPath = "C:\inetpub\wwwroot\AzureBak\"
$CurrentDateTime = Get-Date -UFormat "%Y%m%d%H%M%S"
$BackupIPs = ""
$OutFileBak = $OutputPath + "\AzureBak.txt"
$OutFileBakBackup = $OutputBackupPath + "\AzureBak-$CurrentDateTime.txt"
Remove-Item $OutFileBak
$username="svcitdazurescript@nd.gov"
$usernameg="svcitdazurescript@ndstate.onmicrosoft.com"
#Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat
$password=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat | ConvertTo-SecureString
$passwordg=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sacg.bat | ConvertTo-SecureString
$AdminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$password
$AdminCredg=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $usernameg,$passwordg
Login-AzureRMAccount -Credential $AdminCred -Environment AzureCloud
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$BackupVMs = Get-AzureRMVM | Where-Object {$_.Tags["Backup"] -match "OS-BackupEnabled"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $BackupVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$BackupIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$BackupIPs += $privateip.privateIPAddress + "`n"
}
}
}
}
Login-AzureRMAccount -EnvironmentName AzureUSGovernment -Credential $AdminCredg
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$BackupVMs = Get-AzureRMVM | Where-Object {$_.Tags["Backup"] -match "OS-BackupEnabled"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $BackupVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$BackupIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$BackupIPs += $privateip.privateIPAddress + "`n"
}
}
}
}
If ($BackupIPs -ne "") {
$BackupIPs | Out-File $OutFileBak -Encoding ASCII -NoNewline -Force
$BackupUPs | Out-File $OutFileBakBackup -Encoding ascii -NoNewline -Force
}
@@ -0,0 +1,134 @@
<# Scheduled Task metadata
General
Get IPs for PA - Azure Backup
run as ndgov\!itdvcenterscript
run whether user is logged on or not
Triggers
Daily, 11:30am - repeat every 1 hour indefinitely
Actions
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noninteractive -file "C:\itdscript\GetIPsMonitor.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 1 hour -eq $true
if the running task does not end when requested, force it to stop
#>
#cdfelchle 7/12/16
#Files to Monitor
$FileCheckWin = "c:\inetpub\wwwroot\win.txt"
$FileCheckLin = "c:\inetpub\wwwroot\lin.txt"
$FileCheckBak = "c:\inetpub\wwwroot\AzureBak.txt"
$FileCheckWinAz = "c:\inetpub\wwwroot\Azurewin.txt"
$FileCheckLinAz = "c:\inetpub\wwwroot\Azurelin.txt"
#E-mail Initialization and Construction
$emailSubject = "VMware-PA Integration Failure"
$emailRelay = "apprelay2.nd.gov"
$emailBody =
"Scripting Server Error Report (ITDVMVCP1SCRIPT)
------------------------------------------
"
$emailRecipients = "itdvctremailalerts@nd.gov"
$emailSender = "itdvmvcp1script@nd.gov"
#File Presence Check
$WindowsPresent = Test-Path $FileCheckWin
$LinuxPresent = Test-Path $FileCheckLin
$AzureWindowsPresent = Test-Path $FileCheckWinAz
$AzureLinuxPresent = Test-Path $FileCheckLinAz
$AzureBakPresent = Test-Path $FileCheckBak
#Flag to send e-mail
$SendEmail = $False
#File Presence Check
If ($WindowsPresent -eq $False){
$SendEmail = $True
$emailBody += $FileCheckWin + " --- Missing File`n"
}
If ($LinuxPresent -eq $False){
$SendEmail = $True
$emailBody += $FileCheckLin + " --- Missing File`n"
}
If ($AzureWindowsPresent -eq $False){
$SendEmail = $True
$emailBody += $FileCheckWinAz + " --- Missing File`n"
}
If ($AzureLinuxPresent -eq $False){
$SendEmail = $True
$emailBody += $FileCheckLinAz + " --- Missing File`n"
}
If ($AzureBakPresent -eq $False){
$SendEmail = $True
$emailBody += $FileCheckBak + " --- Missing File`n"
}
#File Size Check
If ($WindowsPresent -eq $True -and (Get-Item $FileCheckWin).length -lt 1000){
$SendEmail = $True
$emailBody += "$FileCheckWin --- File size is less than 1kb`n"
}
If ($LinuxPresent -eq $True -and (Get-Item $FileCheckLin).length -lt 1000){
$SendEmail = $True
$emailBody += "$FileCheckLin --- File size is less than 1kb`n"
}
If ($AzureWindowsPresent -eq $True -and (Get-Item $FileCheckWinAz).length -lt 100){
$SendEmail = $True
$emailBody += "$FileCheckWinAz --- File size is less than 1kb`n"
}
If ($AzureLinuxPresent -eq $True -and (Get-Item $FileCheckLinAz).length -lt 100){
$SendEmail = $True
$emailBody += "$FileCheckLinAz --- File size is less than 1kb`n"
}
If ($AzureBakPresent -eq $True -and (Get-Item $FileCheckBak).length -lt 10){
$SendEmail = $True
$emailBody += "$FileCheckBak --- File size is less than 10 bytes`n"
}
#File Age Check
$CurrentTime = Get-Date
If ($WindowsPresent -eq $True -and (Get-Item $FileCheckWin).LastWriteTime -lt $CurrentTime.AddHours(-13)){
$SendEmail = $True
$emailBody += "$FileCheckWin --- File is older than 12 hours`n"
}
If ($LinuxPresent -eq $True -and (Get-Item $FileCheckLin).LastWriteTime -lt $CurrentTime.AddHours(-13)){
$SendEmail = $True
$emailBody += "$FileCheckLin --- File is older than 12 hours`n"
}
If ($AzureWindowsPresent -eq $True -and (Get-Item $FileCheckWinAz).LastWriteTime -lt $CurrentTime.AddHours(-13)){
$SendEmail = $True
$emailBody += "$FileCheckWinAz --- File is older than 12 hours`n"
}
If ($AzureLinuxPresent -eq $True -and (Get-Item $FileCheckLinAz).LastWriteTime -lt $CurrentTime.AddHours(-13)){
$SendEmail = $True
$emailBody += "$FileCheckLinAz --- File is older than 12 hours`n"
}
If ($AzureBakPresent -eq $True -and (Get-Item $FileCheckBak).LastWriteTime -lt $CurrentTime.AddHours(-13)){
$SendEmail = $True
$emailBody += "$FileCheckBak --- File is older than 12 hours`n"
}
If ($SendEmail -eq $True){
Send-MailMessage -To $emailRecipients -From $emailSender -Subject $emailSubject -Body $emailBody -SmtpServer $emailRelay
}
@@ -0,0 +1,87 @@
<# Scheduled Task metadata
General
Old-VMware Billing
run as ndgov\!itdvcenterscript (required for SQL Database access)
run whether user is logged on or not
Triggers
Daily, 5am
Actions
old-C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noninteractive -file "C:\itdscript\vmconfig.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 1 hour -eq $true
if the running task does not end when requested, force it to stop
#>
Start-Transcript C:\ITDSCRIPT\Logs\VMConfig.txt
Add-PSSnapin VMware.VimAutomation.Core
Set-PowerCLIConfiguration -DefaultVIServerMode multiple -Scope Session -Confirm:$false
Connect-VIServer -Server itdvmvcp1.nd.gov,itdvmvcp2.nd.gov,itdvmvc1.nd.gov,itdvmvc2.nd.gov
#Connect-VIServer -Server itdvmvcp2.nd.gov
###########################
## Functions #
###########################
###
### Override Invoke-SQLCmd cmdlet in order to display proper error Handling.
###
function Invoke-SQLCmd ([string] $ServerInstance, [string] $Database, [String] $Query)
{
Try
{
$conn = new-object system.data.SqlClient.SqlConnection("Data Source=$ServerInstance;Integrated Security=TRUE;Initial Catalog=$Database");
$ds = new-object "System.Data.DataSet" "dsChildSites"
$da = new-object "System.Data.SqlClient.SqlDataAdapter" ($Query, $conn)
$fillcnt = $da.Fill($ds)
$conn.Close()
$dtChild = new-object "System.Data.DataTable" "dsChildSites"
$dtChild = $ds.Tables[0]
$dtChild | FOREACH-OBJECT -process {
$_
}
}
Catch
{
write-output $Query
Throw $_
}
}
#$Servers = Get-VM | Where-Object {$_.PowerState -like 'PoweredOn'} | Select Name, NumCPU, @{label="MemoryMB"; expression={$_.MemoryGB * 1024}}, @{label="HardDiskSizeGB"; expression={(Get-HardDisk -VM $_ | Measure-Object -Sum CapacityGB).Sum * 1024}}, VMHost | Sort-Object Name
$Servers = Get-VM | Where-Object {($_ | Get-Harddisk).count -ne 0} | Select Name, NumCPU, @{label="MemoryMB"; expression={$_.MemoryGB * 1024}}, @{label="HardDiskSizeGB"; expression={(Get-HardDisk -VM $_ | Measure-Object -Sum CapacityGB).Sum * 1024}}, VMHost | Sort-Object Name
$SQLServer = "ITDSQL16P1\SQL16P1"
$DB = "ITD-SRS-Billing"
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$SQLServer';database='$DB';Integrated Security=TRUE;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Date = "'" + (Get-Date).ToString('yyyy/MM/dd') + "'"
$sql = "delete from [VMware_VCenter_VMs] where snapshotdate = $Date;"
Invoke-SQLCmd -ServerInstance $SQLServer -Database $DB -Query $sql
foreach($Server in $Servers) {
$ServerName = "'" + $Server.Name + "'"
$ServerMemoryMB = $Server.MemoryMB
$ServerNumCPU = $Server.NumCPU
$ServerHardDiskSizeGB = $Server.HardDiskSizeGB
$ServerHost = "'" + $Server.VMHost + "'"
$sql ="INSERT INTO [VMware_VCenter_VMs] (ServerName, SnapshotDate, VMName, Memory_MB, Num_VCPU, Disk_MB, ESXHostName) Values ('None', $Date, $ServerName, $ServerMemoryMB, $ServerNumCPU, $ServerHardDiskSizeGB, $ServerHost);"
Invoke-SQLCmd -ServerInstance $SQLServer -Database $DB -Query $sql
}
$Connection.Close()
Stop-Transcript
@@ -0,0 +1,30 @@
<# Scheduled Task metadata
General
SetVMTagAndMoveToAppNameFolder
run as ndgov\svcitdiaassched
run whether user is logged on or not
run with highest privileges
Triggers
Daily, 1pm
Actions
old powershell.exe -file "D:\PowerShellTasks\SetVMTagAndMoveToAppNameFolder\SetVMTagAndMoveToAppNameFolderTask.ps1"
new "C:\Program Files\PowerShell\7\pwsh.exe" -file "F:\PowerShellTasks\SetVMTagAndMoveToAppNameFolder\SetVMTagAndMoveToAppNameFolderTask.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 3 days
if the running task does not end when requested, force it to stop
#>
$TimeStamp = Get-Date -UFormat "%Y%m%d-%H%M%S"
$TranscriptPath = "F:\SetVMTagAndMoveToAppNameFolder\Logs\SetVMTagAndMoveToAppNameFolderTask-$Timestamp.log"
Start-Transcript $TranscriptPath
Connect-ITDvCenter -Credential $svcitdvmvcauto
Set-ITDVMwareVMTagFromSharePoint -SharePointCredential $svcitdiaassprw -Verbose
Move-ITDVMwareVMToAppNameFolder -Credential $svcitdvmvcauto -Verbose
Disconnect-VIServer -Server * -Force -Confirm:$false
@@ -0,0 +1,12 @@
$TimeStamp = Get-Date -UFormat "%Y%m%d-%H%M%S"
$TranscriptPath = "D:\PowerShellTasks\StartDatastoreUnmap\Logs\StartDatastoreUnmapTask-$Timestamp.log"
Start-Transcript $TranscriptPath
try
{
Start-ITDVMwareDatastoreUnmap -Credential $svcitdvmvcauto -Verbose
}
catch
{
Send-MailMessage -To itdvctremailalerts@nd.gov -From itdvmvcp1script@nd.gov -Subject "Task StartITDVMwareDatastoreUnmap errored" -Body "Task started $TimeStamp.`nCheck logs for further information" -SmtpServer apprelay1.nd.gov
}
@@ -0,0 +1,28 @@
<# Scheduled Task metadata
General
SetVMTagNadMovToAppNameFolder
run as ndgov\svcitdiaassched
run whether user is logged on or not
run with highest privileges
Triggers
Daily, 8am
Disabled
Actions
powershell.exe -file "D:\PowerShellTasks\SetVMTagAndMoveToAppNameFolder\SyncVMwareAppNameTagsFromSharePoint.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 3 days
if the running task does not end when requested, force it to stop
#>
$TimeStamp = Get-Date -UFormat "%Y%m%d-%H%M%S"
$TranscriptPath = "D:\PowerShellTasks\SyncVMwareAppNameTagsFromSharePoint\Logs\SyncVMwareAppNameTagsFromSharePointTask-$Timestamp.log"
Start-Transcript $TranscriptPath
try {
Sync-ITDVMwareSharePointAppNameTags -vCenterCredential $svcitdvmvcauto -SharePointCredential $svcitdiaassprw -Verbose
}
catch {
Send-MailMessage -To itdvctremailalerts@nd.gov -From itdvmvcp1script@nd.gov -Subject "Task SyncVMwareAppNameTagsFromSharePoint errored" -Body "Task started $TimeStamp.`nCheck logs for further information" -SmtpServer apprelay1.nd.gov
}
@@ -0,0 +1,34 @@
<# Scheduled Task metadata
General
SetVMTagNadMovToAppNameFolder
run as ndgov\svcitdiaassched
run whether user is logged on or not
run with highest privileges
Triggers
Daily, 10:15am, repeat every 8 hours
Actions
"C:\Program Files\PowerShell\7\pwsh.exe" -file "D:\PowerShellTasks\SyncVMwareDatastoresToSharePoint\SyncVMwareDatastoresToSharePoint.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 3 days
if the running task does not end when requested, force it to stop
#>
$TimeStamp = Get-Date -UFormat "%Y%m%d-%H%M%S"
$TranscriptPath = "F:\SyncVMwareDatastoresToSharePoint\Logs\SyncVMwareDatastoresToSharePoint-$Timestamp.log"
Start-Transcript $TranscriptPath
try
{
Connect-ITDvCenter -Credential $svcitdvmvcauto
Sync-ITDVMwareSharePointDatastoreRecord -SharePointCredential $svcitdiaassprw -verbose
Disconnect-VIServer -Server * -Confirm:$flse
}
catch
{
Send-MailMessage -To itdvctremailalerts@nd.gov -From itdvmvcp1script@nd.gov -Subject "Task SyncVMwareDatastoresToSharePoint errored" -Body "Task started $TimeStamp.`nCheck logs for further information" -SmtpServer apprelay1.nd.gov
}
Stop-Transcript
@@ -0,0 +1,10 @@
Connect-HPOVMgmt -Hostname itdoneviewp1.nd.gov -Credential $AdminCred -LoginAcknowledge
$VMwareHosts = Get-VMHost
$HPOVServers = Get-HPOVServer | Select-Object *,@{n='Enclosure';e={$_.Name.split(',')[0]}}
ForEach($VMwareHost in $VMwareHosts)
{
$HPOVServer = $HPOVServers | where-object ServerName -eq $VMwareHost.Name
$VMwareHost | New-TagAssignment -Tag $HPOVServer.Enclosure -Server $VMwareHost.Uid.split('@')[1].split(':')[0]
}
@@ -0,0 +1,34 @@
<# Scheduled Task metadata
General
SyncVMwareSharePointTags
run as ndgov\svcitdiaassched
run whether user is logged on or not
run with highest privileges
Triggers
Daily, 10:15am, repeat every 8 hours
Actions
powershell.exe -file "D:\PowerShellTasks\SetVMTagAndMoveToAppNameFolder\SyncVMwareTagsFromSharePoint.ps1"
"C:\Program Files\PowerShell\7\pwsh.exe" -file "F:\SyncVMwareTagsFromSharePoint\SyncVMwareTagsFromSharePointTask.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 3 days
if the running task does not end when requested, force it to stop
#>
$TimeStamp = Get-Date -UFormat "%Y%m%d-%H%M%S"
$TranscriptPath = "F:\SyncVMwareTagsFromSharePoint\Logs\SyncVMwareTagsFromSharePointTask-$Timestamp.log"
Start-Transcript $TranscriptPath
try {
#Sync-ITDVMwareSharePointTags -vCenterCredential $svcitdvmvcauto -SharePointCredential $svcitdiaassprw -Verbose
Connect-ITDvCenter -Credential $svcitdvmvcauto
Sync-ITDVMwareSharePointTags -SharePointCredential $svcitdiaassprw -Verbose
Disconnect-VIServer -Server * -Confirm:$false
}
catch {
Send-MailMessage -To itdvctremailalerts@nd.gov -From itdvmvc1script@nd.gov -Subject "Task SyncVMwareTagsFromSharePoint errored" -Body "Task started $TimeStamp.`nCheck logs for further information" -SmtpServer apprelay1.nd.gov
}
@@ -0,0 +1,62 @@
<# Scheduled Task metadata
General
Old-VMware Billing
run as ndgov\!itdvcenterscript (required for SQL Database access)
run whether user is logged on or not
Triggers
Daily, 5am
Actions
old-C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noninteractive -file "C:\itdscript\vmconfig.ps1"
new-"C:\Program Files\PowerShell\7\pwsh.exe" -noninteractive -file "F:\SyncVMwareVMsToSql\SyncVMwareVMsToSql.ps1"
"C:\Program Files\PowerShell\7\pwsh.exe" -noninteractive -file "F:\SyncVMwareVMsToSql\SyncVMwareVMsToSql.ps1"
Settings
allow task to be run on demand
stop the task if it runs longer than 1 hour -eq $true
if the running task does not end when requested, force it to stop
SQL Query to check for most recent 2500 records
SELECT TOP (2500) [ServerName]
,[SnapshotDate]
,[VMName]
,[Memory_MB]
,[Num_VCPU]
,[Disk_MB]
,[ESXHostName]
FROM [ITD-SRS-Billing].[dbo].[VMWare_VCenter_VMs]
ORDER BY SnapshotDate DESC, VMName ASC
#>
$Secret:!itdvcenterscript
$TimeStamp = Get-Date -UFormat "%Y%m%d%H%M%S"
Start-Transcript F:\SyncVMwareVMsToSql\Logs\SyncVMwareVMsToSql-$Timestamp.log
Set-PowerCLIConfiguration -DefaultVIServerMode multiple -Scope Session -Confirm:$false
Connect-ITDvCenter
$Datacenters = Get-Datacenter | Where-Object {$_.Name -notlike "*Normandy*" -and $_.Name -notlike "*Vantis*"}
$VMs = $Datacenters | Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" -and $_.Name -notlike "itdzmtest*"} | Select Name, NumCPU, @{label="MemoryMB"; expression={$_.MemoryGB * 1024}}, @{label="HardDiskSizeGB"; expression={(Get-HardDisk -VM $_ | Measure-Object -Sum CapacityGB).Sum * 1024}}, VMHost | Sort-Object Name
$SqlServer = "itdsql22p1.nd.gov\SQL22P1"
$Database = "ITD-SRS-Billing"
$Date = "'" + (Get-Date).ToString('yyyy/MM/dd') + "'"
# remove today's entries if already there
Write-Verbose -Message "remove today's entries if already there"
$SqlQuery = "delete from [VMware_VCenter_VMs] where snapshotdate = $Date;"
Invoke-SQLCmd -ServerInstance $SqlServer -Database $Database -Query $SqlQuery
foreach($VM in $VMs) {
Write-Verbose -Message ("Begin " + $VM.Name)
$VMName = "'" + $VM.Name + "'"
$VMMemoryMB = $VM.MemoryMB
$VMNumCPU = $VM.NumCPU
$VMHardDiskSizeGB = $VM.HardDiskSizeGB
$VMHost = "'" + $VM.VMHost + "'"
$SqlQuery ="INSERT INTO [VMware_VCenter_VMs] (ServerName, SnapshotDate, VMName, Memory_MB, Num_VCPU, Disk_MB, ESXHostName) Values ('None', $Date, $VMName, $VMMemoryMB, $VMNumCPU, $VMHardDiskSizeGB, $VMHost);"
Invoke-SQLCmd -ServerInstance $SqlServer -Database $Database -Query $SqlQuery
}
Stop-Transcript