

function Log
{
[CmdletBinding()]
param(
	[String] $Message,
	[ValidateSet('Info', 'Warning', 'Error', 'Debug', 'Success')]
	$Level = 'Info',
	[String] $Path = 'fichierLog.txt',
	[Switch] $Append = $true,
	[Switch] $DisplayOnTerminal = $true,
  [Int32] $Indentation=1
	
)

	$null = Get-Variable -Name 'LogPath' -ErrorAction SilentlyContinue
	if ($?){
		$Path = $global:LogPath
	}else{
		$global:LogPath = $Path
	}
	
	$logMessage = "{0}`t{1}{2}{3}" -f ((Get-Date), $Level, ((&{$t="" ; (0..$Indentation) | % { $t+="`t"} ; $t})), $Message)
	 
		switch ($Level){
			'Info' {
          if ($DisplayOnTerminal){Write-Host $logMessage }
					$logMessage | Out-File -Append:$Append -FilePath $Path
					break}
			'Warning' {
          if ($DisplayOnTerminal){Write-Warning $logMessage}
					$logMessage | Out-File -Append:$Append -FilePath $Path
					break}
			'Error' {
          if ($DisplayOnTerminal){Write-Error $logMessage}
					$logMessage | Out-File -Append:$Append -FilePath $Path
					break}
			'Debug' {
          if ($DisplayOnTerminal){Write-Debug $logMessage}
					if ($DebugPreference -ne 'SilentlyContinue'){
						$logMessage | Out-File -Append:$Append -FilePath $Path
					}
					break}
			'Success' {
          if ($DisplayOnTerminal){Write-Host $logMessage -ForegroundColor Green}
					$logMessage | Out-File -Append:$Append -FilePath $Path
					break}
		}
	
}


function Boolean-ToInt($text)
{
  if ($text -eq 'true'){
      return 1
  }elseif ($text -eq 'false'){
      return 0
  }else{
      return $text
  }
}


function Boolean-ToString($text)
{
    if ($text -eq $true){
        return '$true'
    }elseif ($text -eq $false){
        return '$false'
    }else{
        return $text
    }
}


function Set-LocationScriptPath()
{
    Set-Location (Get-Item ($MyInvocation.ScriptName)).Directory.FullName
}


function Get-ScriptBaseName()
{
    return (Get-Item ($MyInvocation.ScriptName)).BaseName
}


#REGION 3

function Get-LunFromIqn{
param(
	[Parameter(Mandatory=$true,ValueFromPipeline = $true)]
	[String] $iqn,
	[Parameter(Mandatory = $true)]
	$lun,
	[VMware.VimAutomation.Types.InventoryItem []] $Entity=(Get-VMHost)
	)

process{
	$hash = @{}
	$luns = ($Entity | Get-ScsiLun -LunType disk)
	$luns | %{
		$oLun = $_
		$linfo = Get-ScsiLunPath -ScsiLun $oLun
		if ($linfo.SanID -eq $iqn){$hash[$oLun.CanonicalName] = $oLun}
	}
	$hash.Values | % {
		$oLun = $_
		$lunNumber = $null
		if ($oLun.RuntimeName -match ":L($lun)$") { 
			$lunNumber = $Matches[1]
			$oLun | Add-Member -MemberType NoteProperty -Name LunNumber `
                                -Value $lunNumber
			return $oLun
		}
	}
	}
}


function Import-StorageCsv
{
param(
  [Parameter(Mandatory = $true)]
  [string] $Path,
  [string] $Delimiter=';',
  [Parameter(Mandatory = $true)]
  [VMware.VimAutomation.Types.VMHost []] $VMHost,
  [Boolean] $Confirm=$false
)

  Import-Csv -Path $Path -Delimiter $Delimiter | % {
  	$line = $_
  	switch ($line.Type){
			("NFS"){                
				$null = Get-VMHost $VMHost | % {
                    Get-Datastore -Name ("NFS_" + $line.server + "_" + $line.id.Split("/")[-1] + "_" + $line.env) -RelatedObject $_ -ErrorAction SilentlyContinue
                    if (-not $?){
                        Write-Host "=> Création du datastore NFS '$($line.server)' '$($line.id)' sur '$($_.Name)'"    
                        $null = New-Datastore -Name ("NFS_" + $line.server + "_" + $line.id.Split("/")[-1] + "_" + $line.env) `
										-Nfs `
							  			-NfsHost $line.identifiant `
										-Path $line.id `
                                        -VMHost $_ `
										-Confirm:$Confirm
                    }
                }
				break}
			("iSCSI"){
                $null = Get-Datastore -Name ("iSC_{0}_{1:000}_{2}" -f ($line.server, [int]$line.id, $line.env)) -ErrorAction SilentlyContinue
                if ($?){break}

                $lun = Get-LunFromIqn -iqn $line.identifiant `
                                      -lun $line.id `
                                      -Entity (Get-VMHost $VMHost | Select-Object -First 1)
                
                Write-Host "=> Création du datastore iSCSI '$($line.server)' '$($line.id)'"
				$null = New-Datastore -Vmfs -Name ("iSC_{0}_{1:000}_{2}" -f ($line.server, [int]$line.id, $line.env)) `
                              -Path $lun.CanonicalName `
							  -Confirm:$Confirm `
							  -VMHost ($VMHost | Select-Object -First 1)
                              
				break}
			("FC"){
                $null = Get-Datastore -Name ("FC_{0}_{0:000}_{2}" -f ($line.server, [int]$line.id, $line.env)) -ErrorAction SilentlyContinue
                if ($?){break}
				
                Write-Host "=> Création du datastore FC '$($line.server)' '$($line.id)'"
                Get-VMHost $VMHost | Select-Object -First 1 | New-Datastore -Vmfs `
										-Name ("FC_{0}_{0:000}_{2}" -f ($line.server, [int]$line.id, $line.env)) `
							  			-Path $line.identifiant `
							  			-Confirm:$Confirm
				break}
		}
       Start-Sleep -Seconds 5	
  }
}


