Wednesday, February 24, 2016

Install missing Powershell ISE on Windows Server 2008 R2

Everytime I login to any of new server in my windows server 2008 r2 with default PSversion powershell v2 I find ISE is missing and it need to install in case if i want to run some script, (Powershell ISE is my favorite powershell script editor which comes with windows 2008 r2 and above), I use ISE lot to edit scripts. 

Here is how when I search for powershell it is missing.
Here is how you can install it using powershell it self, open powershell as an administrator. and you will have run below 2 commands to install ISE.
Import-Module ServerManager
Add-WindowsFeature Powershell-ISE
If you check in the above screenshot you will find powershell can be used from GUI, need to install as a feature from Server Manager and the Feature name is a Windows Powershell Integrated Scripting Engine.

I prefer the powershell way only to install ISE, because I find it quick, no need to touch mouse., and also this way I memorize my essential commands.

Friday, February 19, 2016

vSphere Datastores inventory report powercli - Volume 2

I used to collect datastores inventory using my old script VMware Datastores inventory. It is still very handy when I want to keep it as inventory. This inventory is also good when I want to troubleshoot, but over the period of time I found still I am missing something. Now I have added some more useful information about iSCSI paths. With this information I was able to rectify and implement multiplying best practices correctly. 

Alike my old script this also tells datastore configuration information per host, It starts with first esxi host, pull information about all the datastores configured on it, then second host and all the datastores on it, and so on, Below is list this script pulls information about.
VMhost name
DatastoreName -  You will find it repetitive if same datastore is mounted on another host also
FreeSpaceGB - Free Space in GB
CapacityGB - Capacity in GB
FileSystemVersion - this tells what is the version of VMFS filesystem.
RuntimeName: Handy when you want to check what device datastore is mapped.
CanonicalName: I use this to match my esxi datastore and storage name. (I can ensure I am working on correct lun/datastore)
MultipathPolicy: Self explanatory.
Vendor: Esxi can detect what can be device (vendor) of datastore.
DatastoreDatacenter:  Datacenter this datastore available.
VMsOnDatastore: VMs name on the this datastore but only belongs the esxi host you are fetching information
NumberofPaths: This is really handy and saved my day lots of time.
Paths: IP addresses of Paths (iscsi target storage paths)
State: Where path is active or standby?
Preferred:  What storage path is preferred path?
IsWorkingPath: This somewhat similar to preferred path. but tells is the path active currently.

