Install.ps1

function Install-Appliance {
  param(
    [Parameter(
      Mandatory = $true,
      HelpMessage = "Accept the End User License Agrement 'https://www.netapp.com/pdf.html?item=/media/14114-enduserlicenseagreementworldwide.pdf'")]
    [ValidateNotNullOrEmpty()]
    [boolean]
    $AcceptNetAppEulaAggrement,

    [Parameter(
      Mandatory = $true,
      HelpMessage = 'Virtual machine name for the appliance.')]
    [ValidateNotNullOrEmpty()]
    [string]
    $ApplianceVirtualMachine,

    [Parameter(
      Mandatory = $false,
      HelpMessage = 'Destination ESXi cluster name to be used for deploying the appliance.')]
    [ValidateNotNullOrEmpty()]
    [string]
    $EsxiCluster,

    [Parameter(
      Mandatory = $true,
      HelpMessage = 'Datastore to be used for the appliance.')]
    [ValidateNotNullOrEmpty()]
    [string]
    $VmDatastore,

    [Parameter(
      Mandatory = $true,
      HelpMessage = 'Destination network to be used for the appliance.')]
    [ValidateNotNullOrEmpty()]
    [string]
    $NetworkMapping,

    [Parameter(
      Mandatory = $true,
      HelpMessage = 'Network name to be used for the appliance.')]
    [string]
    $ApplianceNetworkName,

    [Parameter(
      HelpMessage = 'Specifies if Dhcp has to be used for the appliance instead of static IP address.')]
    [boolean]
    $Dhcp,

    [Parameter(
      Mandatory = $false,
      HelpMessage = 'IPV4 address to be used for the appliance.')]
    [string]
    $ApplianceIPAddress,

    [Parameter(
      Mandatory = $false,
      HelpMessage = 'Subnet mask.')]
    [string]
    $Netmask,

    [Parameter(
      Mandatory = $false,
      HelpMessage = 'Gateway IP address.')]
    [string]
    $Gateway,

    [Parameter(
      Mandatory = $false,
      HelpMessage = 'Primary DNS server IP address.')]
    [string]
    $PrimaryDNS,

    [Parameter(Mandatory)]
    [System.Management.Automation.PSCredential]
    $scvcredential,

    [Parameter(Mandatory)]
    [System.Management.Automation.PSCredential]
    $maintusercredential
  )
 
  BEGIN { 
  
    Write-DebugLog "In Begin block of cmdlet Install-NetAppCBSAppliance."

    $ApplianceVirtualMachine = $ApplianceVirtualMachine.Trim()
    
    $VmDatastore = $VmDatastore.Trim()
    $NetworkMapping = $NetworkMapping.Trim()
    $ApplianceNetworkName = $ApplianceNetworkName.Trim()
    
    if ($EsxiCluster -ne $null -and $EsxiCluster -ne '') {
      $EsxiCluster = $EsxiCluster.trim();
    }
  
    $newUserName = "NetAppSCDPAdmin"
    $newUserFirstName = "NetApp SCDP Administrator"
    $newUserLastName = "vsphere.local"
    $Domain = "VSPHERE.LOCAL"
    $vra_user = $Domain + "\" + $newUserName
    $SCDPRole = "NetApp SCDP Administrator"
    $CloudAdminsGroupName = "CloudAdmins"
    $VMFolderName = "NetApp-CBS"
    $tagName = "AVS_ANF_CLOUD_ADMIN_VM_TAG"
    $tagCategoryName = "AVS_ANF_CLOUD_ADMIN_VM_TAG_CATEGORY"

    $OVAName = "Cb-vm-1.0-240711_0707.ova"
    $DestinationPath = Get-Location
    #$DestinationPath = "$env:HOME"
    $EsxHost = "";
  }

  PROCESS {    
    Write-DebugLog -Message "Install-NetAppCBSAppliance execution is started."

    if ($AcceptNetAppEulaAggrement -ne $true) {
      write-error "You must accept the NetApp Eula Aggrement to install." -ErrorAction Stop
    } 
    
    $scvPasswd = $scvcredential.GetNetworkCredential().Password  
    if ($scvPasswd.length -lt 8) {
      write-error "Appliance password must be at least 8 characters." -ErrorAction Stop
    }
    
    $maintpassword = $maintusercredential.GetNetworkCredential().Password  
    if ($maintpassword.length -lt 8) {
      write-error "Maintenance user password must be at least 8 characters." -ErrorAction Stop
    }
    
    Invoke-PreflightNetAppCBSAVSCheck
    test-vc-address    

    if ($Dhcp -eq $true) {
      $ApplianceIPAddress = "";
      $Netmask = "";
      $Gateway = "";
      $PrimaryDNS = "";
    }  
  
    $newUserPassword = Get-Password
    $vcSecurePass = ($newUserPassword | ConvertTo-SecureString -AsPlainText -Force)
    $vcNewUserCred = New-Object System.Management.Automation.PSCredential ($newUserName, $vcSecurePass)

    try {
      $tagAssignment = Get-TagAssignment -Tag $tagName -Category $tagCategoryName -ErrorAction SilentlyContinue          
    }
    catch {
      if ($tagAssignment) { 
        Write-DebugLog "Inside catch block but tagAssignment is not empty"
        if ($tagAssignment.Entity.Name) {
          Write-DebugLog "Appliance name "$tagAssignment.Entity.Name | Out-String
        }
      }
      Write-DebugLog $_.exception.Message
    }
  
    if ($tagAssignment) {         
      
      Write-DebugLog "Tag Present"
      $VirtualMachine = $tagAssignment.Entity.Name  

      $CommandName = "Install-NetAppCBSAppliance"
      
      if ($Dhcp -eq $true) {
        $CommandName = "Install-NetAppCBSApplianceUsingDHCP"
      }

      if ($VirtualMachine) {
        write-error "Virtual machine appliance is already installed. Use cmdlet Invoke-UpgradeNetAppCBSAppliance to upgrade the virtual machine appliance." -ErrorAction Stop
      }
      else {
        Write-DebugLog "Empty entity"
      }
    }
    else {
      Write-DebugLog "Tag not found"
    }  
  
    $VMObject = Get-VM -Name $ApplianceVirtualMachine -ErrorAction SilentlyContinue -ErrorVariable CloudAdminVMError
  
    # Install when $CloudAdminVMError is not empty or $VMObject is empty
    if (($CloudAdminVMError -ne $null) -or ($null -eq $VMObject)) {
      if ($CloudAdminVMError) {
        Write-DebugLog -Message "CloudAdminVMError is not empty"
        Write-DebugLog -Message $CloudAdminVMError | Out-String
        if ($CloudAdminVMError.PSObject.Properties.Match('CategoryInfo').Count) {
          if ($CloudAdminVMError.CategoryInfo.Category -eq "ObjectNotFound") {
            Write-DebugLog -Message "VM not found : $CloudAdminVMError"
          }
          else {
            Write-DebugLog -Message "Unable to fetch details about $ApplianceVirtualMachine"
          }
        }      
      }
      if ($null -eq $VMObject) {
        Write-DebugLog -Message "VMObject is empty "
      }


      $EsxHost = get-esxihost -EsxiCluster $EsxiCluster   
        
      # Validate datastore
      Test-DataStore -VmDatastore $VmDatastore -FreeSapce 5

      if ($Dhcp -ne $true) {
        $isValidApplianceIPAddress = Test-IpAddress $ApplianceIPAddress

        if ($isValidApplianceIPAddress -eq $false) {
          Write-Error "Invalid Appliance IP Address." -ErrorAction Stop
        }
      }
 
      test-stale-plugin          
        
      try {        
        
        $BlobContent = Get-BlobContent -BlobName $OVAName -DestinationPath $DestinationPath -TotalBlobSizeInKB 2202009.6 -ErrorAction Stop
        Write-DebugLog -Message "OVA file downloaded."
      }
      catch {
        Write-DebugLog -Message  $_.exception | Out-String
        Write-Error -ErrorId  "INSTALL_OVA_DOWNLOAD_FAILED" -Message  "Download failed"
        Write-Error -ErrorId  "INSTALL_OVA_DOWNLOAD_FAILED" -Message  $_.exception.Message -ErrorAction Stop
        Throw $_.exception.Message
      }  

      Write-DebugLog -Message "Installing..."
      
      Write-DebugLog -Message "Creating appliance user."
      Add-SSOUser -Domain $Domain -vcUserCre $vcNewUserCred -FirstName $newUserFirstName -LastName $newUserLastName
      
      Write-DebugLog -Message "Adding user to the group."
      Add-SSOUserToSSOGroup -Domain $Domain -UserName $newUserName -CloudAdminsGroupName $CloudAdminsGroupName
      
      Write-DebugLog -Message "Adding user to the role."
      Add-Role -vra_user $vra_user -SCDPRole $SCDPRole
      
      $folder = [AVSSecureFolder]::GetOrCreate($VMFolderName)
      
      if ([string]::IsNullOrEmpty($folder)) { 
        write-error "Failed to create the folder." -ErrorAction Stop
      }
    
      Write-DebugLog -Message "Deploy-OVA -ApplianceVirtualMachine $ApplianceVirtualMachine -EsxHost $EsxHost -VmDatastore $VmDatastore -NetworkMapping $NetworkMapping -ApplianceNetworkName $ApplianceNetworkName -Dhcp -ApplianceIPAddress $ApplianceIPAddress -Netmask $Netmask -Gateway $Gateway -PrimaryDNS $PrimaryDNS -Domain $Domain -Folder $folder"
      
      Deploy-OVA -ApplianceVirtualMachine $ApplianceVirtualMachine -EsxHost $EsxHost -Cluster $EsxiCluster -VmDatastore $VmDatastore -NetworkMapping $NetworkMapping -ApplianceNetworkName $ApplianceNetworkName -Dhcp $Dhcp -ApplianceIPAddress $ApplianceIPAddress -Netmask $Netmask -Gateway $Gateway -PrimaryDNS $PrimaryDNS -Domain $Domain -scvCre $scvcredential -vcUserCredential $vcNewUserCred -OVAName "$DestinationPath/$OVAName" -maintusercredential $maintusercredential -Folder $folder

      $VMName = (Get-Folder -Name $VMFolderName -Location "AVS-vendor-folders" -Type "VM" | Get-VM).Name

      if ($VMName -eq $ApplianceVirtualMachine) {
        Write-DebugLog -Message "virtual machine created inside folder."
      }
      else {
        Write-DebugLog -Message "No virtual machine present inside folder."
      }
      
      Write-DebugLog -Message "Securing appliance started."
      [AVSSecureFolder]::Secure($folder)
      Write-DebugLog -Message "Securing appliance completed."

      Add-TagToVM -ApplianceVirtualMachine $ApplianceVirtualMachine
      
      Mount-VmwareTools -ApplianceVirtualMachine $ApplianceVirtualMachine

      Test-VMWareToolInstallStatus -ApplianceVirtualMachine $ApplianceVirtualMachine
      Wait-Tools -VM $ApplianceVirtualMachine -TimeoutSeconds 300 | Out-Null
      Write-DebugLog "Vmware Tools installed"
      Write-DebugLog "Waiting for OVA deployment to complete..."
      Start-Sleep 600

      Add-NetAppPrivilageToRole -SCDPRole $SCDPRole
      if ($Dhcp -eq $true) {
        Test-Configuration -ApplianceIPAddress "" -ApplianceVirtualMachine $ApplianceVirtualMachine
      }
      else {
        Test-Configuration -ApplianceIPAddress $ApplianceIPAddress -ApplianceVirtualMachine $ApplianceVirtualMachine
      }
      Write-DebugLog -Message "Deploy-OVA execution is completed."
      
      Clear-PasswordInOVFProperties -ApplianceVirtualMachine $ApplianceVirtualMachine
      Remove-File -FileName $OVAName -DestinationPath $DestinationPath
    }
    else {
      Write-DebugLog "CloudAdminVMError is empty"
      Write-DebugLog $VMObject | Out-String
      if ($VMObject -and ($VMObject.Name -eq $ApplianceVirtualMachine)) {
        Write-DebugLog -Message "VM with name $ApplianceVirtualMachine already present."
        Write-Error "Virtual Machine with name $ApplianceVirtualMachine already present." -ErrorAction Stop
      }
    }
  }
  end {
    Write-DebugLog -Message "Install-NetAppCBSAppliance execution is completed."
  }  
}

