Dealing with Clusters

# refreshCluster.ps1
# Function to refresh a cluster in VMM in anticipation of errors with unregistered SMB/CIFS shares

$clustername='cluster-101.kimconnect.com'
$runasAccount='domain\hyperv-admin'

function refreshCluster($clusterName,$runasAccount){    
  # Function to Register FileShare to a Cluster in SCVMM
  function registerFileShareToCluster{
    param(
      $clustername,
      $fileSharePath,
      $runasAccount
    )
    $ErrorActionPreference='Stop'
    try{
      Import-Module -Name "virtualmachinemanager"
      # Preempt this error
      # Error (26193)
      # No Run As account is associated with the host
      if($runasAccount){
        $runas = Get-SCRunAsAccount -Name $runasAccount
        $hostCluster = Get-SCVMHostCluster -Name $clustername
        Set-SCVmHostCluster -VMHostCluster $hostCluster -VMHostManagementCredential $runas
      }
      <# Got this error
      Set-SCVmHostCluster : A Hardware Management error has occurred trying to contact server
      :n:CannotProcessFilter :HRESULT 0x8033801a:No instance found with given property values. .
      WinRM: URL: [http://serverFQDN:5985], Verb: [INVOKE], Method: [AddToLocalAdminGroup], Resource:
      [http://schemas.microsoft.com/wbem/wsman/1/wmi/root/scvmm/AgentManagement]
      (Error ID: 2927, Detailed Error: Unknown error (0x8033801a))
  
      Check that WinRM is installed and running on server. For more information use the command
      "winrm helpmsg hresult" and https://learn.microsoft.com/en-us/troubleshoot/system-center/vmm/troubleshoot-issues-adding-hyper-v-host.
  
      To restart the job, run the following command:
      PS> Restart-Job -Job (Get-VMMServer localhost | Get-Job | where { $_.ID -eq })
      At line:1 char:1
      + Set-SCVmHostCluster -VMHostCluster $hostCluster -VMHostManagementCred ...
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : ReadError: (:) [Set-SCVMHostCluster], CarmineException
          + FullyQualifiedErrorId : 2927,Microsoft.SystemCenter.VirtualMachineManager.Cmdlets.SetHostClusterCmdlet
      #>
      <# preempt this error:
      Register-SCStorageFileShare : A parameter cannot be found that matches parameter name 'VMHostManagementCredential'.
      At line:1 char:87
      + ... ePath -VMHostCluster $hostCluster -VMHostManagementCredential $runasA ...
      +                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : InvalidArgument: (:) [Register-SCStorageFileShare], ParameterBindingException
          + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.SystemCenter.VirtualMachineManager.Cmdlets.RegisterSCSt
        orageFileShareCmdlet
      #>
      Register-SCStorageFileShare -FileSharePath $fileSharePath -VMHostCluster $hostCluster
      <# This error can safely be ignored
      Error (26233)
      Capacity/Free space cannot be calculated for \\NAS\CIFSSHARE. Failed to retrieve information with Win32 error code 64.
      #>  
  
      # This snippet is to register the SMB server onto VMM as a resource. It's optional
      # $servername='servername'
      # $shareName='test'
      # $addedShare = Get-SCStorageFileShare -Name "$servername\$sharename"
      # Register-SCStorageFileShare -StorageFileShare $addedShare -VMHostCluster $hostCluster
      # Set-SCVMHostCluster -RunAsynchronously -VMHostCluster $hostCluster -VMHostManagementCredential $runas
      return $true
    }catch{
      write-warning $_
      return $false
    }
  
  }
  # $clustername='CLUSTER-9999'
  # $fileSharePaths=@(
  #   '\\FILESERVER01\SHARE01',
  #   '\\FILESERVER01\SHARE02'
  # )
  # $runasAccount='domain\hyperv-admin'
  # foreach($fileSharePath in $fileSharePaths){  
  #   $success=registerFileShareToCluster $clusterName $fileSharePath $runasAccount
  #   if($success){
  #     write-host "$fileSharePath added successfully" -ForegroundColor Green
  #   }else{
  #     write-host "$fileSharePath was NOT added" -ForegroundColor Yellow
  #   }
  # }
  
  #Add-PSSnapin Microsoft.SystemCenter.VirtualMachineManager
  Import-Module -Name "virtualmachinemanager"
  #$guestVMs=Get-ClusterResource -cluster $clustername|?{$_.resourcetype.name -eq 'virtual machine'}
  $guestVMs=Get-ClusterGroup -Cluster $clustername|?{$_.GroupType -eq 'VirtualMachine'}
  foreach ($vm in $guestVMs){
      #[string]$vmName=$_.OwnerGroup.Name
      $vmName=$vm.Name
      $status=((Get-SCVirtualMachine -Name $vmName).StatusString|out-string).trim()
      if($status -notmatch 'Stopped|Running' -and !(!$status)){
          try{            
            try{
              Read-SCVirtualMachine $vmName -EA Stop
              write-host "$vmName refresh initiated." -ForegroundColor Green
            }catch [Microsoft.VirtualManager.Utils.CarmineException]{
              $errorMessage=$_
                $smbPath=[regex]::match($errorMessage,'\\\\(.*)\\').Value
                if($smbPath){
                    write-host "Add this SMB/CIFS path the cluster: $smbPath"
                    $smbRegistered=registerFileShareToCluster $clustername $smbPath $runasAccount
                    if($smbRegistered){
                      $null=Refresh-VM -VM $vmName -RunAsynchronously -Force;
                      write-host "$vmName refresh initiated." -ForegroundColor Yellow
                      #$null=Read-SCVirtualMachine -vm $vmName -Force -RunAsynchronously; # This statement missed 'stopped' VMs
                    }else{
                      write-warning "Unable to register $smbPath"
                    }
                }else{
                  write-host $errorMessage
                }
            }
          }catch{
            write-host $_
          }
      }else{
          write-host "$vmName status $(if($status){$status}else{'Unknown'})." -ForegroundColor Gray         
      }
    }
}
refreshCluster $clustername $runasAccount

Dealing with Individual Hyper-V Hosts

# refreshHost.ps1
$hostName='hyperv-2000.kimconnect.com'
$runasAccount='domain\hyperv-admin'

function refreshHost($hostname,$runasAccount){
  
  # Sub-routine to add Share Path to Hyper-V Host
  function addFileSharePathToHost($hostName,$sharePath,$runasAccount){
    try{
      $vmHost = Get-SCVMHost -ComputerName $hostName -EA Stop
      Register-SCStorageFileShare -FileSharePath $sharePath -VMHost $vmHost -EA Stop
      return $true
    }catch [Microsoft.VirtualManager.Utils.CarmineException]{
      $errorMessage=$_
      if($errorMessage -like "*Error ID: 26193*"){
        $runas = Get-SCRunAsAccount -Name $runasAccount
        Set-SCVmHost -VMHost $vmHost -VMHostManagementCredential $runas
        Register-SCStorageFileShare -FileSharePath $sharePath -VMHost $vmHost
        return $true
      }else{
        write-warning "$errorMessage"
        return $false
      }
    }catch{
      write-warning $_
      return $false
    }
    #Set-SCVMHost -VMHost $vmHost -RunAsynchronously -BaseDiskPaths $sharePath #-VMPaths "C:\ProgramData\Microsoft\Windows\Hyper-V"
  }
  
  $unsupportedSharedFiles=Get-SCVMHost $hostname | Get-SCVirtualMachine | ? {$_.Status -eq 'UnsupportedSharedFiles'} | Select Name,State,VMHost
  foreach($vmName in $unsupportedSharedFiles.Name){
    try{
      Read-SCVirtualMachine $vmName -EA Stop
      write-host "$vmName refresh initiated." -ForegroundColor Green
    }catch [Microsoft.VirtualManager.Utils.CarmineException]{
      $errorMessage=$_
        $smbPath=[regex]::match($errorMessage,'\\\\(.*)\\').Value
        if($smbPath){
            write-host "Add this SMB/CIFS path the cluster: $smbPath"
            $smbRegistered=addFileSharePathToHost $hostname $smbPath $runasAccount
            if($smbRegistered){
              $null=Refresh-VM -VM $vmName -RunAsynchronously -Force;
              write-host "$vmName refresh initiated." -ForegroundColor Yellow
              #$null=Read-SCVirtualMachine -vm $vmName -Force -RunAsynchronously; # This statement missed 'stopped' VMs
            }else{
              write-warning "Unable to register $smbPath"
            }
        }else{
          write-host $errorMessage
        }
    }
  }  
}
refreshHost $hostName $runasAccount