This is screenshot after running the script on the console. 
here is the script, on how to use u can check my previous articles, 
  #####################################                                                                
  ## http://kunaludapi.blogspot.com                                                                
  ## Version: 2                                                               
  ## Date: 16 Dec 2015                                                              
  ## Script tested on below platform                                                                
  ## 1) Powershell v4                                                               
  ## 2) Powercli v5.5                                                                
  ## 3) Vsphere 5.5                                                               
  ####################################                                                               
  #Add-PSSnapin vmware.vimautomation.core                                                               
  #Connect-Viserver #vcenterserver                                                                
                                                               
 function Get-DatastoreInventory {                                                               
   $HostDatastoreInfo = Get-VMHost | Get-ScsiLun -LunType disk                                                                
   $DatastoreInfo = Get-Datastore                                                               
   foreach ($Hostdatastore in $HostDatastoreInfo) {                                                                
    $Datastore = $DatastoreInfo | Where-Object {$_.extensiondata.info.vmfs.extent.Diskname -match $Hostdatastore.CanonicalName}                                                               
    $LunPath = $Hostdatastore | Get-ScsiLunPath                                                              
    if ($Datastore.ExtensionData.vm) {                                                               
     $VMsOnDatastore = $(Get-view $Datastore.ExtensionData.vm).name -join ","                                                               
    } #if                                                               
    else {$VMsOnDatastore = "No VMs"}                                                               
                                                                 
   #Work on not assigned Luns error at silentlyContinue                                                               
    if ($Datastore.Name -eq $null) {                                                              
     $DatastoreName = "Not mapped"                                                              
     $FileSystemVersion = "Not mapped"                                                              
    }                                                              
    else {                                                              
     $DatastoreName = $Datastore.Name -join ","                                                              
     $FileSystemVersion = $Datastore[0].FileSystemVersion                                                               
    }                                                              
                                                                   
    $DatastoreFreeSpace = $Datastore.FreeSpaceGB -join ", "                                                               
    $DatastoreCapacityGB = $Datastore.CapacityGB -join ", "                                                               
    $DatastoreDatacenter = $Datastore.Datacenter -join ", "                                                               
                                                               
    $State = $LunPath.State -join ", "                                                              
    $Preferred = $LunPath.Preferred -join ", "                                                              
    $Paths = ($LunPath.ExtensionData.Transport | foreach {($_.Address -split ":")[0]}) -Join ", "                                                              
    $IsWorkingPath = $LunPath.ExtensionData.IsWorkingPath -Join ", "                                                              
                                                                  
    $Obj = New-Object PSObject                                                               
    $Obj | Add-Member -Name VMhost -MemberType NoteProperty -Value $hostdatastore.VMHost                                                               
    $Obj | Add-Member -Name DatastoreName -MemberType NoteProperty -Value $DatastoreName                                                                
    $Obj | Add-Member -Name FreeSpaceGB -MemberType NoteProperty -Value $DatastoreFreeSpace                                                               
    $Obj | Add-Member -Name CapacityGB -MemberType NoteProperty -Value $DatastoreCapacityGB                                                               
    $Obj | Add-Member -Name FileSystemVersion -MemberType NoteProperty -Value $FileSystemVersion                                                               
    $Obj | Add-Member -Name RuntimeName -MemberType NoteProperty -Value $hostdatastore.RuntimeName                                                               
    $Obj | Add-Member -Name CanonicalName -MemberType NoteProperty -Value $hostdatastore.CanonicalName                                                               
    $Obj | Add-Member -Name MultipathPolicy -MemberType NoteProperty -Value $hostdatastore.MultipathPolicy                                                               
    $Obj | Add-Member -Name Vendor -MemberType NoteProperty -Value $hostdatastore.Vendor                                                               
    $Obj | Add-Member -Name DatastoreDatacenter -MemberType NoteProperty -Value $DatastoreDatacenter                                                               
    $Obj | Add-Member -Name VMsOnDataStore -MemberType NoteProperty -Value $VMsOnDatastore                                                               
    $Obj | Add-Member -Name NumberOfPaths -MemberType NoteProperty -Value $LunPath.Count                                                              
    $Obj | Add-Member -Name Paths -MemberType NoteProperty -Value $Paths                                                              
    $Obj | Add-Member -Name State -MemberType NoteProperty -Value $State                                                              
    $Obj | Add-Member -Name Preferred -MemberType NoteProperty -Value $Preferred                                                              
    $Obj | Add-Member -Name IsWorkingPath -MemberType NoteProperty -Value $IsWorkingPath                                                              
    $Obj                                                               
   }                                                               
  }                                                               
  Get-DatastoreInventory | Export-Csv -NoTypeInformation c:\temp\DatastoreInfoHostwise.csv                                                              
I exported report to csv and file looks like this., Csv file can be opened in excel, this CSV can be used as inventory later, My favorite use is capacity management, I kept collecting data for 1 year, and after 1 year i know how datastore is getting filled gradually. 

Monday, February 15, 2016

import vCenter roles (privileges) - Powercli.

From my first article Export vcenter roles (privileges) I exported all the roles and privileges successfully now it was task to migrate Roles on another vCenter. I already had grabbed roles in files so they where completely portable, I extracted zip file of my roles in the same c:\temp folder as I was going to use it.

Other very useful script for vCenter migration.

Exporting virtual machine annotation (Attributes) and notes to CSV file - Powercli