function  get-esxihost {
  param(
    [Parameter(Mandatory = $false)]
    $EsxiCluster
  )
  try {
    $cluster = $null
      
    if ($null -eq $EsxiCluster -or $EsxiCluster -eq "") {
      $cluster = Get-Cluster      
    }
    else {
      $cluster = Get-Cluster -Name $EsxiCluster
    }
  }
  catch {
       Write-Error -ErrorId  "NO_CLUSTER" -Message  $_.exception.Message -ErrorAction Stop
  }
       
  $EsxHost = ''
  if ($null -eq $cluster -or $cluster -eq '') {
    Write-Error -ErrorId  "NO_CLUSTER" -Message  "No ESXi cluster found on this vCenter." -ErrorAction Stop
  }
  else {
    $IsCountPropertyExist = $cluster.PSobject.Properties.Name.Contains("Count")
    Write-DebugLog -Message "Is count property existing : $IsCountPropertyExist"
       
    if ($IsCountPropertyExist -eq $true) {
       
      $TotalClusters = $cluster.Count
       
      for ($i = 0; $i -lt $TotalClusters; $i++) {
    
        $EsxiHostObject = Get-Cluster $cluster[$i] | Get-VMHost | Select-Object -first 1
        $clustername = $cluster[$i]
        Write-DebugLog $clustername
        if ($null -ne $EsxiHostObject -and $EsxiHostObject -ne '') {
          $EsxHost = $EsxiHostObject.Name
          Write-DebugLog -Message "The cluster '$clustername' have host a $EsxHost ."
          break
        }
        else {
          Write-DebugLog -Message "The cluster '$clustername' does not have a host."
          continue
        }
      }
       }
    else {
      $EsxiHostObject = Get-Cluster $cluster[0] | Get-VMHost | Select-Object -first 1
      $clustername = $cluster[0]
      $EsxHost = $EsxiHostObject.Name
      Write-DebugLog -Message "The cluster '$clustername' have host a $EsxHost ."
       }      
  }
  return $EsxHost
}