function Set-PortGroupTrafficShapingPolicy
(
	[Parameter(Mandatory = $true)]
	[String] $HostName,
	[Parameter(Mandatory = $true)]
	[String] $PorGroupName,
	[Parameter(Mandatory = $true)]
	[String] $SwitchName,
	[Boolean] $Enabled=$false,
	[int64] $AverageBandwidth=100000000,
	[int64] $PeakBandwidth=100000000,
	[int64] $BurstSize=104857600
)
{
	$vmHost = Get-View -ViewType HostSystem -Filter @{"Name" = $HostName}
	$networkSystem = Get-View -Id $vmHost.ConfigManager.NetworkSystem

	$pgSpec = New-Object VMware.Vim.HostPortGroupSpec
	$pgSpec.Name = 			$PorGroupName
	$pgSpec.VswitchName =	$SwitchName
	$NetworkPolicy = New-Object VMware.Vim.HostNetworkPolicy

	$NetworkTrafficShapingPolicy = New-Object `
                    VMware.Vim.HostNetworkTrafficShapingPolicy
	$NetworkTrafficShapingPolicy.Enabled = 				$Enabled
	$NetworkTrafficShapingPolicy.AverageBandwidth = 	$AverageBandwidth
	$NetworkTrafficShapingPolicy.PeakBandwidth = 		$PeakBandwidth
	$NetworkTrafficShapingPolicy.BurstSize = 			$BurstSize
		
	$NetworkPolicy.ShapingPolicy = $NetworkTrafficShapingPolicy
	$pgSpec.Policy = $NetworkPolicy

	$networkSystem.UpdatePortGroup($PorGroupName, $pgSpec)
}


function New-VirtualDistributedSwitch
{
param(

	[String] $Name,
	[String] $Version='5.5.0',
	[vmware.VimAutomation.Types.VIContainer] $Location,
	[int] $NumUplink,
	[Hashtable] $vdPortGroup,
	[vmware.VimAutomation.Types.VMHost []] $VMHost,
	[String []] $NetworkAdapter
)

	# création du switch
	$vdSwitch = New-VDSwitch -Name $Name -Version $Version `
			-Location $Location `
            -NumUplinkPorts $NumUplink
	
	# création des groupes de ports
	$vdPortGroup.Keys | % {
		$nomVdPg = $_
		$vdPG = New-VDPortgroup -Name $nomVdPg -VDSwitch $vdSwitch
		
        if ($vdPortGroup[$nomVdPg].ContainsKey('SecurityPolicy')){
            $arguments = ''
            $vdPortGroup[$nomVdPg].SecurityPolicy.Keys | % {
                $arguments += '-' + $_ + ':'  + `
                      (Boolean-ToString `
                                $vdPortGroup[$nomVdPg].SecurityPolicy[$_]) `
                      + ' '
			}		
			$cmd = "Get-VDSecurityPolicy -VDPortgroup '$nomVdPg' | `
                        Set-VDSecurityPolicy $arguments"

            $null = Invoke-Expression -Command $cmd
        }

         if ($vdPortGroup[$nomVdPg].ContainsKey('VlanConfiguration')){
            $arguments = ''
            $vdPortGroup[$nomVdPg].VlanConfiguration.Keys | % {
                $arguments += '-' + $_ + ':'  + `
                            (Boolean-ToString `
							$vdPortGroup[$nomVdPg].VlanConfiguration[$_]) + ' '
			}		
			$cmd = "Set-VDVlanConfiguration -VDPortgroup '$nomVdPg' $arguments"

            $null = Invoke-Expression -Command $cmd
        }
	}
 
    # Ajout des hôtes
    $null = Add-VDSwitchVMHost -VDSwitch $vdSwitch -VMHost $VMHost

    # Configuration des cartes réseau
    $null = Add-VDSwitchPhysicalNetworkAdapter `
	    -DistributedSwitch $vdSwitch `
	    -VMHostPhysicalNic  (`
			    Get-VMHostNetworkAdapter -Name $NetworkAdapter `
				                         -VMHost $VMHost) `
	    -Confirm:$false

}


#ENDREGION 3

#REGION 4

function New-FolderFromPath
{
Param(
  [parameter (Mandatory=$true, `
      ValueFromPipeline=$true, `
      ParameterSetName="file")]
  [String[]] $Path,
  [parameter(Mandatory=$true, ` 
      ValueFrompipelineByPropertyName=$true, 
      ParameterSetName="filesystem")]
  [String] $FullName = '',
  [String] $Root = '',
  [String] $Separator = '\'
  )
	