Move/Migrate VMs to folder Path on another vCenter - Powercli

Get vCenter VM folder Path from VMs and Templates- Powercli

Importing VM annotation (Attributes) and notes from CSV file into vCenter - Powercli

Import vCenter roles (privileges) - Powercli

Export vcenter roles (privileges)


this is screenshot from my previous post it contains all the roles.
Here is the script. I hope I am keeping all simple.

 <#   
  .Synopsis   
   Imports roles into vsphere roles..   
  .Description   
   This script imports roles into vspheres from .role file/   
  .Example   
   Import-vSphereRoles -Path c:\temp  
   Import Roles to the folder.   
  .Notes  
   NAME: Import-vSphereRoles   
   AUTHOR: Kunal Udapi   
   LASTEDIT: 15th February 2016  
   KEYWORDS: Import Roles   
  .Link   
   #Check Online version: http://kunaludapi.blogspot.com    
   #Requires -Version 3.0   
  #>   
  #requires -Version 3    
 [CmdletBinding(SupportsShouldProcess)]   
  Param(   
   [Parameter(Mandatory=$true, Position=1,   
    ValueFromPipeline=$true)]   
   [AllowNull()]   
   [alias("LiteralPath")]   
   [string]$Path = "c:\temp"    
  ) #Param   
 Begin {  
   $roleFiles = Get-ChildItem -Path $Path -Filter *.role  
 }  
 Process {  
   foreach ($role in $roleFiles) {  
     $VIRoleName = $role.BaseName   
     $RolesContent = Get-Content -Path $role.FullName  
     New-Virole -Name $VIRoleName | Out-Null  
     Write-Host "Created Role `"$VIRoleName`"" -BackgroundColor DarkGreen  
     foreach ($Privilege in $RolesContent) {  
       if (-not($privilege -eq $null -or $privilage -eq "")) {  
         Write-Host "Setting Permissions `"$Privilege`" on Role `"$VIRoleName`"" -ForegroundColor Yellow  
         Set-VIRole -Role $VIRoleName -AddPrivilege (Get-VIPrivilege -ID $privilege) | Out-Null  
       } #if (-not($privilege -eq $null -or $privilage -eq ""))  
     } #foreach ($Privilege in $RolesContent)  
   } #foreach ($role in $roleFiles)  
 }  
Once you keep it in .ps1 and run it  (check my earlier post for Export vcenter roles (privileges) how i have collected information and running script), you will see powercli console some thing like below screenshot.
I will be sharing next script for Exporting and Importing roles permissions stay tuned. If you like this article please share knowledge. 

Export vcenter roles (privileges) - Powercli.

This post I am continuing from another posts, Migration from one vcenter to another.

Exporting virtual machine annotation (Attributes) and notes to CSV file - Powercli

Move/Migrate VMs to folder Path on another vCenter - Powercli

Get vCenter VM folder Path from VMs and Templates- Powercli

Importing VM annotation (Attributes) and notes from CSV file into vCenter - Powercli

Import vCenter roles (privileges) - Powercli

Export vcenter roles (privileges)


