

<#
.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 {
        
    }
}