function test-stale-plugin {
  
  $scvExtension1 = "com.netapp.aegis"
  $scvExtension2 = "com.netapp.scv.client"
  $em = Get-View ExtensionManager
  $extensionList = $em.ExtensionList.Key
  if (($extensionList -contains $scvExtension1) -or (($extensionList -contains $scvExtension2))) {
    Write-Error "VCenter already has Cloud Backup Service plugin Installed." -ErrorAction Stop
  }
}

function test-vc-address {
  $vc_up = ping_vm $VC_ADDRESS 5
  if (!$vc_up) {
    Write-Error "vCenter IP adress $VC_ADDRESS is not pingable." -ErrorAction Stop
    return
  }
  else {
    Write-DebugLog -Message "vCenter IP adress $VC_ADDRESS is pingable."
  }
}
function Test-VMWareToolInstallStatus () {
     param(
    [Parameter(Mandatory = $true)]
    $ApplianceVirtualMachine
  )
  $Count = 20
  :verifyvmwaretoolsstatus For ($i = 0; $i -le $Count; $i++) {
    $VMGuestObject = Get-VMToolsStatus -ApplianceVirtualMachine $ApplianceVirtualMachine
    Write-DebugLog $VMGuestObject | Out-String
    $IsStatusPropertyExist = [bool]($VMGuestObject -match "Status")
    $IsGuestStatePropertyExist = [bool]($VMGuestObject -match "GuestState")
    if ($IsStatusPropertyExist -and $IsGuestStatePropertyExist) {
      if (($VMGuestObject.Status -eq "toolsOk") -and ($IsGuestStatePropertyExist -eq "Running")) {
        break 'verifyvmwaretoolsstatus'
      }
      else {
        Start-Sleep 60
      }
    }
  }
}