process{
    if ($FullName -ne ''){ $chemin = $FullName}else{$chemin = $Path}

	  if ($Root -ne '') {$chemin = $chemin.Substring(`
                      ((Get-Item $Root).FullName).Length + 1)}
      if ($chemin -match "\\"){
        $splittedPaths = $chemin.Split($Separator)
      }else{
        $splittedPaths = @($chemin)
      }

      $location = Get-Folder $splittedPaths[0] -ErrorAction Ignore

      if ($location -eq $null){
        Write-Warning "racine de l'arborescence non trouvée, sortie"
        return
      }

      $splittedPaths[1..$splittedPaths.Length] | % {
        $nouveauDossier = Get-Folder -Name $_ -Location $location `
        -NoRecursion `
        -ErrorAction Ignore
        
        if($nouveauDossier -eq $null) { 
            Write-Verbose "Création du répertoire $_"
            $nouveauDossier = New-Folder -Name $_ -Location $location
        }else{
            Write-Warning "Le dossier $_ existe déjà"
        }
        $location = $nouveauDossier
      }
   }
}


function Get-FolderFromPath
{
param(
    [String] $Path
)
    $morceaux = $Path.Split('\')
    $racine = Get-View -VIObject (Get-Folder -Name $morceaux[0])
    if (-not $?){return}
 
    $morceaux[1..$morceaux.Count] | % {
        $morceau = $_
        $child = $racine.ChildEntity | ? {$_.Type -eq 'Folder'} | `
                ? { (Get-Folder -id ("{0}-{1}" `
                -f ($_.Type, $_.Value))).Name -eq $morceau}
        if ($child -eq $null) { throw "Dossier '$morceau' non trouvé"}
        $racine = Get-View -VIObject `
                (Get-Folder -Id ("{0}-{1}" -f ($child.Type, $child.Value)))
        if (-not $?){return}
    }

    return (Get-Folder -Id ("{0}-{1}" `
              -f ($racine.MoRef.Type, $racine.MoRef.Value)))
}


function Get-BestHost
{
[CmdletBinding(DefaultParameterSetName='Memory')]
param(
  [String] $Filter = '.',
  [VMware.VimAutomation.Types.VMHost []] $VMHost=(Get-VMHost),
  [Parameter(ParameterSetName = "Cpu", Mandatory = $false)]
  [Switch] $Cpu,
  [Parameter(ParameterSetName = "Memory", Mandatory = $false)]
  [Switch] $Mem,
  [VMware.VimAutomation.Types.VMHost] $Exclude=$null
)
  
	$MemoryUsageMB	= $VMHost[0].MemoryUsageMB
  $CpuUsageMhz = $VMHost[0].CpuUsageMhz
	$BestHost		= $VMHost[0]

  $VMHost | ? {$_ -ne $Exclude} | `
            ? {$_.ConnectionState -eq 'Connected'} | % { 
    if ($_.Name -match $Filter){
      if ($Mem.IsPresent -or (-not $Cpu.IsPresent)){
        if ($_.MemoryUsageMB -lt $MemoryUsageMB){
          $MemoryUsageMB	= $_.MemoryUsageMB			
          $BestHost		= $_
        }
      }

      if ($Cpu.IsPresent){
        if ($_.CpuUsageMhz -lt $CpuUsageMhz){
          $CpuUsageMhz = $_.CpuUsageMhz
          $BestHost		= $_
        }
      }
		} 
	}
	return $BestHost
}


function Get-LocalDatastore
{
  $localDatastores = @()
  $vmHost = (Get-VMHost  | ? {$_.ConnectionState -eq 'Connected'})
  Get-Datastore | ? {$_.ExtensionData.Info -isnot [VMware.Vim.NasDatastoreInfo]} | %{ 
    $datastore = $_
    $canonicalName = $datastore.ExtensionData.Info.Vmfs.Extent[0].DiskName
    $ds = Get-ScsiLun -CanonicalName $canonicalName -VmHost $vmHost | Select-Object -First 1
    if ($ds.isLocal){$localDatastores += $datastore}
  }
  $localDatastores
}


function Get-BestDatastore
{
param(
  [String] $Filter = '.',
  $Datastore=$null
)
  if ($Datastore -eq $null){
    $locDS = Get-LocalDatastore
    $Datastore = Get-Datastore | ? {$locDS -NotContains $_}
  }

	$maxFreeSpace 	= 0
	$BestDatastore = $Datastore[0]

	$Datastore | % { 
		if ($_.FreeSpaceMB -gt $maxFreeSpace){			
			if ($_.Name -match $Filter){
				$maxFreeSpace 	= $_.FreeSpaceMB
				$BestDatastore	= $_
			}
		} 
	}
	return $BestDatastore
}


function New-VmFromCsv
{
param(
  [parameter (Mandatory=$true, ParameterSetName="file")]
  [String] $CsvPath,
  [String] $Delimiter=';',
  [String] $Encoding='UTF8',
  [parameter (Mandatory=$true, ParameterSetName="csv")]
  $Csv
)
     
  if ($Csv -eq $null) {
    $Csv = Import-Csv -Path $CsvPath `
                      -Delimiter $Delimiter `
                      -Encoding $Encoding
  }

  $Csv | % {   
    $row = $_
    $arguments = ''
    $row | Get-Member -MemberType NoteProperty | `
           Select-Object -Property Name ` | % {
      if ($row.($_.Name) -ne ''){
        $valeur = ($row.($_.Name)).Replace("`n", ' ')
        $valeur = Boolean-ToInt $valeur
        if ($valeur -match ' ' -and (-not $valeur.StartsWith('('))){
          $valeur = '"' + $valeur + '"'
        }
        $arguments += " -{0}:{1}" -f ($_.Name, $valeur)
      }
    }

    $cmd = 'New-VM ' + $arguments
    $cmd
    
    $null = Invoke-Expression -Command $cmd
  }
}


function New-VmFromXml
{
param(
  [parameter (Mandatory=$true, ParameterSetName="file")]
  [String] $XmlPath,
  [parameter (Mandatory=$true, ParameterSetName="xml")]
  [Xml] $Xml
)

  if ($Xml -eq $null){
    $Xml = [Xml] (Get-Content $XmlPath)
  }

  $vms = @()
  if ($Xml.vm.vms.range -ne $null){
    Invoke-Expression $Xml.vm.vms.range | % {
      $vms += $Xml.vm.vms.Name -f $_
    }
  }else{
    $vms = $Xml.vm.Name
    $arguments = ''
  }

  $vms | % {
    $cmd = "New-VM " 
    if ($arguments -ne ''){  $arguments = "-Name '$_' " }
    $attributes = $Xml.vm.Attributes
    for ($i=0;$i -lt $attributes.Count;$i++){
      if ($attributes[$i].'#text' -ne ''){
          $arguments += '-' + $attributes[$i].name + ':'  + `
                        (Boolean-ToInt $attributes[$i].'#text') + ' '
      }
    }	

    if ($Xml.vm.Notes -ne $null){ $arguments += " -Notes '$($Xml.vm.Notes)'" }

    $cmd += $arguments
    $cmd

    $vm = Invoke-Expression -Command $cmd

    Get-HardDisk -VM $vm | Remove-HardDisk -Confirm:$false

    $xml.vm.Disks.Disk | % {
      $arguments = ''    
      $attributes = $_.Attributes
      for ($i=0;$i -lt $attributes.Count;$i++){
        if ($attributes[$i].'#text' -ne ''){
          $arguments += '-' + $attributes[$i].name + ':'  + `
                        (Boolean-ToInt $attributes[$i].'#text') + ' '
        }
      }
      
      $cmd = "New-HardDisk -VM:'$vm' $arguments" 
      $cmd
      $null = Invoke-Expression -Command $cmd
    }
  }
}


function Get-VMFromFolder
{
param(
  [Parameter(Mandatory=$true)]
  [String] $FolderPath,
  [Switch] $Recurse
)  
    
  $view = Get-View -VIObject (Get-FolderFromPath $FolderPath)
  $view.ChildEntity | `
  ? {$_.Type -eq 'VirtualMachine'} | `
  % {Get-VM -Id "$($_.Type)-$($_.Value)"}

  if ($Recurse.isPresent){
    $view.ChildEntity | `
    ? {$_.Type -eq 'Folder'} | `
    % { Get-VMFromFolder ($FolderPath + '\' + `
            (Get-Folder -id "$($_.Type)-$($_.Value)").Name)}
  }
}


function Get-VMFromRessourcePool
{
param(
  [Parameter(Mandatory=$true)]
  $RessourcePool
)  
  (Get-View -VIObject $RessourcePool).Vm | `
  ? {$_.Type -eq 'VirtualMachine'} | `
  % {Get-VM -Id "$($_.Type)-$($_.Value)"}
}


function Deploy-VM
{
param(
  [Parameter(Mandatory=$true)]
  [String] $Name,
  [Parameter(Mandatory=$true)]
  $Source,
  [Parameter(Mandatory=$true)]
  $OSCustomizationSpec,
  $ResourcePool=(Get-Cluster),
  $Location='vm',
  $Datastore=(Get-BestDatastore),
  $Notes=''
)
  $typeSource = ''

  if ($Source.GetType().Name -eq 'String'){
    if ((Get-Template $Source -ErrorAction SilentlyContinue) -ne $null){
      $typeSource = '-Template'
    }
    if ((Get-VM $Source -ErrorAction SilentlyContinue) -ne $null){
      $typeSource = '-VM'
    }
  }else{
      if ($Source.GetType().Name -eq 'VirtualMachineImpl' ){
        $typeSource = '-VM'
      }elseif ($Source.GetType().Name -eq 'TemplateImpl' ){
        $typeSource = '-Template'
      }
  }

  if ($typeSource -eq ''){throw "Type de source inconnue '$Source', sortie"}

$cmd = @"
New-VM -Name `"$Name`" ``
$typeSource `"$Source`" ``
-OSCustomizationSpec `"$OSCustomizationSpec`" ``
-ResourcePool `"$ResourcePool`" ``
-Location `"$Location`" ``
-Datastore `"$Datastore`" ``
-Notes `"$Notes`"
"@

  $vm = Invoke-Expression -Command $cmd
          
  $null = Start-VM $vm

  # boucle pour attendre l'application des paramètres
  $configurationTermine = $false
  $phase = 0
  $start = Get-Date
  $timeout = 10*60
  $cptStatu = 0
  $maxCptStatu = 5

  while (-not $configurationTermine)
  {
    $vm.ExtensionData.UpdateViewData()
    $etatVmTools = $vm.ExtensionData.Guest.ToolsRunningStatus

    if (((Get-Date) - $start).TotalSeconds -gt $timeout){break}

    if ($etatVmTools -eq 'guestToolsRunning'){$cptStatu++}
    if ($cptStatu -gt $maxCptStatu){$configurationTermine = $true}
    
    Start-Sleep -Seconds 1   
  }

  $null = Shutdown-VMGuest $vm -Confirm:$false -ErrorAction SilentlyContinue

  return $vm
}


function Set-vAppVmConfig
{
Param(
    [Parameter(Mandatory=$true,ValueFromPipeline=$True)]
    [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl] $VM,   
    [int] $StartOrder,
    [int] $StartDelay,
    [bool] $WaitingForGuest,
    [ValidateSet("none","powerOn")]
    [string] $StartAction,
    [int] $StopDelay,
    [ValidateSet('none','powerOff','guestShutdown','suspend')]
    [string] $StopAction,
    [bool] $DestroyWithParent
  )
  process 
  {

    $vApp = Get-VIObjectByVIView $vm.ExtensionData.ParentVApp
    if (-not $?){
        throw "La machine $vm ne fait pas partie de la vApp"
    }
    
    $EntityConfig = $vApp.ExtensionData.VAppConfig.EntityConfig
    
    $spec = New-Object VMware.Vim.VAppConfigSpec

    $spec.EntityConfig = $EntityConfig

    $VmConf = $spec.EntityConfig | `
                ? { $_.Key.ToString() -eq $VM.ID.ToString()}

    $PSCmdlet.MyInvocation.BoundParameters.keys | % {
        if (($VmConf | gm -MemberType Property | ? Name -eq $_) -ne $null){
            $VmConf.$_ = $PSCmdlet.MyInvocation.BoundParameters.$_
        }
    }
    
    $vApp.ExtensionData.UpdateVAppConfig($spec)
  }
}


#ENDREGION 4

#REGION 5

function Get-VIPrivilegeAsHash
{
 param(
  [String] $Prefix='_'
 )
  $h = @{}

  Get-VIPrivilege | % {
    $privilege = $_
    $t = $h
    $m = $privilege.Id.Split('.')
    $dernier = $m[-1]

    $m |% {
      if (-not $t.ContainsKey("$Prefix$_")){
        if ($_ -eq $dernier){
          $t["$Prefix$_"] = Get-VIPrivilege -Id $privilege.Id
        }else{
          $t["$Prefix$_"] = @{}   

          $t = $t["$Prefix$_"]
          Add-Member -InputObject $t `
                     -MemberType ScriptProperty `
                     -Name All `
                     -Value { 
            $this.Values | ? { $_.GetType().Name -ne 'Hashtable'}
            $this.Values | ? { $_.GetType().Name -eq 'Hashtable'} | `
                                    % {$_.All}
                            }
        }
      }else{ 
        $t = $t["$Prefix$_"]
      }
    }
  }

  Add-Member -InputObject $h -MemberType ScriptProperty -Name All -Value { 
    $this.Keys | % { $this[$_].All }
  }
  
  return $h
}


function Export-VIRole
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  $Role,
  [String] $Destination
)
process{
  
  if ($Role.Gettype().Name -eq 'String'){
    $FichierRole = $Role
  }else{
    $FichierRole = $Role.Name
  }
  
  ('\', '/', ':', '*', '?', '<', '>', '|') | `
          % {$FichierRole = $FichierRole.Replace($_, '_')}
  if ($Destination -eq ''){
    $File = "$PWD\$FichierRole.txt"
  }else{
    $f = Get-Item $Destination -ErrorAction SilentlyContinue
    if (-not $?){
      $null = New-Item -Path $Destination -Type Directory `
                       -ErrorAction SilentlyContinue
      if ($?){
        $File = "$Destination\$FichierRole.txt"
      }else{
        throw "Chemin non trouvé $Destination"
      }
    }else{
      if ($f.GetType().Name -eq 'DirectoryInfo'){ 
        $File = "$f\$FichierRole.txt"
      } elseif ($f.GetType().Name -eq 'FileInfo'){ 
        $File = "$($f.DirectoryName)\$FichierRole.txt"
      }
    }
  }
  
  if (Test-Path $File){Remove-Item $File}
  
  (Get-VIRole -Name $Role).PrivilegeList | Out-File -FilePath $File -Append
  }
}


function Import-VIRole
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  $File,
  [String] $Name
)
process{
  $pipeline = $false
  
  if ($_){$pipeline = $true}
  
  if ($File.GetType().Name -eq 'FileInfo'){
    $fic = $File
  }elseif ($File.GetType().Name -eq 'String'){
    if ( -not (Test-Path $File)){throw "Fichier $File non trouvé"}
    $fic = Get-Item -Path $File
  }else{
    throw "Type en entrée inconnu '$File'"
  }  

  $privileges = @()
  Get-Content $fic.FullName | % {
      $privilege = $_
      $privileges += Get-VIPrivilege -Id $privilege `
                                     -ErrorAction SilentlyContinue
      if (-not $?){Write-Warning "Privilege $privilege non trouvé"}
  }
  
  if (($Name -eq '') -or $pipeline){$Name = $fic.BaseName}
  
  New-VIRole -Name $Name -Privilege $privileges
  if ($pipeline){$name = ''}
  }
}


function New-VIPermissionPortGroup
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  $PortGroup,
  [Parameter(Mandatory=$true)]
  $Principal,
  [Parameter(Mandatory=$true)]
  $Role
)
process{
  $group = $false

  $o = [ADSI]"WinNT://$($Principal.Replace('\', '/'))"
  if ($o.SchemaClassName -eq 'Group'){$group = $true}

  $oRole = Get-VIRole -Name $Role

  $netView = Get-View -ViewType Network -Filter @{"Name" = $PortGroup}
  $authMgr  = Get-View AuthorizationManager
  $perm     = New-Object VMware.Vim.Permission
  $perm.Principal = $Principal
  $perm.RoleId    = $oRole.Id
  $perm.Propagate = $false
  $perm.Group     = $group
  $authMgr.SetEntityPermissions($netView.moref, $perm)
  }
}


function Export-VIPermissionFolder
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  [VMware.VimAutomation.Types.Folder] $Folder,
  [String] $Destination
)
process{
    
  if (-not (Test-Path $Destination)){
    $null = New-Item -Path $Destination -ItemType Directory
  }
  
  $location = Get-PathFromFolder $Folder
  $xmlContent = "<?xml version='1.0' encoding='UTF-8'?>"
  $xmlContent += "<permissions entity='$Folder' "
  $xmlContent += "type='$($Folder.Gettype().Name)' "
  $xmlContent += "location='$location'"
  $xmlContent += "></permissions>"
  
  $xml = [Xml] $xmlContent

  Get-VIPermission -Entity $Folder | % {
    $perm = $xml.CreateElement('permission')
    $perm.SetAttribute('Role', $_.Role)
    $perm.SetAttribute('Principal', $_.Principal)
    $perm.SetAttribute('Propagate', $_.Propagate)
    $perm.SetAttribute('IsGroup', $_.IsGroup)
    $null = $xml.GetElementsByTagName('permissions').AppendChild($perm)
  }
  
  $xml.Save("{0}\{1}.perm.xml" `
                        -f ($Destination, $location.Replace('\', '_')))
  
  }
}


function Import-VIPermissionFolder
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  $XmlPath
)
process{
  $pipeline = $false
  
  if ($_){$pipeline = $true}
  
  if ($XmlPath.GetType().Name -eq 'FileInfo'){
    $fic = $XmlPath
  }elseif ($XmlPath.GetType().Name -eq 'String'){
    if ( -not (Test-Path $XmlPath)){throw "Fichier $File non trouvé"}
    $fic = Get-Item -Path $XmlPath
  }else{
    throw "Type en entrée inconnu '$File'"
  }  
  $xml = [Xml] (Get-Content $fic.FullName)

  try{
    $Folder = Get-FolderFromPath $xml.permissions.location
  }catch{
    $Folder = New-FolderFromPath $xml.permissions.location
  }

  $xml.permissions.permission |% {
    if ($_.Principal -ne 'root'){
        New-VIPermission -Role $_.Role `
                         -Principal $_.Principal `
                         -Entity $Folder `
                         -Propagate:(Boolean-ToInt $_.Propagate)
    }
  }

  }
}


function Check-AdvancedSetting
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  [VMware.VimAutomation.Types.InventoryItem] $Entity,
  [Parameter(Mandatory=$true)]
  [String] $Name,
  $Value
)

process{

  $adv = Get-AdvancedSetting -Entity $Entity -Name $Name

  if ($adv.Value -eq $Value){
      $Entity | Add-Member -MemberType NoteProperty Conformity $true
  }else{
      $Entity | Add-Member -MemberType NoteProperty Conformity $false
  }

  $Entity | Add-Member -MemberType NoteProperty Value $adv.Value

  $defaultDisplaySet = 'Name', 'Conformity', 'Value'
  $Entity.PSObject.TypeNames.Clear()
  $Entity.PSObject.TypeNames.Insert(0, 'AdvCheck')
  
  $defaultDisplayPropertySet = New-Object `
  System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet', `
                                              [string[]]$defaultDisplaySet)
  
  $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]] `
                          @($defaultDisplayPropertySet)
  $Entity | Add-Member MemberSet PSStandardMembers $PSStandardMembers

  $Entity

  }    
}

function Update-AdvancedSetting
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  [VMware.VimAutomation.Types.InventoryItem] $Entity,
  [Parameter(Mandatory=$true)]
  [String] $Name,
  [Parameter(Mandatory=$true)]
  $Value,
  [Parameter(Mandatory=$true)]
  [ValidateSet('ClusterHA', `
               'VM', `
               'ClusterDRS', `
               'VMHost', `
               'DatastoreClusterSdrs', `
               'VIServer ')]
  $Type,
  $Confirm=$true
)