In this post I will be showing how to export roles. and can be imported to another vCenter. This is completely dedicated to exporting roles only, they are exported to specified folder with .role extension. As you can see I have multiple roles created, some are by default created roles, my script skip those roles and only backup User created roles.
When you edit one of the role you will see information some thing like this, these are called roles privileges. Each privilege has some meaning ful name, ie inside alarms there is acknowledge alarm rights.
Here is my script that can pull all this information and keeps in .role file. Copy paste this script and keep it in ps1 file.
  <#   
  .Synopsis   
   Exports vsphere roles to text file extension roles.   
  .Description   
   This script exports only the custom created roles by users   
  .Example   
   Export-vSphereRoles -Path c:\temp  
   Exports Roles to the folder.   
  .Notes  
   NAME: Export-vSphereRoles   
   AUTHOR: Kunal Udapi   
   LASTEDIT: 12th February 2016  
   KEYWORDS: Export Roles   
  .Link   
   #Check Online version: http://kunaludapi.blogspot.com    
   #Requires -Version 3.0   
  #>   
  #requires -Version 3    
 [CmdletBinding(SupportsShouldProcess)]   
  Param(   
   [Parameter(Mandatory=$true, Position=1,   
    ValueFromPipeline=$true)]   
   [AllowNull()]   
   [alias("LiteralPath")]   
   [string]$Path = "c:\temp"    
  ) #Param   
 Begin {  
   $DefaultRoles = "NoAccess", "Anonymous", "View", "ReadOnly", "Admin", "VirtualMachinePowerUser", "VirtualMachineUser", "ResourcePoolAdministrator", "VMwareConsolidatedBackupUser", "DatastoreConsumer", "NetworkConsumer"  
   $DefaultRolescount = $defaultRoles.Count  
   $CustomRoles = @()  
 } #Begin  
   
 Process {  
   $AllVIRoles = Get-VIRole  
   
   0..($DefaultRolescount) | ForEach-Object {  
     if ($(Get-Variable "role$_" -ErrorAction SilentlyContinue)) {  
       Remove-Variable "role$_" -Force -Confirm:$false  
     } #if ($(Get-Variable "role$_" -ErrorAction SilentlyContinue))  
   } #0..($DefaultRolescount) | Foreach-Object  
   
   0..$DefaultRolescount | ForEach-Object {  
     $DefaultRolesnumber = $DefaultRoles[$_]  
     if ($_ -eq 0) {  
       New-Variable "role$_" -Option AllScope -Value ($AllVIRoles | Where-Object {$_.Name -ne $DefaultRolesnumber})  
     } #if ($_ -eq 0)  
     else {  
       $vartxt = $_ - 1  
       $lastrole = 'role'+"$vartxt"  
       #Get-Variable $lastrole  
       New-Variable "role$_" -Option AllScope -Value (Get-Variable "$lastrole" | select -ExpandProperty value | Where-Object {$_.Name -ne $DefaultRolesnumber})  
     } #else ($_ -eq 0)  
   } #0..$DefaultRolescount | ForEach-Object  
   $filteredRoles = Get-Variable "role$($DefaultRolescount-1)" | select -ExpandProperty value  
 } #Process  
 End {  
   $filteredRoles | ForEach-Object {  
     $completePath = Join-Path -Path $Path -ChildPath "$_.role"  
     Write-Host "Exporting Role `"$($_.Name)`" to `"$completePath`"" -ForegroundColor Yellow  
     $_ | Get-VIPrivilege | select-object -ExpandProperty Id | Out-File -FilePath $completePath  
   } #$filteredRoles | ForEach-Object  
 } #End  
   
Open vmwere vsphere powercli,  Make sure your execution policy is set to remote singed or something that can execute script. Mine is unrestricted, I only run script created by me only.
Connect to old vcenter server using Connect-VIServer command.
Once you are connected. time to execute command, I have saved my script under c:\script. and this is how I run that script with dot sourcing. Once you run ps1 file you can see on the screen what is happening in yellow.
All the roles file are stored on the c:\temp, now you can copy paste these roles in zip file and ready to be used on other vcenter for importing.
You can open role file in notepad and the view is as below. This is how exported vcenter role file looks like, in my next blog i am going to use same file and export privileges to another vCenter.

Saturday, February 13, 2016

Change username/password configured on logon tab of Windows Service - Powershell

This my another part of List account configured on logon of Windows Service and in this there is a recipe to (Setup service account) change or replace account username/ password on windows service logon tab. Before running make sure your account has permissions or admin rights to change into windows service. Also make sure you open powershell as administrator. 