function ShowEULAText {
  $modulePath = Split-Path -Path (Get-Module -Name NetApp.SC-preview).Path
  $eulaFilePath = $modulePath + "/EULA.txt"
  foreach ($line in [System.IO.File]::ReadLines($eulaFilePath)) {
    Write-Host $line -ForegroundColor Yellow
  }
}

function Add-SSOUser () {

  [CmdletBinding()]
  param(
    [Parameter(Mandatory)]
    [string]$Domain,
    [Parameter(Mandatory)]
    [System.Management.Automation.PSCredential]$vcUserCre,
    [Parameter()]
    [string]$FirstName,
    [Parameter()]
    [string]$LastName
  )

  PROCESS {
    Write-DebugLog -Message "Add-SSOUser execution is started"
  
    $userName = $vcUserCre.UserName
    $vcPwd = $vcUserCre.GetNetworkCredential().Password
    Write-DebugLog -Message "Fetch user."
    $SCDPAdminObject = Get-SsoPersonUser -Domain $Domain -Name $userName
  
    if ($null -eq $SCDPAdminObject) {
      Write-DebugLog -Message "SCDPAdminObject empty"
      Write-DebugLog -Message "Calling New-SsoPersonUser to create new SSO user."
      New-SsoPersonUser -UserName $userName -Password $vcPwd -FirstName $FirstName -LastName $LastName -Description "NetApp CBS appliance user" | Out-Null
      Write-DebugLog -Message "User created"
    }
    else {  
      #Change NetAppSCDPAdmin password
      $vcSecurePass = ($vcPwd | ConvertTo-SecureString -AsPlainText -Force)
      $vcNewUserCred = New-Object System.Management.Automation.PSCredential ($userName, $vcSecurePass)
  
      Set-Password -vcUserCre $vcNewUserCred
      Write-DebugLog -Message "User $userName is present in domain $Domain "
    }
  }
  
  END {
    Write-DebugLog -Message "Add-SSOUser execution is completed"
  }  
}
 