process{

  $adv = Get-AdvancedSetting -Entity $Entity -Name $Name

  if ($adv.Value -eq $null){
    New-AdvancedSetting -Name $Name `
                        -Value $Value `
                        -Entity $Entity `
                        -Type $Type `
                        -Confirm:$Confirm
  }else{
    Set-AdvancedSetting -AdvancedSetting $adv `
                        -Value $Value `
                        -Confirm:$Confirm
  }

  }    
}


function Export-Inventory
{
param(
  [String] $Destination,
  [int] $Depth=3
)
  $null = New-Item -Path $Destination -ItemType Directory -ErrorAction SilentlyContinue
  Get-Cluster | Export-Clixml "$Destination\Clusters.xml" -Depth $Depth
  Get-Cluster | Get-VMHost | `
            Export-Clixml "$Destination\VMHosts.xml" -Depth 7
  Get-Datastore | Export-Clixml "$Destination\Datastores.xml" -Depth $Depth
  Get-VirtualSwitch -Standard | `
            Export-Clixml "$Destination\VirtualSwitches.xml" -Depth $Depth
  Get-VDSwitch | Export-Clixml "$Destination\VDSwitches.xml" -Depth $Depth
  Get-VM | Export-Clixml "$Destination\VMs.xml" -Depth $Depth
}


