Tuesday, April 1, 2014

Working with HP ILO using PowerShell

Hi,

We needed to change password for one user for some hundreds of ESXi servers and task was distributed among the team and each person got nearly 50 servers. If you know me there was no way(may be last way) I was going to each ILO ip and change password for each ESXi server.

So I did a little google search and found that HP released a  module for HP ILO that can be downloaded from here HP ILO Cmdlets.     And i just want to clear that this module does not depend on what is the operating system installed on target server, it may be Unix, ESXi or Windows, it does not matter.

HP ILO Cmdlets support ILO v3 and ILO v4 (ILO v1 and ILO v2 are not supported) and you need at least powershell v2 to get this module to work(infact Powershell v1 does not support any Module, only PSSnapins)

After installing you will be getting a powershell module that you can findout by using
PS > Get-Module -ListAvailable



Once you are able to see the module, import the module in current session using
PS > Import-Module HPiLOCmdlets

Best part it this module is a script module, so you can just go to the module where it is installed and you can open HPiLOCmdlets.psm1 in notepad and find out how all fucntions are defined in module.

 












And it give you total of 110 Functions to work with.





So back to my problem, fortunately most of our servers were HP, so I took the charge of task and use below  command to reset the user

PS>Get-Content Servers.txt | foreach{ Set-HPiLOUser -Username username -Password password -UserLoginToEdit testuser -NewPassword newpassword}

So i get all ILO ips from Servers.txt and pipe it to Set-HPiloUser function and here username and pasword are for logging into the ILO, testuser is the user for which we want to change the password and newpassword will be obviously new password you want to set.

Actually you can find better help (I agree, much better help) if you would use
PS > Help  Set-HPiLOUser -Full

You can do much more with Set-HPiLOUser and even more with whole module.




Happy Scripting!!!



Wednesday, March 5, 2014

Lets Sort it Out using Sort-Object

Hi, We all used Sort-Object cmdlet one time or another, but generally we use it to sort in two ways based on one property in ascending or descending order, but Sort-Object can do more sophisticated things.


For our demonstration we will use below database, this data is stored in data.csv, we will store this in $data variable to work, and for whole blogpost, I will use Sort alias for Sort-Object.


PS >$data=import-csv .\data.csv
 
NameIDDepartment
John4567Management
Kivell3099Finance
Jardine1234IT
Gill9123Finance
Sorvino434IT
Jones5456Finance
Andrews1209Finance
Jardine2354IT
Thompson724IT
Jones1287Finance
Morgan8614IT
Howard5914Finance
Parent961Management
Jones5964IT
Smith1029Finance

So First of all we want to Sort above output in descending order based on name.



















That was easy, now we want to sort it on ID, let see the output below.



















Looks like, Powershell did something wrong, so what just happened there and why powershell seems to give us wrong sort output.

When we imported the data in PowerShell, all properties were imported as String, when we ask Powershell to sort, it sorts the property based on its type, most of the time it is fine, but sometimes, we have to intervene, this is one of that type.
We would tackle this by telling the Powershell to treat ID property as integer.



















Now, we have generally no issue to sort data based on two property also, if I want to sort data in descending order first for Department then for name so I can use below command

PS > $data | Sort -Property Department, Name -Descending.

But what if i want to sort data based on Department in Ascending order then on based on Name in Descending order, To do this Sort's Property Parameter can take an hashtable where we can mention, Ascnding or Descending order for each property separately.








Happy Scripting...

Thursday, February 6, 2014

What i found while playing with Group-Object Command

I am big fan of Group-Object command. If anybody asks you how many types of files are there in particular directory, hey it is one liner.

 Get-ChildItem | Group-Object Extension


Somebody asks you how many services are running and how many are stopped, now suppose Group-Object is not there, below is the path you will probably (there are many more other ways) you will take, in which first you will try to find running processes then stopped, then probably pipe that to Measure-Object to find the count of each type of Service.





















If you now Group-Object you can achieve that in one liner.




This is great, there are much more parameters that can be used with Group-Object.

For that just type
PS> Help Group-Object -Full

So, if you have just read the help of Group-Obejct, which I intended, you would know that Group-Object can do
1. Group Object based on a particular property
2. And output can be an hashtable if you use parameter -Ashashtable.

If I ask you get me all services which CanPauseAndContinue, below is the command.








 
If for some reason, you want result to be hashtable, use -asHashtable parameter as below.





I may save the same input in a variable called Services.

PS > $Services= Get-Service | Group-Object Status -AsHashTable

Now $Services.Stopped should give me all Services those are stopped, right?