function Add-SSOUserToSSOGroup () {

  [CmdletBinding()]
  param(
    [Parameter(Mandatory)]
    [string]$UserName,
    [Parameter(Mandatory)]
    [string]$CloudAdminsGroupName,
    [Parameter(Mandatory)]
    [string]$Domain
  )

  <#
      Vmware removes the user from the sso group once user is deleted (during uninstallation). We don't have to do that explicitly.
      This powercli api available to fetch the members of group.
      The error can occur during adding a user for many reasons. No unique error type to find out the error happened for the member is already present or for some other reason. So first time when it fails, ignore the error and remove the user from the group. Then try second time to add it. If it fails second time, the error could be something else so show the error. If first attempt failed because member is already present in group , then after removing it, second attempt should pass.
      In ideal case the first attempt should pass. But in case installation fails, and we try to re-install, the situation could arise where user will be part of member already. In that case we need to remove and add it again as we have no way to know if the user is already part of group or not.
   #>

      
  PROCESS {
    Write-DebugLog -Message "Add-SSOUserToSSOGroup execution is started"
  
    $CloudAdminsGroupObject = Get-SsoGroup -name $CloudAdminsGroupName -Domain $Domain
    
    if ($null -ne $CloudAdminsGroupObject) {
      Write-DebugLog -Message "CloudAdminsGroupObject not null"
      
     
      if ($CloudAdminsGroupObject) {
        Write-DebugLog -Message "SSO group found"
        Write-DebugLog -Message "Add user to the group"
        Add-UserToSsoGroup -User (Get-SsoPersonUser -Domain $Domain -Name $UserName) -TargetGroup (Get-SsoGroup -name $CloudAdminsGroupName -Domain $Domain) -ErrorAction SilentlyContinue -ErrorVariable AddUserToSsoGroupError
            
        if ($AddUserToSsoGroupError) {
          Write-DebugLog -Message "Error while adding user to group"
          $ErrorMessage = $AddUserToSsoGroupError.exception.message
          
          #Error message has user name in it. So replace with *** and display
          $TruncatedMessage = $ErrorMessage.Replace("NetAppSCDPAdmin@vsphere.local", "***")
          Write-DebugLog -Message $TruncatedMessage            
          Write-DebugLog -Message "Removing user from the group"                    
          Remove-UserFromSsoGroup -User (Get-SsoPersonUser -Domain $Domain -Name $UserName) -TargetGroup (Get-SsoGroup -name $CloudAdminsGroupName -Domain $Domain) -ErrorAction SilentlyContinue -ErrorVariable RemoveUserToSsoGroupError
          Write-DebugLog -Message "Adding user to the group"
          Add-UserToSsoGroup -User (Get-SsoPersonUser -Domain $Domain -Name $UserName) -TargetGroup (Get-SsoGroup -name $CloudAdminsGroupName -Domain $Domain) -ErrorAction Stop
          Write-DebugLog -Message "User is added to the group"
        }             
      }
      else {
        Write-Error -Message "The group not found" -ErrorAction Stop
      }
    }
    else {
      Write-Error -Message "The group not found" -ErrorAction Stop
    }
  }
  
  END {
    Write-DebugLog -Message "Add-SSOUserToSSOGroup execution is completed"
  }  
}