function Import-Inventory
{
param(
  [String] $Source 
)

  $inventaire = @{}
  dir $Source | % {
    $inventaire[$_.BaseName] = Import-Clixml $_.FullName
  }
  return  $inventaire
}


function Export-VmToCsv
{
param(
  [String] $Destination
)
  Get-VM | % {
  $v = $_

  $hds = @()
  Get-HardDisk -VM $v | % {
    $hd= $_
    $hds += $hd.CapacityGB
  }
  $disques = [String]::Join(',', $hds)

  (Get-HardDisk -VM $v)[0] | % {
    $disk = $_
    if ($disk.Filename -match "\[(.+)\].*"){
      $Datastore = $Matches[1]
    }else{
      $Datastore = '(Get-BestDatastore)'
    }
  }

  $pgs = @()
  $vdpgs = @()
  $v.NetworkAdapters| Select-Object NetworkName | % {
    $net = $_.NetworkName
    if ( (Get-View -ViewType Network -Filter @{name=$net}).MoRef.Type -eq `
                    'DistributedVirtualPortgroup'){
      $vdpgs += $net
    }else{
      $pgs += $net
    }
  }
  $network = [String]::Join( ",", $pgs)
  $portGroup = [String]::Join( ",", $vdpgs)

  if ($v.CDDrives.Count -gt 0){$cdrom = $true}else{$cdrom = $false}

  if ($v.FolderId -eq $null){
    $location = 'vm'
  }else{
    $location = "(Get-FolderFromPath -Path '" + `
                (Get-PathFromFolder(Get-Folder -Id $v.FolderId)) + "')"
  }

  if ($v.VApp -ne $null){
    $ResourcePool = "(Get-VApp '$($v.VApp)')"
  }else{
    $ResourcePool = "(Get-BestHost)" 
  }

  $vm = [PSCustomObject] @{
      Name = $v.Name ;
      MemoryGB = $v.MemoryGB  ; 
      NumCpu = $v.NumCpu ; 
      GuestId = $v.GuestId ;
      DiskGB = $disques ;
      Cd = $cdrom ;
      ResourcePool = $ResourcePool ;
      NetworkName = $network ;
      Portgroup = $portGroup ;
      Datastore = $Datastore ;
      Location = $location;
      Notes = $v.Notes
  }

  Export-Csv -InputObject $vm `
             -Path $Destination `
             -Delimiter ';' `
             -NoTypeInformation `
             -Append
  }
}


#ENDREGION 5

#REGION 6

function Get-VMHostSummary
{
param(
    [VMware.VimAutomation.Types.VMHost[]] $VmHost=(Get-VMHost)
)
  $VmHost | % {
    $h = $_
    $report = $h | `
      Select-Object Name, `
       ConnectionState, `
       PowerState, `
       @{N='CpuUsage';E={"{0:p2}" -f ($_.CpuUsageMhz / $_.CpuTotalMhz)}}, `
       @{N='MemUsage';E={"{0:p2}" -f ($_.MemoryUsageGB / $_.MemoryTotalGB)}},`
       @{Name='VMs';Expression={(Get-Vm -Location $h).Count}}, `
       @{N='Datastores';E={$h.DatastoreIdList.Count}}, `
       @{N='VirtualSwitchs';E={(Get-VirtualSwitch -VMHost $h).Count}}, `
       @{N='VDSwitchs';E={(Get-VDSwitch -VMHost $h).Count}}

    $report
  }
}


function Get-VMSummary
{
param(
  [VMware.VimAutomation.Types.VirtualMachine[]] $VM=$null
)
  if ($VM -eq $null){$VM = Get-VM}

  $VM | % {
      $v = $_

    $hds = @()
    Get-HardDisk -VM $v | % {
      $hd= $_
      $hds += $hd.CapacityGB
    }
    $disques = [String]::Join(',', $hds)

    $ds = @()
    $v.DatastoreIdList  | % { $ds += Get-Datastore -Id $_ }
    $Datastore = [String]::Join( ",", $ds)

    $pgs = @()
    $vdpgs = @()
    $v.NetworkAdapters| Select-Object NetworkName | % {
      $net = $_.NetworkName
      if ( (Get-View -ViewType Network -Filter @{name=$net}).MoRef.Type -eq `
                      'DistributedVirtualPortgroup'){
        $vdpgs += $net
      }else{
        $pgs += $net
      }
    }
    $network = [String]::Join( ",", $pgs)
    $portGroup = [String]::Join( ",", $vdpgs)

    if ($v.FolderId -eq $null){
      $location = 'vm'
    }else{
      $location = (Get-PathFromFolder(Get-Folder -Id $v.FolderId))
    }

    $Cluster = Get-Cluster -VM $v -ErrorAction SilentlyContinue
    if (-not $?){$Cluster = $null}

    $persoVm = [PSCustomObject] @{
      Name = $v.Name ;
      VMHost = $v.VMHost ;
      Datastore = $Datastore ;
      Cluster = $Cluster
      DiskGB = $disques ;
      NetworkName = $network ;
      Portgroup = $portGroup ;
      MemoryGB  = $v.MemoryGB ; 
      Location = $location;
      GuestHostName = $v.Guest.HostName
      Os = $v.Guest.OSFullName
      Ip = [String]::Join( ",", $v.Guest.IPAddress)
      Snapshots = (Get-Snapshot $v).Count
    }
    $persoVm
  }
}