No, It gave me null.   :-(









But why it is happening, Is it a bug?  answer again is No.

So I pinged my friend Dexter whose blog you can read at http://dexterposh.blogspot.in/.

He told me to use -AsString parameter and it worked, I got all Stopped services when I used $services.Stopped.



















But question arises Why?
Then I did  run below command.




Status has type System.ServiceProcess.ServiceController, but when I use $service.Running, powershell treat Running as String. String Running is not equal to System.ServiceProcess.ServiceController Running, both are different.

So what -Asstring parameter did was change hashtable keys to strings. So now both Running are string and I got my required output.

Let me know for any question.

Happy Scripting!!!!


Sunday, January 26, 2014

Getting Install Software in System

Hi,

My name is Ved Prakash. This is my first blog post, please comment and let me know for any suggestions.

I was sitting on my desk and my boss came to me and said, "Hey Ved, We want to know what software are installed on our Servers, so unwanted software can be removed".

Now this type of task is time consuming even for one server as you have to go to Programs and Features and write everything down and  needed to do it for about 20 servers.

I thought for a minute that Powershell could have helped us and I said yes.

So what could be a reliable way to this. We could have used wmi class Win32_Product  but that is not a good way to get installed software as it is not query optimized and change the consistency of software as Windows installer scan each software and not recommended in production environment so answer was Registry.

Under the subkeys of "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" is the place you can get your installed softwares.

I can get a WMI class of type StdRegProv to get the Standard Registry Provider WMI class to access the registry, which can be used on remote systems also using WMI.
Please see that I have used "list"  parameter which will give me Class not Object

$regwmi=get-wmiobject  -Namespace root\default -list -ComputerName $comp -Class StdRegProv

Now I got the registry location and provider to access it now I need to know how to access this registry location.
You can find in below link that below are the value of Registry trees. In my case I need to access HKEY_LOCAL_MACHINE, so I will be using 2147483650 to access registry.
HKEY_CLASSES_ROOT (2147483648 (0x80000000))
HKEY_CURRENT_USER (2147483649 (0x80000001))
HKEY_LOCAL_MACHINE (2147483650 (0x80000002))
HKEY_USERS (2147483651 (0x80000003))
HKEY_CURRENT_CONFIG (2147483653 (0x80000005))
http://msdn.microsoft.com/en-us/library/aa390788%28v=vs.85%29.aspx

Below is the code to get the subkeys.

$HKLM=2147483650
$Regkey="SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
$subkeys = $regwmi.EnumKey($HKLM, $Regkey)
$subkeys=$subkeys.snames


Now I know the Registry location, I just need to query these registry value using $regwmi already created.

Now, only location SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall works well if system is 32 bit but for 64 bit OS, additionally we need to dig the values from SOFTWARE\wow64\Microsoft\Windows\CurrentVersion\Uninstall to get the complete list of Softwares installed.

I need to first check my server is 64 bit or 32bit then acording to that I need to call the registry provider with appropriate registry location..

Below is the full code to get the information we are looking for.

  Function get-softwares ($comp,$wow,$bit){
 
   if($wow -eq 32 -and $bit -eq 64)
 
   {
           $wow64="\Wow6432Node"
   }
   else
 
   {
           $wow64=""
   }
   $regwmi=gwmi  -Namespace root\default -list -ComputerName $comp| where{$_.name -eq "StdRegProv"}
    $Uninstallkey="SOFTWARE$wow64\Microsoft\Windows\CurrentVersion\Uninstall"



$regwmi
$subkeys = $regwmi.EnumKey($HKLM, $Uninstallkey)
$subkeys=$subkeys.snames
 
 
foreach($key in $subkeys){

        $thisKey=$Uninstallkey+"\"+$key

    

        $obj = New-Object PSObject

        $obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $comp

        $obj | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $($regwmi.getstringvalue(2147483650,$thiskey,'DisplayName').svalue)

        $obj | Add-Member -MemberType NoteProperty -Name "DisplayVersion" -Value $($regwmi.getstringvalue(2147483650,$thiskey,'DisplayVersion').svalue)


        $obj | Add-Member -MemberType NoteProperty -Name "InstallLocation" -Value $($regwmi.getstringvalue(2147483650,$thiskey,'InstallLocation').svalue)


        $obj | Add-Member -MemberType NoteProperty -Name "Publisher" -Value $($regwmi.getstringvalue(2147483650,$thiskey,'Publisher').svalue)
      
        $obj | Add-Member -MemberType NoteProperty -Name "InstallDate" -Value $($regwmi.getstringvalue(2147483650,$thiskey,'InstallDate').svalue)
           $obj | Add-Member -MemberType NoteProperty -Name "Type" -Value $wow
        if($obj.installdate -match "[0-9]{8}")
        {
        $obj.Installdate=$obj.installdate.substring(4,2)+"/"+$obj.installdate.substring(6,2)+"/"+$obj.installdate.substring(0,4)}

        $obj
       # Write-host $obj

     #   $array += $obj

  
}
   }
Function Get-InstalledSoftware
{
param(
$Computername='localhost')

 
   $HKLM = 2147483650
 

 
 
$array=@( foreach($comp in $Computername)
{

$cpu=Get-WmiObject win32_Processor -Filter 'DeviceID="CPU0"'  -ComputerName $comp #-cred $cred
$bit=$cpu.AddressWidth
#"a $Comp"
if($bit -eq 64){

get-softwares -comp  $comp -wow 64 -bit $bit
get-softwares -comp $comp -wow 32 -bit $bit
   }
   else{
   get-softwares -computername $compp -wow 32 -bit $bit}
  
})
#$properties=$obj |get-member |  where{$_.membertype -eq "Noteproperty"} | foreach{$_.name}
#[string]::join(",",$properties)
#$values=$obj.properties
$array | Where-Object { $_.DisplayName -ne "" -and $_.displayname -ne $null}
#foreach{[string]::join(",",@(foreach($p in $properties){$_.$p}))}

 }

Above script can be called as  Get-InstalledSoftware -Computername comp1, comp2