function Add-Role () {

  [CmdletBinding()]
  param(
    [Parameter(Mandatory)]
    [string]$vra_user,
    [Parameter(Mandatory)]
    [string]$SCDPRole
  )
  
  BEGIN {

    Write-DebugLog -Message "In begin block of Add-Role"
  
    $SCDPAdmin_Privileges = @(
      "System.Anonymous"
      "System.View"
      "System.Read"
      "Datastore.Config"
      "Datastore.Rename"
      "Datastore.Move"
      "Datastore.Delete"
      "Datastore.Browse"
      "Datastore.FileManagement"
      "Datastore.AllocateSpace"
      "Network.Assign"
      "Host.Config.Storage"
      "Host.Config.AdvancedConfig"
      "Host.Config.Resources"
      "Host.Config.Settings"
      "Host.Local.CreateVM"
      "Host.Local.ReconfigVM"
      "Host.Local.DeleteVM"
      "VirtualMachine.Inventory.Create"
      "VirtualMachine.Inventory.CreateFromExisting"
      "VirtualMachine.Inventory.Register"
      "VirtualMachine.Inventory.Delete"
      "VirtualMachine.Inventory.Unregister"
      "VirtualMachine.Inventory.Move"
      "VirtualMachine.Interact.PowerOn"
      "VirtualMachine.Interact.PowerOff"
      "VirtualMachine.GuestOperations.Query"
      "VirtualMachine.GuestOperations.Modify"
      "VirtualMachine.GuestOperations.Execute"
      "VirtualMachine.Config.AddExistingDisk"
      "VirtualMachine.Config.AddNewDisk"
      "VirtualMachine.Config.RemoveDisk"
      "VirtualMachine.Config.Resource"
      "VirtualMachine.Config.AdvancedConfig"
      "VirtualMachine.Config.ReloadFromPath"
      "VirtualMachine.State.CreateSnapshot"
      "VirtualMachine.State.RevertToSnapshot"
      "VirtualMachine.State.RemoveSnapshot"
      "Resource.AssignVMToPool"
      "Resource.ApplyRecommendation"
      "Resource.HotMigrate"
      "Resource.ColdMigrate"
      "Resource.QueryVMotion"
      "Task.Create"
      "Task.Update"
      "Extension.Register"
      "Extension.Update"
      "Extension.Unregister"
    )
  
  }
  
  PROCESS {
    
    Write-DebugLog -Message "Add-Role execution is started"

    Write-DebugLog -Message "Creating Role."

    $NewVIRole = New-VIRole -Name $SCDPRole -Privilege (Get-VIPrivilege -Id $SCDPAdmin_Privileges) -ErrorAction SilentlyContinue -ErrorVariable SCDPRoleError
    
    if ($SCDPRoleError) {
      Write-DebugLog -Message "SCDPRoleError is not empty"
      if ($SCDPRoleError.exception.GetType().Name -eq "DuplicateName") {
        Write-DebugLog -Message "A Role with same name already exists on server"
      }
      else {
        Write-Error Error-Id "install-create-role-failed" -Message "Could not create role."
        Write-DebugLog -Message $SCDPRoleError.exception | Out-String
      }
    }
  
    Write-DebugLog -Message "Assigning privilege."
    $rootFolder = Get-Folder -NoRecursion
    Write-DebugLog -Message "Calling Get-VIRole."
    $SCDPRoleObject = Get-VIRole -Name $SCDPRole
    Write-DebugLog -Message "Calling New-VIPermission." | Out-String
    New-VIPermission -entity $rootFolder -Principal $vra_user -Role $SCDPRoleObject -ErrorAction SilentlyContinue -ErrorVariable VIPermissionError | Out-Null
  }
  
  END {
    Write-DebugLog -Message "Add-Role execution is completed"
  }  
}


function Add-NetAppPrivilageToRole () {

  [CmdletBinding()]
  param(
    [Parameter(Mandatory)]
    [string]$SCDPRole
  )
  
  BEGIN {

    Write-DebugLog -Message "In begin block of Add-NetAppPrivilageToRole"
  
    $SCDPAdmin_NetAppPrivileges = @(
      "netappSCV.Backup.BackupScheduled"
      "netappSCV.Recovery.MountUnMount"
      "netappSCV.Guest.RestoreFile"
      "netappSCV.View"
      "netappSCV.Configure.ConfigureSnapCenterServer"
      "netappSCV.Recovery.RecoverVM"
      "netappSCV.Backup.DeleteBackupJob"
      "netappSCV.Configure.ConfigureStorageSystems.Delete"
      "netappSCV.Configure.ConfigureStorageSystems.AddUpdate"
      "netappSCV.Backup.BackupNow"
      "netappSCV.Guest.Configure"
    )  
  }
  
  PROCESS {
    
    Write-DebugLog -Message "Add-NetAppPrivilageToRole execution is started."

    Write-DebugLog -Message "Assigning privilage to the role."

    $ModifySCDPRole = Set-VIRole -Role (Get-VIRole -Name $SCDPRole) -AddPrivilege (Get-VIPrivilege -Id $SCDPAdmin_NetAppPrivileges) -ErrorAction SilentlyContinue -ErrorVariable ModifySCDPRoleError
  
    if ($ModifySCDPRoleError) {
      Write-DebugLog -Message "ModifySCDPRoleError is not empty"
      if ($ModifySCDPRoleError.exception) {
        Write-DebugLog -Message $ModifySCDPRoleError.exception.message | Out-String
      }
    }
  }
  
  END {
    Write-DebugLog -Message "Add-NetAppPrivilageToRole execution is completed."
  }  
}