function Get-ClusterSummary
{
param(
    [VMware.VimAutomation.Types.Cluster[]] $Cluster=$null
)
  if ($Cluster -eq $null){$Cluster = Get-Cluster}

  $Cluster | % {
    $c = $_

    $ds = @()
    Get-Datastore -Entity $c  | % { $ds += $_.Name }
    $Datastores = [String]::Join( ",", $ds)
    $TotalDatastores = $ds.Count

    $hs = @()
    Get-VMHost -Location $c  | % { $hs += $_.Name }
    $Hosts = [String]::Join( ",", $hs)
    $TotalHosts = $hs.Count  

    $persoCluster = [PSCustomObject] @{
      Name = $c.Name ;
      HAEnabled = $c.HAEnabled ;
      DrsEnabled  = $c.DrsEnabled ; 
      TotalVMs = (Get-VM -Location $c).Count ;
      TotalDatastores = $TotalDatastores ;
      TotalHosts = $TotalHosts ;
      MemoryTotalGB = [math]::round( (Get-VMHost -Location $c | Measure-Object -Property MemoryTotalGB -Sum).Sum, 2) ;
      CpuTotalGhz = [math]::round( ((Get-VMHost -Location $c | Measure-Object -Property CpuTotalMhz -Sum).Sum / 1000), 2) ;
      Datastores = $Datastores ;
      Hosts = $Hosts 
    }
    $persoCluster
  }
}