You can check my earlier post List account configured on logon of Windows Service, how to use this script, if you still have any issue drop a comment on this post I will try to resolve it.
 function Set-ServiceLogonAccount {  
 <#  
  .Synopsis  
   Change or set username password on Service logon Account  
  .Description  
   Make sure you open powershell with as administrator and you have appropriate permissions to modify service settings. You must specify Service name instead of display name.  
  .Example  
   Set-ServiceLogonAccount -ComputerName 192.168.33.51 -LogonUserName vcloud\vkunal -LogonPassword Computer@1 -Service lanmanserver -Credential (Get-Credential)  
     
   It make changes on service lanmanserver on remote computer 192.168.33.51, logon username is changed to vcloud\vkunal and password is set to Computer@1, credential is your remote login credentials.  
  .Example  
   Set-ServiceLogonAccount -LogonUserName .\test -LogonPassword Computer@1  
   By default if only logonusername and logonpassword paramter given it make changes to localhost and service is lanmanserver.  
   
  .OutPuts  
   ∞ JUMBOPC is pinging, attempting to connect...  
   
   PSComputerName : JUMBOPC  
   Name      : LanmanServer  
   DisplayName  : Server  
   StartMode   : Auto  
   State     : Running  
   Started    : True  
   StartName   : .\test  
   
  .Notes  
   NAME: Set-ServiceLogonAccount  
   AUTHOR: Kunal Udapi  
   LASTEDIT: 13th February 2015  
   KEYWORDS: Service log on accounts  
  .Link  
   #Check Online version: Http://kunaludapi.blogspot.com   
   #Requires -Version 3.0  
  #>  
 #requires -Version 3   
 [CmdletBinding(SupportsShouldProcess)]  
 Param(  
   [Parameter(<#Mandatory=$true,#>Position=1,  
     ValueFromPipeline=$true,  
     ValueFromPipelineByPropertyName=$true)]  
   [AllowNull()]  
   [alias("ComputerName", "Computer")]  
   [string]$Name = $env:COMPUTERNAME,   
   
   [Parameter(Mandatory=$true,Position=3)]  
   [string]$LogonUserName,   
     
   [Parameter(Mandatory=$true,Position=4)]  
   [string]$LogonPassword,   
      
   [Parameter(Position=2)]  
   [AllowNull()]    
   [alias("ServiceName")]  
   [string]$Service = 'LanmanServer',  
   
   #[Parameter(Mandatory=$true)]  
   [System.Management.Automation.PSCredential]$Credential,  
   $Protocol = 'DCOM'  
 ) #Param  
 Begin {  
   #$TempFolder = Split-Path $CSVfile  
   #if (-not (Test-Path $TempFolder)) {  
   #  [void](New-Item -Path $TempFolder -Force)  
   #} #if (-not (Test-Path $TempFolder)) {  
 #region Ping  
   Function Get-Ping {  
     Test-Connection -ComputerName $Name -Quiet -Count 2 -ErrorAction SilentlyContinue  
   } # Function Ping-Server  
 #endregion  
   $CIMoption = New-CimSessionOption -Protocol $protocol  
 } #Begin  
 Process {  
   $query = "Select * from Win32_Service Where Name = `'$service`'"  
   if ($(Get-Ping $Name) -eq $true) {  
     Write-Host "$([char]8734) $Name is pinging, attempting to connect..." -ForegroundColor Green  
     if ($Credential -eq $null) {  
       Try {  
         $CIMsession = New-CimSession -ComputerName $Name -SessionOption $CIMoption -ErrorAction SilentlyContinue  
         $cimresult = Get-CimInstance -CimSession $CIMsession -Query $query | Invoke-CimMethod -Name Change -Arguments @{StartName=$LogonUserName;StartPassword=$LogonPassword}  
         #$ServiceDetails = Get-CimInstance -CimSession $CIMsession -Query $query  
       } #Try  
       Catch {  
         Write-Host "`t $([char]215) Server $Name cannot be contacted, skipped it" -ForegroundColor Red  
         Continue  
       } #Catch  
     } #if ($Credential -eq $null)  
     else {  
       Try {  
         #$ServiceDetail = Get-WmiObject -Query $query -ComputerName $Name -Credential $Credential -ErrorAction SilentlyContinue  
         $CIMsession = New-CimSession -ComputerName $Name -SessionOption $CIMoption -Credential $Credential -ErrorAction SilentlyContinue  
         $cimresult = Get-CimInstance -CimSession $CIMsession -Query $query |Invoke-CimMethod -Name Change -Arguments @{StartName=$LogonUserName;StartPassword=$LogonPassword}  
       } #Try  
       Catch {  
         Write-Host "`t $([char]215) Server $Name cannot be contacted, skipped it" -ForegroundColor Red  
         Continue  
       } #Catch  
     } #else ($Credential -eq $null)  
   } #if ($(Ping-Server $Name) -eq $true  
   else {  
     Write-Host "$([char]8734) $Name is not pinging, but Still trying to connect..." -ForegroundColor Yellow  
     if ($Credential -eq $null) {  
       Try {  
         #$ServiceDetail = Get-WmiObject -Query $query -ComputerName $Name -ErrorAction SilentlyContinue  
         $CIMsession = New-CimSession -ComputerName $Name -SessionOption $CIMoption -ErrorAction SilentlyContinue  
         $cimresult = Get-CimInstance -CimSession $CIMsession -Query $query |Invoke-CimMethod -Name Change -Arguments @{StartName=$LogonUserName;StartPassword=$LogonPassword}  
       } #Try  
       Catch {  
         Write-Host "`t $([char]215) Server $Name cannot be contacted, skipped it" -ForegroundColor Red  
         Continue  
       } #Catch  
     } #if ($Credential -eq $null)  
     else {  
       Try {  
         #$ServiceDetail = Get-WmiObject -Query $query -ComputerName $Name -Credential $Credential -ErrorAction SilentlyContinue  
         $CIMsession = New-CimSession -ComputerName $Name -SessionOption $CIMoption -Credential $Credential -ErrorAction SilentlyContinue  
         $cimresult = Get-CimInstance -CimSession $CIMsession -Query $query |Invoke-CimMethod -Name Change -Arguments @{StartName=$LogonUserName;StartPassword=$LogonPassword}  
       } #Try  
       Catch {  
         Write-Host "`t $([char]215) Server $Name cannot be contacted, skipped it" -ForegroundColor Red  
         Continue  
       } #Catch  
     } #else ($Credential -eq $null)  
   } #else ($(Ping-Server $Name) -eq $false)  
   if (-not ($cimresult -eq $null)) {  
     Get-CimInstance -CimSession $CIMsession -Query $query | Select-Object PSComputerName, Name, DisplayName, StartMode, State, Started, StartName  
   } #if ($ServiceDetails -eq $null)  
   else {  
     Write-Host "`t $([char]215) Please check Server $Name manually" -ForegroundColor Red  
   } #else ($ServiceDetail -eq $null)  
 } #Process  
 End {  
   
 } #End  
 } $function  
In the first screenshot I am setting local account on local machine,
In this screenshot I am modifying logon account on remote server, service is lanmanserver, also I have mention credential which will popup for username password to connect to remote server.
Here is parameters information
-ComputerName: If not specified default is localhost (this syntex can take value from pipe as well)
-LogonUserName:  Service account username

-LogonPassword:  Service Account password
-Service: if not specified default is lanmanserver, you have mention service name not display name
This is final result from both local and remote computer from services.msc
-Credential: Incase if remote computer in another domain or if you are not administrator you can use "-credential (get-credential)" to connect. otherwise for same domain this parameter doesn't required.
-Protocol: By default it uses legacy wmi dcom protocol to connect, there is another option wsman which use PSRemoting protocol.

Check on earlier useful script:
Get members from Remote Groups
List account configured on logon of Windows Service - Powershell