function Add-TagToVM {
  param(
    [Parameter(Mandatory = $true)]
    $ApplianceVirtualMachine
  )

  BEGIN {
    Write-DebugLog -Message "In begin block of Add-TagToVM"

    $newTagName = "AVS_ANF_CLOUD_ADMIN_VM_TAG"
    $newTagDescription = "Tag to identify VMs created using AVS-ANF script "
    $newTagCategoryName = "AVS_ANF_CLOUD_ADMIN_VM_TAG_CATEGORY"
    $newTagCategoryDescription = "TagCategory for the tag CloudAdminVmTag"
  }

  PROCESS {

    Write-DebugLog -Message "Add-TagToVM execution is started"
    Write-DebugLog -Message "Inside Add-TagToVM " |  Out-String

    Try {
      #Assign Tag to VM
      $GetVMTag = Get-Tag -Name $newTagName -ErrorAction Stop
      Write-DebugLog -Message "Tag found"  | Out-String
      Get-VM $ApplianceVirtualMachine | New-TagAssignment -Tag $GetVMTag  | Out-Null 
      Write-DebugLog "Tag Assignment completed"
    }
    Catch {
      Try {
        $GetVMTagCat = Get-TagCategory -Name $newTagCategoryName -ErrorAction Stop
        Write-DebugLog "TagCategory found"
        New-Tag -Name $newTagName -Category $GetVMTagCat -Description $newTagDescription | Out-Null
      }
      Catch {
        Write-DebugLog "TagCategory with name CloudAdminVmTagCategory not found. Creat one"
        New-TagCategory -Name $newTagCategoryName -Description $newTagCategoryDescription | Out-Null
        Write-DebugLog "Now, let's create a new Tag under TagCategory:" $newTagCategoryName
        New-Tag -Name $newTagName -Category $newTagCategoryName -Description $newTagDescription | Out-Null
      }
      #Assign Tag to VM
      $GetVMTag = Get-Tag -Name $newTagName -ErrorAction Stop
       
      Get-VM -Name $ApplianceVirtualMachine | New-TagAssignment -Tag $GetVMTag   | Out-Null  
    
      Write-DebugLog -Message "Tag Assignment completed"
    }
  }

  END {
    Write-DebugLog -Message "Add-TagToVM execution is completed"
  }

}

function Deploy-OVA () {

  param(
    [Parameter(Mandatory)]
    [string]$ApplianceVirtualMachine,
    [Parameter(Mandatory)]
    [string]$Cluster,
    [Parameter(Mandatory)]
    [string]$EsxHost,
    [Parameter(Mandatory)]
    [string]$Folder,
    [Parameter(Mandatory)]
    [string]$VmDatastore,
    [Parameter(Mandatory)]
    [string]$NetworkMapping,
    [Parameter(Mandatory)]
    [string]$ApplianceNetworkName,
    [boolean]$Dhcp,
    [Parameter()]
    [string]$ApplianceIPAddress,
    [Parameter()]
    [string]$Netmask,
    [Parameter()]
    [string]$Gateway,
    [Parameter()]
    [string]$PrimaryDNS,
    [Parameter(Mandatory)]
    [string]$Domain,
    [Parameter(Mandatory)]
    [string]$OVAName,
    [Parameter(Mandatory)]
    [System.Management.Automation.PSCredential]$scvCre,
    [Parameter(Mandatory)]
    [System.Management.Automation.PSCredential]$vcUserCredential,
    [Parameter(Mandatory)]
    [System.Management.Automation.PSCredential]$maintusercredential    
  )

  PROCESS {    
 
    Write-DebugLog -Message "Deploy-OVA execution is started."

    $vcenterLogin = $vcUserCredential.UserName
    $vcPwd = $vcUserCredential.GetNetworkCredential().Password
    $scvLogin = $scvCre.UserName
    $scvPwd = $scvCre.GetNetworkCredential().Password
    $ovfConfig = Get-OvfConfiguration -Ovf $OVAName
    Write-DebugLog -Message "ovfConfig.NetworkMapping.nat.Value = $NetworkMapping"
    $ovfConfig.NetworkMapping.nat.Value = $NetworkMapping
    $ovfconfig.vplatform.Vendor_Provider_Appliance.auth.UserName.Value = $scvLogin
    $ovfconfig.vplatform.Vendor_Provider_Appliance.auth.passwd.Value = $scvPwd
    Write-DebugLog -Message "ovfconfig.vplatform.Vendor_Provider_Appliance.vcenter.register.ipAddress.Value = $VC_ADDRESS"
    $ovfconfig.vplatform.Vendor_Provider_Appliance.vcenter.register.ipAddress.Value = $VC_ADDRESS
    $ovfconfig.vplatform.Vendor_Provider_Appliance.vcenter.register.UserName.Value = "$vcenterLogin@$Domain"
    $ovfconfig.vplatform.Vendor_Provider_Appliance.vcenter.register.passwd.Value = $vcPwd
    Write-DebugLog -Message "ovfconfig.vplatform.Vendor_Provider_Appliance.hostName.Value = $ApplianceNetworkName"
    $ovfconfig.vplatform.Vendor_Provider_Appliance.hostName.Value = $ApplianceNetworkName
    $maintpassword = $maintusercredential.GetNetworkCredential().Password   
    $ovfconfig.vplatform.Vendor_Provider_Appliance.maint.passwd.Value = $maintpassword
    
    if ($Dhcp -eq $false) {
      Write-DebugLog -Message "ovfconfig.vplatform.Vendor_Provider_Appliance.ipAddress.Value = $ApplianceIPAddress"
      $ovfconfig.vplatform.Vendor_Provider_Appliance.ipAddress.Value = $ApplianceIPAddress
      Write-DebugLog -Message "ovfconfig.vplatform.Vendor_Provider_Appliance.netMask.Value = $Netmask"
      $ovfconfig.vplatform.Vendor_Provider_Appliance.netMask.Value = $Netmask
      Write-DebugLog -Message "ovfconfig.vplatform.Vendor_Provider_Appliance.gateway.Value = $Gateway"
      $ovfconfig.vplatform.Vendor_Provider_Appliance.gateway.Value = $Gateway
      Write-DebugLog -Message "ovfconfig.vplatform.Vendor_Provider_Appliance.primaryDNS.Value = $PrimaryDNS"
      $ovfconfig.vplatform.Vendor_Provider_Appliance.primaryDNS.Value = $PrimaryDNS
    }

    Write-DebugLog -Message "ovfconfig.vplatform.Vendor_Provider_Appliance.searchDomains.Value = $Domain"
    $ovfconfig.vplatform.Vendor_Provider_Appliance.searchDomains.Value = $Domain
    
    Write-DebugLog -Message "Source path: $OVAName"
    
    try {
      Write-DebugLog -Message "Import-VApp command execution started."
      Import-VApp -Source $OVAName -OvfConfiguration $ovfconfig -Name $ApplianceVirtualMachine -VMHost $EsxHost -Location $Cluster -InventoryLocation $Folder -Datastore $VmDatastore -DiskStorageFormat thin -Confirm:$false -ErrorAction Stop | Out-Null
    }
    catch {        
      Write-DebugLog -Message "Installation failed."
      Clear-PasswordInOVFProperties -ApplianceVirtualMachine $ApplianceVirtualMachine
      Write-Error -ErrorId "INSTALL-IMPORT-FAILED" -Message "Import failed during installation."
      Write-Error $_.exception.Message -ErrorAction Stop
      Throw $_.exception.Message
    }       
      
    Write-DebugLog "Deploying..."
    Start-Sleep 120
  }

  END {
    Write-DebugLog -Message "Deploy-OVA execution is completed."
  }
}