function Export-Html
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  $InputObject,
  [Parameter(Mandatory=$true)]
  [String] $Destination,
  [String] $Titre='Rapport',
  [String] $CssPath='style.css',
  [String] $Filter=$null
)
begin{
  $css = '<style type="text/css">' + (Get-Content $CssPath) + '</style>'
  $green = '#80FF80'
  $red = '#FF6C48'
  $report = @()
}
process{
  $report += $InputObject | Select-Object -Property *, @{
                      N='Conformité'; 
                      E={if ((Invoke-Expression ('$_.' + $Filter))){'@conforme'}else{'@non conforme'}}}

    
}
   
end {
  $report | ConvertTo-Html -Title $titre `
                -Head $css `
                -Body "<CENTER><H1>$Titre</H1></CENTER>" | `
    % {
      if ($_ -match '<td>@conforme</td>'){
        $_ -replace '<tr>', "<tr bgcolor=$green>"
      }elseif ($_ -match '<td>@non conforme</td>'){
        $_ -replace '<tr>', "<tr bgcolor=$red>"
      }else{
        $_
        }
      } | Out-File $Destination
  }
}


function Get-Audit
{
[CmdletBinding()]
param(
  [String] $EventType,
  [String] $Username,
  [String] $Start,
  [String] $Finish,
  [ValidateSet('Error', 'Info', 'Warning')] $EventCategory,
  [Int32] $MaxSamples 
)

  $cmd = 'Get-VIEvent '  
  $PSCmdlet.MyInvocation.BoundParameters.keys | ? {$_ -ne 'EventType'} | % {
    $cle = $_
    if ($cle -iin ('Start', 'Finish')){
        $valeur = "(Get-Date '$($PSCmdlet.MyInvocation.BoundParameters.$cle)')"
    }else{
        $valeur = $PSCmdlet.MyInvocation.BoundParameters.$cle
    }
    $cmd += "-{0}:{1} " -f ($cle, $valeur)
  }

  $events = Invoke-Expression -Command $cmd
  $events | ? {$_.Gettype().Name -eq $EventType} | `
  ft UserName, CreatedTime, FullFormattedMessage -AutoSize
}


#ENDREGION 6

#REGION 7

function Get-VmMountedIso
{
param (
  [String] $Iso='.',
  [Switch] $Cd
)
  $arrVms = @()
  $arrIsos = @()
  
  Get-VM | % {
    $vm = $_ ; $null = Get-CDDrive -VM $_ | ? {$_.IsoPath -match $Iso} | % {
        $arrIsos+=$_
        Write-Host ("{0}`t{1}" -f ($vm.Name, $_.IsoPath))
        $arrVms+=$vm
    }
  }
  
  if ($Cd.isPresent){
      return $arrIsos
  }else{
      return $arrVms
  }
}


function Get-LockdownMode
{
param(
  [ValidateSet('Enabled', 'Disabled')]
  $LockdownMode=$null,
  [VMware.VimAutomation.Types.VMHost[]] $VMHost=(Get-VMHost)
)
  if ($LockdownMode -eq 'Enabled'){$lock = $true}else{$lock = $false}

  if ($LockdownMode -eq $null){
    $VMHost | Select-Object @{N='VMHost'; E={$_}}, `
                               @{N='LockdownMode'; `
                                 E={$_.ExtensionData.Config.AdminDisabled}}
  }else{
    $VMHost | ? {$_.ExtensionData.Config.AdminDisabled -eq $lock} | `
    Select-Object @{N='VMHost'; E={$_}}, `
                  @{N='LockdownMode'; `
                    E={$_.ExtensionData.Config.AdminDisabled}}
  }
}


function Enable-LockdownMode
{
param(
  [Parameter(ValueFromPipelineByPropertyName=$true)]
  [VMware.VimAutomation.Types.VMHost[]] $VMHost=$null,
  [Switch] $DisableLockdownMode
)

process{
  if ($VMHost -eq $null){return}
  $VMHost | % {
    if ($DisableLockdownMode.isPresent){
      if ($_.ExtensionData.Config.AdminDisabled -eq $true){
        $_.ExtensionData.ExitLockdownMode() 
        $_
      }
    }else{
      if ($_.ExtensionData.Config.AdminDisabled -eq $false){
        $_.ExtensionData.EnterLockdownMode() 
        $_
      }
    }
  }
  }    
}

function Get-PathFromFolder
{
param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  [VMware.VimAutomation.Types.Folder []] $Folder
)
process{
  $Folder | % {
    $id = $_.Id
    $path = @()
    $in = $true
    while ($in){    
      $dossier = Get-Folder -Id $id -ErrorAction SilentlyContinue
      if ($?){
        $path += $dossier.Name
        $id = $dossier.ParentId
        if ($id -eq $null){ $in = $false } 
      }else{
        $in = $false
      }
    }

    [Array]::Reverse($path)
    [String]::Join('\', $path)
  }
  }
}


function Where-Is($Entity)
{
  
  if (($Entity -isnot [VMware.VimAutomation.Types.VirtualMachine]) -and `
      ($Entity -isnot [VMware.VimAutomation.Types.VApp]) -and `
      ($Entity -isnot [VMware.VimAutomation.Types.Template])
  ){
    "La fonction d'accepte que des types : VirtualMachine, VApp, Template"
    return
  }
  
  $v = Get-View -VIObject $Entity

  if ($v.ParentFolder -ne $null){ 
    $ParentFolder = $v.ParentFolder
  }elseif ($v.ParentVApp -ne $null){
    $vapp = Get-VApp -Id ($v.ParentVApp.Type + "-" + $v.ParentVApp.Value)
    $rep += ((Where-Is $vapp) +  '\' + $v.Name)
    return $rep
  }else{
    $ParentFolder = $v.Parent
  }
  
  if ($v.GetType().Name -eq 'VirtualApp'){
      ((Get-PathFromFolder -Folder (Get-Folder -Id $ParentFolder)) `
        + '\' + $v.Name)
  }else{
    Get-PathFromFolder -Folder (Get-Folder -Id $ParentFolder)
  }
}


$Completion_VMHostService = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)

    Get-VMHostService (Get-VMHost)[0] | % {
        New-Object System.Management.Automation.CompletionResult $_.Key, $_.Key, 'ParameterValue', $_.Label
    }
}

function Start-HostService
{
[CmdletBinding()] 
param(
  [Parameter(Mandatory=$true)]
  $Service,
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  [VMware.VimAutomation.Types.VMHost[]] $VMHost
)
process{
  $VMHost | Get-VMHostService | ? { $_.Key -eq $Service} |  Start-VMHostService
}
}

function Stop-HostService
{
[CmdletBinding()] 
param(
  [Parameter(Mandatory=$true)]
  $Service,
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
  [VMware.VimAutomation.Types.VMHost[]] $VMHost
)
process{
  $VMHost | Get-VMHostService | ? { $_.Key -eq $Service} |  Stop-VMHostService
}
}

if (-not $global:options) { $global:options = @{CustomArgumentCompleters = @{};NativeArgumentCompleters = @{}}}
                      
$global:options['CustomArgumentCompleters']['Start-HostService:Service'] = `
  $Completion_VMHostService

$global:options['CustomArgumentCompleters']['Stop-HostService:Service'] = `
  $Completion_VMHostService

$function:tabexpansion2 = $function:tabexpansion2 -replace 'End\r\n{','End { if ($null -ne $options) { $options += $global:options} else {$options = $global:options}'


#ENDREGION 7

#REGION 8


function Add-iScsiStaticTarget
{
param(
	[Parameter(Mandatory=$true)]
	$VMHost,
	[Parameter(Mandatory=$true)]
	[String] $Address,
	[Parameter(Mandatory=$true)]
	[String] $IScsiName,
	[Int] $Port=3260,
	[String] $ChapName, 
	[String] $ChapPassword,
	[ValidateSet('Prohibited', 'Discouraged', 'Preferred', 'Required')]
	$ChapType
)

  $targets = New-Object VMware.Vim.HostInternetScsiHbaStaticTarget[] (1)
  $targets[0] = New-Object VMware.Vim.HostInternetScsiHbaStaticTarget
  $targets[0].address = $Address
  $targets[0].port = $Port
  $targets[0].iScsiName = $IScsiName

  if ($ChapName -ne '' -and $ChapPassword -ne '' -and $ChapType -ne ''){
    $targets[0].authenticationProperties `
        = New-Object VMware.Vim.HostInternetScsiHbaAuthenticationProperties
    $targets[0].authenticationProperties.chapAuthEnabled = $true
    $targets[0].authenticationProperties.chapName = $ChapName
    $targets[0].authenticationProperties.chapSecret = $ChapPassword
    $targets[0].authenticationProperties.chapAuthenticationType `
          = "chap$ChapType"
    $targets[0].authenticationProperties.chapInherited = $false
    $targets[0].authenticationProperties.mutualChapAuthenticationType `
          = "chapProhibited"
    $targets[0].authenticationProperties.mutualChapInherited = $true
  }

  $connecteur = Get-VMHostHba -Type iSCSI -VMHost $VMHost | Select-Object -First 1
  $_this = Get-View -Id (`
					"HostStorageSystem-{0}" -f `
					((Get-VMHost $VMHost).ExtensionData.ConfigManager.StorageSystem.Value)
				)
  $_this.AddInternetScsiStaticTargets($connecteur.Device, $targets)
}


#ENDREGION 8