function Mount-VmwareTools {
  param(
    [Parameter(Mandatory = $true)]
    $ApplianceVirtualMachine
  )

  PROCESS {
    Write-DebugLog -Message "Mount VMware Tools execution is started."

    StopStartVMWareVM -ApplianceVirtualMachine  $ApplianceVirtualMachine
  
    Write-DebugLog "Waiting for Mount VMware tools to be ready for install..."
    Start-Sleep 100
      
    Write-DebugLog -Message "Initiate mount tools operation."
  
    try {
      Mount-Tools -VM $ApplianceVirtualMachine  -ErrorAction Stop
      Write-DebugLog "Waiting for Mount VMware Tools operations to be completed..."
    }
    catch {
      Write-DebugLog -Message  $_.exception | Out-String
      Write-Error -ErrorId "INSTALL-MOUNT-FAILED" -Message "Mount failed."
      Write-Error $_.exception.Message -ErrorAction Stop
    }
  }
  END {
    Write-DebugLog -Message "The operation mount VMware tools completed."
  }
}


function StopStartVMWareVM {
  param(
    [Parameter()]
    [string]
    $ApplianceVirtualMachine
  )
  Write-DebugLog -Message "Get-VM -Name $ApplianceVirtualMachine -ErrorAction SilentlyContinue -ErrorVariable SCDPRoleError"
  $VMObject = Get-VM -Name $ApplianceVirtualMachine -ErrorAction SilentlyContinue -ErrorVariable GetVMError

  if ($GetVMError) {
    Write-DebugLog $GetVMError | Out-String
  }

  if ($VMObject) {
    $VMPowerState = $VMObject.PowerState
    Write-DebugLog -Message "VMPowerState: $VMPowerState"
    if ($VMPowerState -ne "PoweredOn") {
      Write-DebugLog -Message "Starting the Virtual Machine ."
      Start-VM -VM $ApplianceVirtualMachine | Out-Null
      $Count = 10
      For ($i = 0; $i -le $Count; $i++) {
            
        $VMObject = Get-VM -Name $ApplianceVirtualMachine
        $VMPowerState = $VMObject.PowerState
        if ($VMPowerState -eq "PoweredOn") {
          break
        }
        else {
          Start-Sleep 10
        }
      }
      Write-DebugLog -Activity "The Virtual Machine has started. "
    }
    else {
      Write-DebugLog -Message "VM is already powered on."
    }
  }
}