Tuesday, November 8, 2011

ESX or Linux update Automation for windows users: su root and password

Today, I improved an old post. (I recommend you to read it before this post)
These scripts work correctly but for security reasons I could not use this work. Indeed, we must log before with an user then su in root. Moreover, with these previous scripts, that was not possible to transfert any other files like binaries files. So I decided to work on this problem to avoid to manually update 150 esx.
Sure, some trick exist like "expect" (not included in esx) or cpan perl expect, but it was simpliest to me to improve my scripts.

To use my scripts, just create a file yourfile.zip containing a script yourfile.sh and all needed files
process of these scripts:
script use a computer listing file (here servers.txt file) including all your computers you need to update
Script upload on your esx or linux computers yourfile.zip to /tmp directory, then decompress yourfile.zip and run yourfile.sh file

In update_esx_v2.zip, I give you a script example which permit you to update ESX with 2 patchs
[EDIT 15 february 2012] I re-upload zip file and add some informations in this post

In update.zip, file update.sh script contains all commands to do update
#!/bin/sh
# Update
cd ESX350-201012404-BG/
esxupdate --nosig update
cd ..
cd ESX350-201012410-BG/
esxupdate --nosig update
cd ..
In update.zip, there is also all necessary files used by update.sh

update\
update\update.sh
update\ESX350-201012404-BG\
update\ESX350-201012404-BG\contents.xml
update\ESX350-201012404-BG\contents.xml.sig
update\ESX350-201012404-BG\descriptor.xml
update\ESX350-201012404-BG\VMware-esx-scripts-3.5.0-317866.i386.rpm
update\ESX350-201012404-BG\headers\
update\ESX350-201012404-BG\headers\contents.xml
update\ESX350-201012404-BG\headers\contents.xml.sig
update\ESX350-201012404-BG\headers\header.info
update\ESX350-201012404-BG\headers\VMware-esx-scripts-0-3.5.0-317866.i386.hdr
update\ESX350-201012410-BG\
update\ESX350-201012410-BG\contents.xml
update\ESX350-201012410-BG\contents.xml.sig
update\ESX350-201012410-BG\descriptor.xml
update\ESX350-201012410-BG\vmware-keying-data-1-20100930.noarch.rpm
update\ESX350-201012410-BG\headers\
update\ESX350-201012410-BG\headers\contents.xml
update\ESX350-201012410-BG\headers\contents.xml.sig
update\ESX350-201012410-BG\headers\header.info
update\ESX350-201012410-BG\headers\vmware-keying-data-0-1-20100930.noarch.hdr



Now, you can run "run_update.cmd" which run your updates with user esxadmin
(only if this user can do all that you want - if user to connect your esx is not esxadmin change line with set usern=esxadmin)
@echo off
set usern=esxadmin
set zipfile=update.zip
set computerfile=servers.txt

if "%1"=="" goto :nopass
set password=%1

cscript //nologo update_esx.vbs %computerfile% %zipfile% %usern% %password%
goto :eof

:nopass
echo you need a password for user %usern%
goto :eof

To run your update with user esxadmin then su root
@echo off
set usern=esxadmin
set userroot=root
set zipfile=update.zip
set computerfile=servers.txt

if "%1"=="" goto :nopass
if "%2"=="" goto :nopass2
set password=%1
set pwdroot=%2

cscript //nologo update_esx.vbs %computerfile% %zipfile% %usern% %password% %userroot% %pwdroot%
goto :eof

:nopass
echo you need a password for user %usern%
goto :eof

:nopass2
echo you need a password for user %userroot% 
goto :eof

all computers to update are in file servers.txt below
computer1
computer2
computer3

Main script update_esx.vbs that permit to transfert and decompress "yourfile.zip" and execute "yourfile.sh" on your linux or esx
'
' update_esx.vbs
'
' by F.RICHARD
'
' v1.00 2007 Nov - Initial release
' v1.01 2008 Jan - Display Standard output
' v2.00 2011 Nov - Modify script to use and send ZIP file
'
Option Explicit

Const ForReading = 1
Const ForWriting = 2

'
' Detect WScript or CScript
'
If InStr(LCase(WScript.FullName), "wscript")>0 Then  ' ex: FullName = C:\WINNT\system32\wscript.exe 
 WScript.Echo "This script must be run under CScript."
 WScript.Quit
End If

'
' Get Command Line Args
'
Dim Args
Set Args = Wscript.Arguments
If Args.Count < 4 Then
 Wscript.Echo "Syntax : " & WScript.ScriptName & " input_computer_list_file zip_file_to_send_uncompress_and_execute user password"
 Wscript.Echo "Syntax : " & WScript.ScriptName & " input_computer_list_file zip_file_to_send_uncompress_and_execute user password [root] [root password]"
 Wscript.Echo "         Example : cscript " & WScript.ScriptName & " servers.txt myfile.zip user password"
 Wscript.Echo "         Example : cscript " & WScript.ScriptName & " servers.txt myfile.zip user password root rootpass"
 Wscript.Echo ""
 Wscript.Echo "computer_list_file: line begin by # or ; indicate start of a comment, everything after is ignored"
 Wscript.Echo ""
 Wscript.Quit
End If


' Args(0) = computer list
Dim strInputList
strInputList = Trim(args(0))

' Args(1) = zip file to send and execute
Dim strScriptToExecute, strCompressFile, strDirectory, strCompressFileExt
strCompressFile = Trim(args(1))
strCompressFileExt = Right(strCompressFile, Len(strCompressFile)-InStr(1, strCompressFile, ".") )
If (StrComp(strCompressFileExt, "zip", vbTextCompare) <> 0) Then
 WScript.Echo "File to send: '" & strCompressFile & "'is not a .zip file"
 WScript.Quit
End If
strDirectory = Left(strCompressFile, InStr(1, strCompressFile, ".")-1)
strScriptToExecute = strDirectory & ".sh"

' Args(2) = user
Dim strUser
strUser = Trim(args(2))

' Args(3) = password
Dim strPassword
strPassword = Trim(args(3))

' Args(4) = root name
' Args(5) = root password
Dim strRootPassword, strRootName
If Args.Count > 5 Then
 strRootName = Trim(args(4))
 strRootPassword = Trim(args(5))
End If


'
' Get Path
'
Dim strScriptFullName, strScriptPath
strScriptFullName = WScript.ScriptFullName ' ex: C:\Program Files\MyFolder\MyProg.exe
strScriptPath = Left(strScriptFullName, InStrRev(strScriptFullName, "\") - 1) ' ex: C:\Program Files\MyFolder

Dim objFso
Set objFso = CreateObject("Scripting.FileSystemObject")


'
' Test If all Files Exist
'
If Not isFileExist(strInputList) Then
 strInputList = strScriptPath & "\" & strInputList
 If Not isFileExist(strInputList) Then
  WScript.Echo "Computer list:" & strInputList & " File Not Exist !"
  WScript.Quit
 End If   
End If   
WScript.Echo "Computer list:" & strInputList & " File Exist"

If Not isFileExist(strCompressFile) Then
 strCompressFile = strScriptPath & "\" & strCompressFile
 If Not isFileExist(strCompressFile) Then
  WScript.Echo "Compress file:" & strCompressFile & """" & " File Not Exist !"
  WScript.Quit
 End If   
End If   
WScript.Echo "Script to uncompress:" & strCompressFile & " File Exist"

Dim strPlink
strPlink= strScriptPath & "\" & "plink.exe"
If Not isFileExist(strPlink) Then
 WScript.Echo "PuTTY Link:" & strPlink & " File Not Exist !"
 WScript.Quit
End If     
WScript.Echo "PuTTY Link:" & strPlink & " File Exist"

Dim strPscp
strPscp= strScriptPath & "\" & "pscp.exe"
If Not isFileExist(strPscp) Then
 WScript.Echo "PuTTY Secure Copy client:" & strPscp & " File Not Exist !"
 WScript.Quit
End If     
WScript.Echo "PuTTY Secure Copy client:" & strPscp & " File Exist"


Dim objShell, ComSpec
Set objShell = CreateObject( "WScript.Shell" )
ComSpec=objShell.ExpandEnvironmentStrings("%ComSpec%")

'
' Read computer list file into dictionary
'
Dim objDictionary, return
return = ReadFileToDict(strInputList, objDictionary)
If return = 0 Then
 WScript.Echo "Error during computer list file read"
 WScript.Quit
End If


'
' Generate .sh file to execute
'
Dim strContent, strScriptToDecFile
strScriptToDecFile = "decfile.sh"
strContent = "#!/bin/sh" & vbLf & _
 "# Unzip " & strCompressFile & " then enter in " & strDirectory & " directory and execute " & strScriptToExecute & " file" & vbLf & _
 "cd /tmp" & vbLf & _
 "unzip -o " & strCompressFile & vbLf
return = WriteStrToFile(strScriptToDecFile, strContent)


' Display file
Dim objItem, strServer, objCmd, strCmdline, continue, strGenerateKey
For Each objItem in objDictionary
 strServer = objDictionary.Item(objItem)
 Wscript.Echo ""
 WScript.Echo "Server:" & strServer
 
 ' Test Connection
 strCmdline = ComSpec & " /c """ & strPlink & """ -batch -C -pw " & strPassword & " " & strUser & "@" & strServer & " pwd "
 strGenerateKey = ComSpec & " /c echo y | """ & strPlink & """ " & strServer & " -pw " & strPassword & " " & strUser

 WScript.Echo "Test Connection on server " & strServer
 return = DoConnection(strCmdline, strGenerateKey, strServer, True)

 If (return > 0) Then
  strGenerateKey=""
  Do
   WScript.Echo "Re-verify Connection on server " & strServer
   return = DoConnection(strCmdline, strGenerateKey, strServer, True)
  Loop While (return > 0 and return < 255)
  If (return > 0) Then
   WScript.Echo "Transfer " & strScriptToDecFile & " script on server " & strServer
   strCmdline = ComSpec & " /c """ & strPscp & """ -batch -C -pw " & strPassword & " " & strScriptToDecFile & " " & strUser & "@" & strServer & ":/tmp"
   return = DoConnection(strCmdline, strGenerateKey, strServer, True)

   WScript.Echo "Transfer " & strCompressFile & " script on server " & strServer
   strCmdline = ComSpec & " /c """ & strPscp & """ -batch -C -pw " & strPassword & " " & strCompressFile & " " & strUser & "@" & strServer & ":/tmp"
   return = DoConnection(strCmdline, strGenerateKey, strServer, True)

   WScript.Echo "Execute " & strScriptToDecFile & " script on server " & strServer
   strCmdline = ComSpec & " /c """ & strPlink & """ -batch -C -pw " & strPassword & " " & strUser & "@" & strServer & " " & "cd /tmp; sh " & strScriptToDecFile
   return = DoConnection(strCmdline, strGenerateKey, strServer, True)

   ' if root / or not root
   If Args.Count > 5 Then

    objShell.Run "putty.exe -ssh " & strUser & "@" & strServer
    WScript.Sleep 5000
    objShell.AppActivate strServer & " - PuTTY"
    WScript.Sleep 5000
    objShell.SendKeys "" &  strPassword & "{ENTER}"
    WScript.Sleep 5000     
    objShell.SendKeys "su - " & strRootName & "{ENTER}"
    WScript.Sleep 5000     
    objShell.SendKeys "" & strRootPassword & "{ENTER}"
    WScript.Sleep 5000     
    objShell.SendKeys "cd /tmp/" & strDirectory & "; sh " & strScriptToExecute & "{ENTER}"
    WScript.Sleep 5000     
   Else
    WScript.Echo "Execute " & strScriptToExecute & " script on server " & strServer
    strCmdline = ComSpec & " /c """ & strPlink & """ -batch -C -pw " & strPassword & " " & strUser & "@" & strServer & " " & "cd /tmp/" & strDirectory & "; sh " & strScriptToExecute
    return = DoConnection(strCmdline, strGenerateKey, strServer, True)
   End If
  End If
 End If

Next



'
' Quit
'
WScript.Sleep 1000
WScript.Quit

'--------------------

' DoConnection
'
' 
'
Function DoConnection(strCmdline, strGenerateKey, strServer, displayLogfile)
 Dim objCmd, return, Continue

 'WScript.Echo "cmdline->" & strCmdline
 Set objCmd = objShell.Exec(strCmdline)
 Do While objCmd.Status = 0
  return = objCmd.stdErr.ReadAll
  WScript.Sleep 100
 Loop
 If (displayLogfile) Then
  Dim strStdOut
  strStdOut = objCmd.StdOut.ReadAll()
  If (len(strStdOut) > 0) Then
   Wscript.Echo strStdOut
  End If
 End If

 continue = 0
 If Instr(return, "Access denied" ) > 0 Then ' Access denied
  WScript.Echo "ERROR on server " & strServer & vbCrLf & return
  continue = 0

 Elseif Instr(return, "Unable to open connection" ) > 0 Then ' Unable to open connection
  WScript.Echo "ERROR on server " & strServer & vbCrLf & return
  continue = 0

 Elseif Instr(return, "ERROR" ) > 0 Then ' FATAL ERROR: Network error: Connection timed out
  WScript.Echo "ERROR on server " & strServer & vbCrLf & return
  continue = 0

 Elseif Instr(return, "fingerprint" ) > 0 Then
  If (len(strGenerateKey) > 2) Then
   WScript.Echo "GENERATE key fingerprint on server " & strServer
   'WScript.Echo "generatekey->" & strGenerateKey
   objShell.Exec(strGenerateKey)
   continue = 1
  Else
   WScript.Echo "NOT GENERATE key fingerprint " & strServer
   continue = 2
  End If
 Else
  continue = 255
  'WScript.Echo "Logged on " & strServer & " - " & return
 End if

 DoConnection = continue
End Function



'--------------------

' isFileExist
'
' Test if File Exist
'
Function IsFileExist(strInputFile)
 Dim objFSO
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 If Not objFSO.FileExists(strInputFile) Then
  Wscript.echo strInputFile & " file not exist !"
  IsFileExist = False
 Else
  IsFileExist = True
 End If
End Function


'--------------------

' ReadFileToDict
'
' Read each line -> put in Dictionary
' strInputfile = file to read
' objDictionary = dictionary for results
'
Function ReadFileToDict(strInputFile, ByRef objDictionary)
 Dim objFSO, objTextFile, strNextLine, i
 Set objDictionary = CreateObject("Scripting.Dictionary")
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 If isFileExist(strInputFile) Then
  Set objTextFile = objFSO.OpenTextFile(strInputFile, ForReading)
  i = 0
  Do Until objTextFile.AtEndOfStream
   strNextLine = Trim(objTextFile.Readline)
   If ( (Not Left(strNextLine, 1) = "#") _
    and (Not Left(strNextLine, 1) = ";") _
    and (Len(strNextLine)>1) _
    ) Then
    objDictionary.Add i, strNextLine
    i = i + 1
   End If
  Loop
  objTextFile.Close
  ReadFileToDict = True
 Else
  ReadFileToDict = False
 End If
End Function


'--------------------

' WriteStrToFile
'
' Write string to file
' strOutputFile = file to write
' strContent = string to write
'
Function WriteStrToFile(strOutputFile, ByRef strContent)
 Dim objFSO, objTextFile
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 Set objTextFile = objFSO.CreateTextFile(strOutputFile, True)  ' delete file
 objTextFile.Write(strContent)
 objTextFile.Close
End Function


'--------------------

Thursday, August 4, 2011

Check your Onboard Administrator / Virtual Connect password

If you want to check your Onboard Administrator / Virtual Connect password, or test some passwords, because you don't really remember the real good one, I modified my previous script Plink_reg.cmd to make work for you.

For this, just change line 43 to 47 in file Plink_reg.cmd (or download TestOAVCPass.zip)

Echo Reg plink %1 (%date% %time%)
Echo ----------------------------- >> %LOGFILE% 2>>&1
Echo Reg plink %1 (%date% %time%) >> %LOGFILE% 2>>&1
plink.exe -ssh -l %2 -pw %3 -batch %1 "exit" >> %LOGFILE% 2>>&1
goto :EOF

with these lines

Echo Reg plink %1 (%date% %time%)
Echo ----------------------------- >> %LOGFILE% 2>>&1
Echo Reg plink %1 (%date% %time%) %2 %3 >> %LOGFILE% 2>>&1
plink.exe -ssh -l %2 -pw %3 -batch %1 "exit" > temp.txt 2>>&1
set passok=PASSWORD_KO
type temp.txt | findstr /i denied
if errorlevel 1 set passok=PASSWORD_IN_THIS_LINE
Echo ;%date% %time%;%1;%2;%3;%passok% >> resultpass.txt
goto :EOF


For example, to test password password1,password2,password3 and password4 in oa or vc with ip address 192.1.1.100 use a file "myipass.txt" with these entries:

192.1.1.100;manager;password1
192.1.1.100;manager;password2
192.1.1.100;manager;password3
192.1.1.100;manager;password4


Run "TestOAVCPass.exe myipass.txt" then you should have result like below (here password3 is the good oa password)

;31/07/2011 12:23:07,26;192.1.1.100;manager;password1;PASSWORD_KO
;31/07/2011 12:23:10,10;192.1.1.100;manager;password2;PASSWORD_KO
;31/07/2011 12:23:11,49;192.1.1.100;manager;password3;PASSWORD_IN_THIS_LINE
;31/07/2011 12:23:13,94;192.1.1.100;manager;password4;PASSWORD_KO

Saturday, July 2, 2011

Check your ip/computername with nslookup in powershell

Nslookup is a great tool for testing and troubleshooting. However, if you need to check a large range of IP/Computername in mass, nslookup is not the better choice. So, this below script could help you to do the same in powershell. (Download script)


#
# NSLookup
#
# by F.Richard 2011-05
#


# ***********************************************

Function NSlookup {
Param($hostname)
#$iphostEntry = [System.Net.Dns]::GetHostEntry($hostname)
# Rexolve obsolete but better than GetHostEntry
$iphostEntry = [System.Net.Dns]::Resolve($hostname)
$line = $iphostEntry.HostName

$strSeparator = ";"
foreach ($addr in $iphostEntry.AddressList) {
$line = $line + $strSeparator + $Addr.IPAddressToString
$strSeparator = "|"
}

$strSeparator = ";"
foreach ($alias in $iphostEntry.aliases) {
$line = $line + $strSeparator + $alias
$strSeparator = "|"
}

return $line
}



# ***********************************************

Function TestFile {
Param(
[String] $strFilename,
[String] $strCurDir
)
if ($strFilename) {
$strCurDir = $(if ($strCurDir) {$strCurDir} else {if ($MyInvocation.MyCommand.CommandType -eq "Function") {(Get-Location).Path} else {Split-Path -parent $MyInvocation.MyCommand.Path} })
If ((Test-Path("$strFilename")) -eq $False){
If ($strFilename.ToUpper().Contains($strCurDir.ToUpper()) ) {
Write-Host "ERROR: file $strFilename NOT exist"
return
} Else {
If ((Test-Path("$strCurDir\$strFilename")) -eq $False){
Write-Host "ERROR: file $strFilename NOT exist"
Write-Host "ERROR: file $strCurDir\$strFilename NOT exist"
return
} Else {
$strFilename = "$strCurDir\$strFilename"
}
}
}
return $strFilename
}
}


# ***********************************************

Function GetFileIntoArr {
Param(
[String] $strFilename,
[String] $strCurDir,
[Ref]$arrFile,
[String] $strComment
)
$strComment = $(if ($strComment) {$strComment} else {"#"})
$strCurDir = $(if ($strCurDir) {$strCurDir} else {if ($MyInvocation.MyCommand.CommandType -eq "Function") {(Get-Location).Path} else {Split-Path -parent $MyInvocation.MyCommand.Path} })

$retFilename = TestFile -strFilename $strFilename -strCurDir $strCurDir
if ($retFilename) {
$Content = Get-Content "$retFilename"
Foreach ($line in $Content) {
$comment = $False
If ($line.Trim().length -gt 0) { # take only line with data and without # at begininng of the line
# if we do not want to use comment
If ($strComment -eq "#") {
If ($line.substring(0,1) -eq "#") {
$comment = $True
}
}
If ($comment -eq $False) {
# Get Search & Replace
$arrFile.Value += $line.Trim()
}
}
}
return $True
} else {
return $False
}
}

# ***********************************************

#
# MAIN PROGRAM
#

# Verify Arguments Number
If($Args.Count -lt 2) {
Write-Host "Syntax:"$MyInvocation.MyCommand.Name "inputfilename outputfilename"
Write-Host " Example:"$MyInvocation.MyCommand.Name" 'inputfile.txt' 'outputfile.txt' "
Write-Host " Example:"$MyInvocation.MyCommand.Name" -inputfile 'inputfile.txt' -outputfile 'outputfile.txt' "
Write-Host
Break
}

$inputfile = $args[0]
$outputfile = $args[1]
$date = get-date -format "yyyy-MM-dd"
$Content = "#Date;Computer;Hostname;IP`r`n"
$Content | Out-File -encoding ASCII $outputfile
[Array] $arrComputers = @( )

if ($inputfile) {
if (!(GetFileIntoArr -strFilename $inputfile -arrFile ([Ref]$arrComputers))) {
Break
}
} else {
Write-Host "ERROR: you need a filename.txt as second parameter inputfile"
Break
}
Foreach ($computer in $arrComputers) {
$nslookup = NSlookup($computer)
$line = $date + ";" + $computer + ";" + $nslookup
#+ "`r`n"
Write-Host $line
$line | Out-File -append -encoding ASCII $outputfile
}


Example of Result:

#Date;Computer;Hostname;IP
2011-06-01;COMPUTER1;computer1.dns1.my.net;192.1.1.45;COMPUTER1.dns2.my.net
2011-06-01;COMPUTER2;COMPUTER2.si.net;192.1.1.100
2011-06-01;COMPUTER3;COMPUTER3.si.net;192.1.1.101
2011-06-01;COMPUTER4;COMPUTER4.si.net;192.1.102

Wednesday, June 29, 2011

Find your VMware local VMFS datastore with powershell

To find your local VMFS datastore

Solution 1: name all your local vmfs LOCAL_xxx
Get all your local datastore by using
Get-Datastore | Get-View | Where-Object { $_.Name -match "LOCAL_*" } | Select-Object  @{n="Name";e={$_.Name}}}

Name
----
LOCAL_ESX01
LOCAL_ESX02
LOCAL_ESX03



Solution 2: use MultipleHostAccess info from Get-Datastore
(Thanks to http://blogs.vmware.com/vipowershell/2009/08/how-to-list-datastores-that-are-on-shared-storage.html?cid=6a00d8341c328153ef0120a52e7f0b970b for MultipleHostAccess tip)
You can use this:
Get-Datastore | Get-View | Select-Object  @{n="Name";e={$_.Name}}, @{n="San_Nas";e={$_.Summary.MultipleHostAccess}}

Name San_Nas
---- -------
NFS_VOL2 True
LOCAL_ESX01 False
NFS_VOL1 True
LOCAL_ESX02 False
LOCAL_ESX03 False



Solution 3: use Vendor / Model SCSILun informations from VMHost get-view
Get-VMHost | Get-View | Foreach-Object { $vmhost=$_.Name; $_.Config.StorageDevice.ScsiLun |  Select-Object @{n="Hostname";e={$vmhost}},@{n="Model";e={$_.Model}},@{n="Vendor";e={$_.Vendor}} }


Hostname Model Vendor
-------- ----- ------
esx01 LOGICAL VOLUME HP
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx01 SYMMETRIX EMC
esx02 RAID 5 DGC
esx02 SYMMETRIX EMC
esx02 SYMMETRIX EMC
esx02 RAID 5 DGC
esx03 LOGICAL VOLUME HP
esx03 2810XIV IBM
esx03 2810XIV IBM
esx03 2810XIV-LUN-0 IBM
esx03 2810XIV IBM



Example of SAN vendor/model
Vendor / Model
VMware / Block device
EMC / SYMMETRIX
IBM / 2810XIV

Example of Local storage
Vendor / Model
HP / LOGICAL VOLUME
DGC / RAID 5

Friday, June 17, 2011

Optimize your vmware powershell: part 1 - Get-Datacenter

Remember Get-Datacenter | Get-View = Get-View -ViewType Datacenter
For better performance, use
Get-View -ViewType
Use "-Property property1,property2,property3" switch if you don't need all properties. Less data to take = better performance too.

Execution time results after the execution of some commands:

Command

seconds

Get-View -ViewType Datacenter -Property Name

0,093652985

Get-View -ViewType Datacenter

0,128286732

Get-Datacenter

0,190378198

Get-Datacenter | Get-View

0,241663792

Get-View -ViewType Datacenter -Property Name | Foreach-Object { Get-VIObjectByVIView $_.MoRef }

0,296987547

Get-View -ViewType Datacenter | Foreach-Object { Get-VIObjectByVIView $_.MoRef

0,342440257



Get-Datastore fields and its equivalent fields with Get-View

Command

Equivalent Fields

$dc0 = Get-Datacenter | Where-Object { $_.Name -eq "Datacenter_1" }

$dc1 = Get-View -ViewType Datacenter | Where-Object { $_.Name -eq "Datacenter_1" }

$dc0.ExtensionData

$dc1

$dc0.Name

$dc1.Name

$dc0.Id

$dc1.MoRef

$dc0.ParentFolderId

$dc1.Parent

$dc0.CustomFields

[Array] $arrFields = @()
$dc1 | Foreach-Object {
$datacenter = $_
$datacenter.AvailableField | Foreach-Object {
$availablefield = $_
$Key = $availablefield.Name
$Value = ($datacenter.CustomValue | Where-Object { $_.Key -eq $availablefield.Key}).Value

$objParent = New-Object PSObject
$objParent | Add-Member -MemberType noteproperty -Name "Key" -Value $key
$objParent | Add-Member -MemberType noteproperty -Name "Value" -Value $value
$arrFields += $objParent
}
}

$arrFields

Another way to improve your scripts: use -Filter switch when you want specific data. Some lines can also be better than 1 cmdlets , but it's not always the case (see below)

Command

seconds

#Equivalent

#Get-Datacenter -Name Datacenter_2

Get-View -ViewType Datacenter -Filter @{"Name"="Datacenter_2"}

0,11421332

#Equivalent

#Get-Datacenter -Name Datacenter_2

Get-View -ViewType Datacenter | Where-Object { $_.Name -eq "Datacenter_2" }

0,13915101

Get-Datacenter -Name Datacenter_2

0,18590567

Get-Datacenter -Id Datacenter-datacenter-3472

0,18141816

Get-Datacenter -Cluster Cluster_2

0,37470311

#Equivalent

# Get-Datacenter -Cluster Cluster_2

$cluster=" Cluster_2"

$parent = (Get-View -ViewType ComputeResource -Filter @{"Name"=$cluster} -Property Parent).Parent.ToString()

While ($parent.ToString().Substring(0,5).ToUpper() -ne "DATAC") {

$parent = (Get-View -ViewType Folder -Property Parent | Where-Object { $_.MoRef.ToString() -eq $parent}).Parent.ToString()

}

Get-Datacenter -Id $parent

0,4999502

Get-Datacenter -VMHost ESX01

0,8159789

#Equivalent

# Get-Datacenter -VMHost ESX01

$parent = (Get-View -ViewType HostSystem -Filter @{"Name"=" ESX01"} -Property Parent).Parent.ToString()

If ($parent.ToString().Substring(0,5).ToUpper() -eq "CLUST") {

$parent = (Get-View -ViewType ComputeResource -Property Parent | Where-Object { $_.MoRef.ToString() -eq $parent}).Parent.ToString()

}

While ($parent.ToString().Substring(0,5).ToUpper() -ne "DATAC") {

$parent = (Get-View -ViewType Folder -Property Parent | Where-Object { $_.MoRef.ToString() -eq $parent}).Parent.ToString()

}

Get-Datacenter -Id $parent

0,7234534

#Equivalent

# Get-Datacenter -VM VM01

$vm=" VM01"

$parent = (Get-View -ViewType VirtualMachine -Filter @{"Name"=$vm} -Property Parent).Parent.ToString()

While ($parent.ToString().Substring(0,5).ToUpper() -ne "DATAC") {

$parent = (Get-View -ViewType Folder -Property Parent | Where-Object { $_.MoRef.ToString() -eq $parent}).Parent.ToString()

}

Get-Datacenter -Id $parent

0,6182902

Get-Datacenter -VM VM01

5,26492918



Some cmdlets result properties

[vSphere PowerCLI]> Get-Datacenter | select *

ParentFolderId : Folder-group-d1
ParentFolder : Datacenters
CustomFields : {}
ExtensionData : VMware.Vim.Datacenter
Id : Datacenter-datacenter-3472
Name : Datacenter_2
Uid : /VIServer=@localhost:443/Datacenter=Datacenter-datacenter-3472/

ParentFolderId : Folder-group-d1
ParentFolder : Datacenters
CustomFields : {}
ExtensionData : VMware.Vim.Datacenter
Id : Datacenter-datacenter-10
Name : Datacenter_1
Uid : /VIServer=@localhost:443/Datacenter=Datacenter-datacenter-10/


[vSphere PowerCLI]> Get-View -ViewType Datacenter


VmFolder : Folder-group-v11
HostFolder : Folder-group-h12
DatastoreFolder :
NetworkFolder :
Datastore : {Datastore-datastore-123, Datastore-datastore-233, Datastore-datastore-235, Datastore-datastore-237...}
Network : {Network-network-1634, Network-network-1636, Network-network-6006, Network-network-3456...}
Parent : Folder-group-d1
CustomValue : {}
OverallStatus : gray
ConfigStatus : gray
ConfigIssue : {}
EffectiveRole : {-1}
Permission : {113, 113, -5, -2...}
Name : Datacenter_1
DisabledMethod : {}
RecentTask : {}
DeclaredAlarmState : {alarm-1.datacenter-10, alarm-2.datacenter-10, alarm-3.datacenter-10, alarm-4.datacenter-10...}
TriggeredAlarmState : {alarm-3.host-184, alarm-3.host-3310, alarm-3.host-3834, alarm-3.host-5972...}
AlarmActionsEnabled : False
Tag :
Value : {}
AvailableField : {}
MoRef : Datacenter-datacenter-10
Client : VMware.Vim.VimClient

VmFolder : Folder-group-v3473
HostFolder : Folder-group-h3474
DatastoreFolder :
NetworkFolder :
Datastore : {Datastore-datastore-3554, Datastore-datastore-3556, Datastore-datastore-3558, Datastore-datastore-3560...}
Network : {Network-network-9660, Network-network-6759, Network-network-6761, Network-network-6760...}
Parent : Folder-group-d1
CustomValue : {}
OverallStatus : gray
ConfigStatus : gray
ConfigIssue : {}
EffectiveRole : {-1}
Permission : {107, 107, 107, 107...}
Name : Datacenter_2
DisabledMethod : {}
RecentTask : {}
DeclaredAlarmState : {alarm-1.datacenter-3472, alarm-2.datacenter-3472, alarm-3.datacenter-3472, alarm-4.datacenter-3472...}
TriggeredAlarmState : {alarm-3.host-11857, alarm-3.host-11873, alarm-3.host-6439, alarm-4.vm-9648}
AlarmActionsEnabled : False
Tag :
Value : {}
AvailableField : {}
MoRef : Datacenter-datacenter-3472
Client : VMware.Vim.VimClient

[vSphere PowerCLI]> Get-Datacenter | Where-Object { $_.Name -eq "Datacenter_1" } | Get-Member

TypeName: VMware.VimAutomation.ViCore.Impl.V1.Inventory.DatacenterImpl

Name MemberType Definition
---- ---------- ----------
ConvertToVersion Method ConvertToVersion()
Equals Method System.Boolean Equals(Object obj)
GetHashCode Method System.Int32 GetHashCode()
GetHostFolder Method VMware.VimAutomation.ViCore.Interop.V1.Inventory.FolderInterop GetHostFolder()
GetType Method System.Type GetType()
GetVmFolder Method VMware.VimAutomation.ViCore.Interop.V1.Inventory.FolderInterop GetVmFolder()
get_CustomFields Method System.Collections.Generic.IDictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] get_CustomFields()
get_ExtensionData Method System.Object get_ExtensionData()
get_Id Method System.String get_Id()
get_Name Method System.String get_Name()
get_ParentFolder Method VMware.VimAutomation.ViCore.Types.V1.Inventory.Folder get_ParentFolder()
get_ParentFolderId Method System.String get_ParentFolderId()
get_Uid Method System.String get_Uid()
IsConvertableTo Method System.Boolean IsConvertableTo(Type toType)
ToString Method System.String ToString()
CustomFields Property System.Collections.Generic.IDictionary`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] CustomFields {get;}
ExtensionData Property System.Object ExtensionData {get;}
Id Property System.String Id {get;}
Name Property System.String Name {get;}
ParentFolder Property VMware.VimAutomation.ViCore.Types.V1.Inventory.Folder ParentFolder {get;}
ParentFolderId Property System.String ParentFolderId {get;}
Uid Property System.String Uid {get;}

[vSphere PowerCLI]>Get-View -ViewType Datacenter | Where-Object { $_.Name -eq "Datacenter_1"   } | Get-Member

TypeName: VMware.Vim.Datacenter

Name MemberType Definition
---- ---------- ----------
Destroy Method System.Void Destroy()
Destroy_Task Method VMware.Vim.ManagedObjectReference Destroy_Task()
Equals Method System.Boolean Equals(Object obj)
GetAllEventsView Method VMware.Vim.EventHistoryCollector GetAllEventsView(EventFilterSpec eventFilterSpec)
GetAllTasksView Method VMware.Vim.TaskHistoryCollector GetAllTasksView(TaskFilterSpec taskFilterSpec)
GetEntityOnlyEventsCollectorView Method VMware.Vim.EventHistoryCollector GetEntityOnlyEventsCollectorView(EventFilterSpec eventFilterSpec)
GetEntityOnlyTasksCollectorView Method VMware.Vim.TaskHistoryCollector GetEntityOnlyTasksCollectorView(TaskFilterSpec taskFilterSpec)
GetEventCollectorView Method VMware.Vim.EventHistoryCollector GetEventCollectorView(EventFilterSpecRecursionOption recursionOption, EventFilterSpec eventFilterSpec)
GetHashCode Method System.Int32 GetHashCode()
GetTaskCollectorView Method VMware.Vim.TaskHistoryCollector GetTaskCollectorView(TaskFilterSpecRecursionOption recursionOption, TaskFilterSpec taskFilterSpec)
GetType Method System.Type GetType()
get_AlarmActionsEnabled Method System.Boolean get_AlarmActionsEnabled()
get_AvailableField Method VMware.Vim.CustomFieldDef[] get_AvailableField()
get_Client Method VMware.Vim.VimClient get_Client()
get_ConfigIssue Method VMware.Vim.Event[] get_ConfigIssue()
get_ConfigStatus Method VMware.Vim.ManagedEntityStatus get_ConfigStatus()
get_CustomValue Method VMware.Vim.CustomFieldValue[] get_CustomValue()
get_Datastore Method VMware.Vim.ManagedObjectReference[] get_Datastore()
get_DatastoreFolder Method VMware.Vim.ManagedObjectReference get_DatastoreFolder()
get_DeclaredAlarmState Method VMware.Vim.AlarmState[] get_DeclaredAlarmState()
get_DisabledMethod Method System.String[] get_DisabledMethod()
get_EffectiveRole Method System.Int32[] get_EffectiveRole()
get_HostFolder Method VMware.Vim.ManagedObjectReference get_HostFolder()
get_MoRef Method VMware.Vim.ManagedObjectReference get_MoRef()
get_Name Method System.String get_Name()
get_Network Method VMware.Vim.ManagedObjectReference[] get_Network()
get_NetworkFolder Method VMware.Vim.ManagedObjectReference get_NetworkFolder()
get_OverallStatus Method VMware.Vim.ManagedEntityStatus get_OverallStatus()
get_Parent Method VMware.Vim.ManagedObjectReference get_Parent()
get_Permission Method VMware.Vim.Permission[] get_Permission()
get_RecentTask Method VMware.Vim.ManagedObjectReference[] get_RecentTask()
get_Tag Method VMware.Vim.Tag[] get_Tag()
get_TriggeredAlarmState Method VMware.Vim.AlarmState[] get_TriggeredAlarmState()
get_Value Method VMware.Vim.CustomFieldValue[] get_Value()
get_VmFolder Method VMware.Vim.ManagedObjectReference get_VmFolder()
PowerOnMultiVM Method VMware.Vim.ClusterPowerOnVmResult PowerOnMultiVM(ManagedObjectReference[] vm, OptionValue[] option)
PowerOnMultiVM_Task Method VMware.Vim.ManagedObjectReference PowerOnMultiVM_Task(ManagedObjectReference[] vm, OptionValue[] option)
QueryConnectionInfo Method VMware.Vim.HostConnectInfo QueryConnectionInfo(String hostname, Int32 port, String username, String password, String sslThumbprint)
Reload Method System.Void Reload()
Rename Method System.Void Rename(String newName)
Rename_Task Method VMware.Vim.ManagedObjectReference Rename_Task(String newName)
setCustomValue Method System.Void setCustomValue(String key, String value)
SetViewData Method System.Void SetViewData(ObjectContent objectContent, String[] properties)
ToString Method System.String ToString()
UpdateViewData Method System.Void UpdateViewData(Params String[] properties), System.Void UpdateViewData()
WaitForTask Method System.Object WaitForTask(ManagedObjectReference taskReference)
AlarmActionsEnabled Property System.Boolean AlarmActionsEnabled {get;}
AvailableField Property VMware.Vim.CustomFieldDef[] AvailableField {get;}
Client Property VMware.Vim.VimClient Client {get;}
ConfigIssue Property VMware.Vim.Event[] ConfigIssue {get;}
ConfigStatus Property VMware.Vim.ManagedEntityStatus ConfigStatus {get;}
CustomValue Property VMware.Vim.CustomFieldValue[] CustomValue {get;}
Datastore Property VMware.Vim.ManagedObjectReference[] Datastore {get;}
DatastoreFolder Property VMware.Vim.ManagedObjectReference DatastoreFolder {get;}
DeclaredAlarmState Property VMware.Vim.AlarmState[] DeclaredAlarmState {get;}
DisabledMethod Property System.String[] DisabledMethod {get;}
EffectiveRole Property System.Int32[] EffectiveRole {get;}
HostFolder Property VMware.Vim.ManagedObjectReference HostFolder {get;}
MoRef Property VMware.Vim.ManagedObjectReference MoRef {get;}
Name Property System.String Name {get;}
Network Property VMware.Vim.ManagedObjectReference[] Network {get;}
NetworkFolder Property VMware.Vim.ManagedObjectReference NetworkFolder {get;}
OverallStatus Property VMware.Vim.ManagedEntityStatus OverallStatus {get;}
Parent Property VMware.Vim.ManagedObjectReference Parent {get;}
Permission Property VMware.Vim.Permission[] Permission {get;}
RecentTask Property VMware.Vim.ManagedObjectReference[] RecentTask {get;}
Tag Property VMware.Vim.Tag[] Tag {get;}
TriggeredAlarmState Property VMware.Vim.AlarmState[] TriggeredAlarmState {get;}
Value Property VMware.Vim.CustomFieldValue[] Value {get;}
VmFolder Property VMware.Vim.ManagedObjectReference VmFolder {get;}

Sunday, June 5, 2011

GetSpecialFolderPath in Powershell

To complete "Enumerate your own enum in Powershell" post, I give you this below script to use GetSpecialFolderPath
(Download it)
You can remove # comment in this script if you need to see some examples of array or hashtable use


#
#
# GetSpecialFolderPath
#
# by F.Richard 2011-05
#
#

#Requires -Version 2.0


# CSIDL
# http://msdn.microsoft.com/en-us/library/bb762494%28v=vs.85%29.aspx
# for windows XP and later OS
# KNOWNFOLDERID
# http://msdn.microsoft.com/en-us/library/dd378457%28v=vs.85%29.aspx
# for Vista and later OS
# Recognized Environment Variables
# http://technet.microsoft.com/en-us/library/cc749104%28WS.10%29.aspx

# DllImport
$signature = @"
[DllImport("Shell32.dll")]
public static extern int SHGetSpecialFolderPath(UIntPtr hwndOwner, System.Text.StringBuilder lpszPath, CSIDL iCsidl, int fCreate);


public enum CSIDL : int {
CSIDL_DESKTOP = 0x0000,
CSIDL_INTERNET = 0x0001,
CSIDL_PROGRAMS = 0x0002,
CSIDL_CONTROLS = 0x0003,
CSIDL_PRINTERS = 0x0004,
CSIDL_PERSONAL = 0x0005,
CSIDL_FAVORITES = 0x0006,
CSIDL_STARTUP = 0x0007,
CSIDL_RECENT = 0x0008,
CSIDL_SENDTO = 0x0009,
CSIDL_BITBUCKET = 0x000a,
CSIDL_STARTMENU = 0x000b,
CSIDL_MYDOCUMENTS = CSIDL_PERSONAL,
CSIDL_MYMUSIC = 0x000d,
CSIDL_MYVIDEO = 0x000e,
CSIDL_DESKTOPDIRECTORY = 0x0010,
CSIDL_DRIVES = 0x0011,
CSIDL_NETWORK = 0x0012,
CSIDL_NETHOOD = 0x0013,
CSIDL_FONTS = 0x0014,
CSIDL_TEMPLATES = 0x0015,
CSIDL_COMMON_STARTMENU = 0x0016,
CSIDL_COMMON_PROGRAMS = 0x0017,
CSIDL_COMMON_STARTUP = 0x0018,
CSIDL_COMMON_DESKTOPDIRECTORY = 0x0019,
CSIDL_APPDATA = 0x001a,
CSIDL_PRINTHOOD = 0x001b,
CSIDL_LOCAL_APPDATA = 0x001c,
CSIDL_ALTSTARTUP = 0x001d,
CSIDL_COMMON_ALTSTARTUP = 0x001e,
CSIDL_COMMON_FAVORITES = 0x001f,
CSIDL_INTERNET_CACHE = 0x0020,
CSIDL_COOKIES = 0x0021,
CSIDL_HISTORY = 0x0022,
CSIDL_COMMON_APPDATA = 0x0023,
CSIDL_WINDOWS = 0x0024,
CSIDL_SYSTEM = 0x0025,
CSIDL_PROGRAM_FILES = 0x0026,
CSIDL_MYPICTURES = 0x0027,
CSIDL_PROFILE = 0x0028,
CSIDL_SYSTEMX86 = 0x0029,
CSIDL_PROGRAM_FILESX86 = 0x002a,
CSIDL_PROGRAM_FILES_COMMON = 0x002b,
CSIDL_PROGRAM_FILES_COMMONX86 = 0x002c,
CSIDL_COMMON_TEMPLATES = 0x002d,
CSIDL_COMMON_DOCUMENTS = 0x002e,
CSIDL_COMMON_ADMINTOOLS = 0x002f,
CSIDL_ADMINTOOLS = 0x0030,
CSIDL_CONNECTIONS = 0x0031,
CSIDL_COMMON_MUSIC = 0x0035,
CSIDL_COMMON_PICTURES = 0x0036,
CSIDL_COMMON_VIDEO = 0x0037,
CSIDL_RESOURCES = 0x0038,
CSIDL_RESOURCES_LOCALIZED = 0x0039,
CSIDL_COMMON_OEM_LINKS = 0x003a,
CSIDL_CDBURN_AREA = 0x003b,
CSIDL_COMPUTERSNEARME = 0x003d,
CSIDL_FLAG_CREATE = 0x8000,
CSIDL_FLAG_DONT_VERIFY = 0x4000,
CSIDL_FLAG_DONT_UNEXPAND = 0x2000,
CSIDL_FLAG_NO_ALIAS = 0x1000,
CSIDL_FLAG_PER_USER_INIT = 0x0800
}
"@



# Register shell32 functions
If (-not ("Shell32.Tools" -as [Type])) {
$type = Add-Type -MemberDefinition $signature -Name Tools -Namespace Shell32 -Using System.Text -PassThru
} else {
If ($debug) { Write-Host "Shell32.Tools already Registered" }
}
# Get Common Desktop Directory
$hwnd = New-Object UIntPtr
$lpData = New-Object System.Text.StringBuilder(260) # MAX_PATH = 256
$CSIDL = "CSIDL_COMMON_DESKTOPDIRECTORY"
if([Shell32.Tools]::SHGetSpecialFolderPath($hwnd, $lpData, $CSIDL, 0)) {
Write-Host $CSIDL "=" $lpData
}


# Enum To Array
$arrEnum=[Enum]::GetNames([Shell32.Tools+CSIDL])
# Remove remark to display name and value
#foreach ($name in $arrEnum) {
# Write-Host "Name:$name Value:"([Shell32.Tools+CSIDL]::$name).value__
#}


# Enum To Hash
$hashEnum = @{ }
[Enum]::GetValues([Shell32.Tools+CSIDL])| % {$hashEnum["$_"] = $_.value__ }
# Remove remark to display name and value
#foreach ($name in $hashEnum.keys) {
# Write-Host "Name:$name Value:"$hashEnum["$name"]
#}


foreach ($CSIDL in $arrEnum) {
if ([Shell32.Tools]::SHGetSpecialFolderPath($hwnd, $lpData, $CSIDL, 0)) {
Write-Host $CSIDL "=" $lpData
}
}


Windows 2003 english example results with myuser user


C:\> .\GetSpecialFolderPath.ps1
CSIDL_COMMON_DESKTOPDIRECTORY = C:\Documents and Settings\All Users\Desktop
CSIDL_DESKTOP = C:\Documents and Settings\myuser\Desktop
CSIDL_PROGRAMS = C:\Documents and Settings\myuser\Start Menu\Programs
CSIDL_PERSONAL = C:\Documents and Settings\myuser\My Documents
CSIDL_MYDOCUMENTS = C:\Documents and Settings\myuser\My Documents
CSIDL_FAVORITES = C:\Documents and Settings\myuser\Favorites
CSIDL_STARTUP = C:\Documents and Settings\myuser\Start Menu\Programs\Startup
CSIDL_RECENT = C:\Documents and Settings\myuser\Recent
CSIDL_SENDTO = C:\Documents and Settings\myuser\SendTo
CSIDL_STARTMENU = C:\Documents and Settings\myuser\Start Menu
CSIDL_DESKTOPDIRECTORY = C:\Documents and Settings\myuser\Desktop
CSIDL_NETHOOD = C:\Documents and Settings\myuser\NetHood
CSIDL_FONTS = C:\WINDOWS\Fonts
CSIDL_TEMPLATES = C:\Documents and Settings\myuser\Templates
CSIDL_COMMON_STARTMENU = C:\Documents and Settings\All Users\Start Menu
CSIDL_COMMON_PROGRAMS = C:\Documents and Settings\All Users\Start Menu\Programs
CSIDL_COMMON_STARTUP = C:\Documents and Settings\All Users\Start Menu\Programs\Startup
CSIDL_COMMON_DESKTOPDIRECTORY = C:\Documents and Settings\All Users\Desktop
CSIDL_APPDATA = C:\Documents and Settings\myuser\Application Data
CSIDL_PRINTHOOD = C:\Documents and Settings\myuser\PrintHood
CSIDL_LOCAL_APPDATA = C:\Documents and Settings\myuser\Local Settings\Application Data
CSIDL_COMMON_FAVORITES = C:\Documents and Settings\All Users\Favorites
CSIDL_INTERNET_CACHE = C:\Documents and Settings\myuser\Local Settings\Temporary Internet Files
CSIDL_COOKIES = C:\Documents and Settings\myuser\Cookies
CSIDL_HISTORY = C:\Documents and Settings\myuser\Local Settings\History
CSIDL_COMMON_APPDATA = C:\Documents and Settings\All Users\Application Data
CSIDL_WINDOWS = C:\WINDOWS
CSIDL_SYSTEM = C:\WINDOWS\system32
CSIDL_PROGRAM_FILES = C:\Program Files
CSIDL_PROFILE = C:\Documents and Settings\myuser
CSIDL_SYSTEMX86 = C:\WINDOWS\system32
CSIDL_PROGRAM_FILES_COMMON = C:\Program Files\Common Files
CSIDL_COMMON_TEMPLATES = C:\Documents and Settings\All Users\Templates
CSIDL_COMMON_DOCUMENTS = C:\Documents and Settings\All Users\Documents
CSIDL_COMMON_ADMINTOOLS = C:\Documents and Settings\All Users\Start Menu\Programs\Administrative Tools
CSIDL_ADMINTOOLS = C:\Documents and Settings\myuser\Start Menu\Programs\Administrative Tools
CSIDL_COMMON_MUSIC = C:\Documents and Settings\All Users\Documents\My Music
CSIDL_COMMON_VIDEO = C:\Documents and Settings\All Users\Documents\My Videos
CSIDL_RESOURCES = C:\WINDOWS\resources
CSIDL_CDBURN_AREA = C:\Documents and Settings\myuser\Local Settings\Application Data\Microsoft\CD Burning
CSIDL_FLAG_PER_USER_INIT = C:\Documents and Settings\myuser\Desktop
CSIDL_FLAG_NO_ALIAS = C:\Documents and Settings\myuser\Desktop
CSIDL_FLAG_DONT_UNEXPAND = C:\Documents and Settings\myuser\Desktop
CSIDL_FLAG_DONT_VERIFY = C:\Documents and Settings\myuser\Desktop
CSIDL_FLAG_CREATE = C:\Documents and Settings\myuser\Desktop



Windows XP french example results with myuser user


c:\> .\GetSpecialFolderPath.ps1
CSIDL_COMMON_DESKTOPDIRECTORY = C:\Documents and Settings\All Users\Bureau
CSIDL_DESKTOP = C:\Documents and Settings\myuser\Bureau
CSIDL_PROGRAMS = C:\Documents and Settings\myuser\Menu Démarrer\Programmes
CSIDL_PERSONAL = D:\DONNEES
CSIDL_MYDOCUMENTS = D:\DONNEES
CSIDL_FAVORITES = C:\Documents and Settings\myuser\Favoris
CSIDL_STARTUP = C:\Documents and Settings\myuser\Menu Démarrer\Programmes\Démarrage
CSIDL_RECENT = C:\Documents and Settings\myuser\Recent
CSIDL_SENDTO = C:\Documents and Settings\myuser\SendTo
CSIDL_STARTMENU = C:\Documents and Settings\myuser\Menu Démarrer
CSIDL_MYMUSIC = D:\DONNEES\Ma musique
CSIDL_MYVIDEO = D:\DONNEES\Mes vidéos
CSIDL_DESKTOPDIRECTORY = C:\Documents and Settings\myuser\Bureau
CSIDL_NETHOOD = C:\Documents and Settings\myuser\Voisinage réseau
CSIDL_FONTS = C:\WINDOWS\Fonts
CSIDL_TEMPLATES = C:\Documents and Settings\myuser\Modèles
CSIDL_COMMON_STARTMENU = C:\Documents and Settings\All Users\Menu Démarrer
CSIDL_COMMON_PROGRAMS = C:\Documents and Settings\All Users\Menu Démarrer\Programmes
CSIDL_COMMON_STARTUP = C:\Documents and Settings\All Users\Menu Démarrer\Programmes\Démarrage
CSIDL_COMMON_DESKTOPDIRECTORY = C:\Documents and Settings\All Users\Bureau
CSIDL_APPDATA = C:\Documents and Settings\myuser\Application Data
CSIDL_PRINTHOOD = C:\Documents and Settings\myuser\Voisinage d'impression
CSIDL_LOCAL_APPDATA = C:\Documents and Settings\myuser\Local Settings\Application Data
CSIDL_COMMON_FAVORITES = C:\Documents and Settings\All Users\Favoris
CSIDL_INTERNET_CACHE = C:\Documents and Settings\myuser\Local Settings\Temporary Internet Files
CSIDL_COOKIES = C:\Documents and Settings\myuser\Cookies
CSIDL_HISTORY = C:\Documents and Settings\myuser\Local Settings\Historique
CSIDL_COMMON_APPDATA = C:\Documents and Settings\All Users\Application Data
CSIDL_WINDOWS = C:\WINDOWS
CSIDL_SYSTEM = C:\WINDOWS\system32
CSIDL_PROGRAM_FILES = C:\Program Files
CSIDL_MYPICTURES = D:\DONNEES
CSIDL_PROFILE = C:\Documents and Settings\myuser
CSIDL_SYSTEMX86 = C:\WINDOWS\system32
CSIDL_PROGRAM_FILES_COMMON = C:\Program Files\Fichiers communs
CSIDL_COMMON_TEMPLATES = C:\Documents and Settings\All Users\Modèles
CSIDL_COMMON_DOCUMENTS = C:\Documents and Settings\All Users\Documents
CSIDL_COMMON_ADMINTOOLS = C:\Documents and Settings\All Users\Menu Démarrer\Programmes\Outils d'administration
CSIDL_ADMINTOOLS = C:\Documents and Settings\myuser\Menu Démarrer\Programmes\Outils d'administration
CSIDL_COMMON_MUSIC = C:\Documents and Settings\All Users\Documents\Ma musique
CSIDL_COMMON_PICTURES = C:\Documents and Settings\All Users\Documents\Mes images
CSIDL_COMMON_VIDEO = C:\Documents and Settings\All Users\Documents\Mes vidéos
CSIDL_RESOURCES = C:\WINDOWS\resources
CSIDL_CDBURN_AREA = C:\Documents and Settings\myuser\Local Settings\Application Data\Microsoft\CD Burning
CSIDL_FLAG_PER_USER_INIT = C:\Documents and Settings\myuser\Bureau
CSIDL_FLAG_NO_ALIAS = C:\Documents and Settings\myuser\Bureau
CSIDL_FLAG_DONT_UNEXPAND = C:\Documents and Settings\myuser\Bureau
CSIDL_FLAG_DONT_VERIFY = C:\Documents and Settings\myuser\Bureau
CSIDL_FLAG_CREATE = C:\Documents and Settings\myuser\Bureau

Monday, May 30, 2011

Calcul des Indemnités Kilométriques MAJ IK avril 2011

Suite à la mise à jour en avril des Indices Kilométriques par l'administration, j'ai modifié mon billet http://franckrichard.blogspot.com/2011/03/calcul-des-indemnites-kilometriques.html pour prendre en compte

Monday, May 23, 2011

Remote assistance in Windows 2003/2008 without activate it

An old information which can interest some people. Sometimes I need to have user or account service rights on a server to make some actions. A remote desktop connection or a "Runas" in command line can help me for this, but that means I must to know user's password. This information can be critical, so, when user is not in the same building or in an other country than me, remote assistance is a good way to resolve this problem. But, on a server, this feature is generally not activated. So the trick is to use Task Manager.

Actions:
Connect your server using remote desktop connection (mstsc.exe) then run task manager (taskmgr.exe in command line or start / Windows security / Task manager).



User or service account which you need to control is already connected on this server. So in "Users" tab in task manager you can see it. Select user then click on right button. Click on "Remote Control"







A new window appears asking you hotkey for closing your session. Use default (ctrl+*) or define your own hotkey then click on OK button


















Now user to control have a window which permit to your user to control his session. User click on Yes button, and you can control his session now. Terminate your session using hotkey define above.







For information, you can do the same with "Terminal Services Manager"

Sunday, May 15, 2011

findstr does not support unicode

I often use findstr command on my windows XP to find some informations in text files (grep for unix)

For example with this command

findstr /i "PC2K01" *.*

you will have something like:

File_WIN_PC01_20110414.csv:2011-04-14;PC2K01;;G:;72;62;WINDOWS
File_WIN_PC01_20110414.csv:2011-04-14;PC2K01;;H:;54;49;WINDOWS


I don't remember having problems to find something with findstr command. Except today, when I try to find a computer name in some files. I was completely sure this computer exist in my files and findstr doesn't find this computer...
Finally, I found manually the file containing my computer. So I decided to understand why findstr didn't work. 2 reasons appears to me immediatly: 1st-findstr is bugged. 2nd-there is an encoding problem. To verify this 2nd reason I tested all my files with Get-FileEncoding.ps1
like this

Import-Module .\Get-FileEncoding.ps1
Get-ChildItem | select name, @{n='Encoding';e={Get-FileEncoding $_.FullName}}


Then it appears some file are in Unicode

Name Encoding
---- --------
1.csv ASCII
2.csv Unicode UTF-16 Little-Endian
3.csv ASCII
4.csv ASCII
5.csv ASCII
6.csv ASCII


To verify my idea was good, I just tested something that exist in unicode file 2.csv. In file 2.csv there is the string mystring and only in this file.

findstr /i "mystring" 2.csv

and nothing appears. Findstr does not support unicode....

The solution: convert all your files to ansi.
For this, use this command to create files ANSI_1.csv ANSI_2.csv ...

Get-ChildItem | Foreach-Object { Get-Content -Path $_.Fullname | Out-File ANSI_$_ -Encoding Default }

(for information, you can also do it manually by using notepad / file save as / and changing encoding)

some other ideas if you don't want to convert your files to ansi:
- use find command which is unicode (yes find is unicode / not findstr...)

- use Microsoft sysinternals strings utility
http://technet.microsoft.com/en-us/sysinternals/bb897439

- use powershell

Select-String *.* -pattern "string" | Select-Object filename,pattern,line

Friday, May 6, 2011

Enumerate your own enum in Powershell

Enumeration does not really exist in Powershell. However, when I wrote my ExportRegistyToFile Powershell script, I use 2 techniques of "enumeration".

1st: easily way using hash
Declaration:

$DataTypes = @{"enum1" = "1"; "enum2" = "2"; "enum3" = "3"}


Enumeration:

$DataTypes.Keys

That display (remember hash is not array, so you can have enum2 before enum1 but you set enum1 before enum2)

enum2
enum1
enum3



Enumerate a key and his value:

$enum = "enum2"
Write-Host "Enum:" $enum "value:" $DataTypes ["$enum"]

which display

Enum: enum2 value: 2


Now, 2nd technique to do an enumeration by using add-type (this is the same technique you use when you want to do a pinvoke for accessing win32 api)
Declaration:

$signature = @"
public enum MyEnum : int {
enum1 = 0x0001,
enum2 = 0x0002,
enum3 = 0x0003
}
"@
$type = Add-Type -TypeDefinition $signature -Name Enum -Namespace Data -Using System.Text -PassThru



Enumeration (with + tips - Namespace.functionname+yourenum)

[Enum]::GetNames([Data.Enum+MyEnum])

which display

enum1
enum2
enum3



Enumerate a key and his value:

$enum = "enum2"
Write-Host "Enum:" ([Data.Enum+MyEnum]::$enum) "value:" ([Data.Enum+MyEnum]::$enum.value__)

which display

Enum: enum2 value: 2



There is a great article on scripting guys blog that explain this last technique
http://blogs.technet.com/b/heyscriptingguy/archive/2010/06/06/hey-scripting-guy-weekend-scripter-the-fruity-bouquet-of-windows-powershell-enumerations.aspx


Below a powershell script to test these 2 techniques (Download it)

#
#
# Enum
#
# by F.Richard 2011-05
#
#

#Requires -Version 2.0

$signature = @"
public enum MyEnum : int {
enum1 = 0x0001,
enum2 = 0x0002,
enum3 = 0x0003
}
"@

# Register Enum functions
If (-not ("Data.Enum" -as [Type])) {
$type = Add-Type -TypeDefinition $signature -Name Enum -Namespace Data -Using System.Text -PassThru
} else {
If ($debug) { Write-Host "Data.Enum already Registered" }
}


[Enum]::GetNames([Data.Enum+MyEnum])
$enum = "enum2"
Write-Host "Enum:" ([Data.Enum+MyEnum]::$enum) "value:" ([Data.Enum+MyEnum]::$enum.value__)


$DataTypes = @{"enum1" = "1"; "enum2" = "2"; "enum3" = "3"}
$DataTypes.Keys
$enum = "enum2"
Write-Host "Enum:" $enum "value:" $DataTypes["$enum"]

Tuesday, April 26, 2011

Scripting Games 2011 Advanced Category: final result 4th

Well, finally I'm the 4th in these Scripting Games 2011 Advanced Category competition. Just after Glenn Sizemore, one of "VMware vSphere PowerCLI Reference: Automating vSphere Administration" author

http://blogs.technet.com/b/heyscriptingguy/archive/2011/04/25/final-results-winners-for-the-2011-scripting-games-advanced-category.aspx

Sunday, April 24, 2011

The 2011 Scripting Games Advanced Event 10: Use PowerShell to Create a Function to Create Temp Files

The 2011 Scripting Games Advanced Event 10: Use PowerShell to Create a Function to Create Temp Files

My personal script:
http://2011sg.poshcode.org/1811
Average Rating: 5.00 by 2 users.
(Download it)


#
#
# 2011 Scripting Games Advanced Event 10: Use PowerShell to Create a Function to Create Temp Files
#
# by F.Richard 2011-04
#
#

#Requires -Version 2.0

Function CreateTempFile {
<#
.SYNOPSIS
Create temp file
.DESCRIPTION
create temp file then return filename
.PARAMETER encoding
write file in encoding format
You can use: "Unicode", "UTF7", "UTF8", "UTF32", "ASCII","BigEndianUnicode", "Default","OEM"
"Default" = ANSI format / Default parameter = "Default"
.PARAMETER notepad
display temp file in notepad after creation
.EXAMPLE
"hahaha" | CreateTempFile
write "hahaha" in a temp file and return filename
.EXAMPLE
"hohoho" | CreateTempFile -notepad
write "hohoho" in a temp file and display it in notepad then return filename
.EXAMPLE
dir C:\ | CreateTempFile -encoding unicode
write directory of c:\ in a temp file in unicode format then return filename
#>
Param(
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeLine = $true)]
[psobject] $inputdata,

[Parameter(Mandatory = $false, Position = 1)]
[ValidateSet("Unicode", "UTF7", "UTF8", "UTF32", "ASCII","BigEndianUnicode", "Default","OEM")]
[string] $Encoding="Default",

[Parameter(Mandatory = $false, Position = 2)]
[switch]$notepad,
[Switch]$Whatif
)

# temp file name
# use windows IO function but can use %temp%\(get-date).ToString('yyyyMMdd')
$tempfile = [System.IO.Path]::GetTempFileName()

# create temp file
Write-Debug "Create Temp file $tempFile"
Write-Verbose "Create Temp file $tempFile"
if ($Whatif) {
Write-Host "What if: Create Temp file $tempFile"
} else {
Out-File -filePath $tempFile -InputObject $inputdata -Encoding unicode
}

# open temp file in notepad if switch
if ($notepad) {
Write-Debug "Open file $tempFile in notepad"
Write-Verbose "Open file $tempFile in notepad"
if ($Whatif) {
Write-Host "What if: Open file $tempFile in notepad"
} else {
Notepad $tempFile | Out-Null
}
}

# return temp filename
Write-Debug "return tempfile name"
Write-Verbose "return tempfile name"
if ($Whatif) {
Write-Host "What if: return $tempFile"
return
} else {
return $tempfile
}
}

The 2011 Scripting Games Advanced Event 9: Use PowerShell to Create a File Name Based on Date and Username

The 2011 Scripting Games Advanced Event 9: Use PowerShell to Create a File Name Based on Date and Username

My personal script:
http://2011sg.poshcode.org/1781
Average Rating: 3.00 by 2 users.
(Download it)


#
#
# 2011 Scripting Games Advanced Event 9: Use PowerShell to Create a File Name Based on Date and Username
#
# by F.Richard 2011-04
#
#

#Requires -Version 2.0

Param(
[Parameter(Mandatory = $false, Position = 0, ValueFromPipeLine = $true, ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[String] $string = "My log",

[Parameter(Mandatory = $false, Position = 1)]
[ValidateNotNullOrEmpty()]
[String] $foldername = "HSGLogFiles",

[Parameter(Mandatory = $false, Position = 2)]
[ValidateNotNullOrEmpty()]
[switch] $mydoc
)

<#
.SYNOPSIS
Create log file
.DESCRIPTION
create filename (YYYYMMDD_username.log) in
.PARAMETER string
String to write Default: "My log"
.PARAMETER foldername
Folder name to write Default: "HSGLogFiles"
.PARAMETER path
path where write foldername Default: "CommonApplicationData"
.PARAMETER mydoc
switch to write in my document's directory / replace path folder
.EXAMPLE
CreateLogFile
write file C:\ProgramData\HSGLogFiles\20110420_franck.log
(if we are april 20 2011 and my username is franck in Windows 7)
.EXAMPLE
CreateLogFile -mydoc
write file %userprofile%\Documents\HSGLogFiles\20110420_franck.log
(if we are april 20 2011 and my username is franck)
#>



# if switch mydoc write directory on my document's folder
if ($mydoc) {
$path = [Environment]::GetFolderPath("MyDocuments") + "\" + $foldername
} else {
$path = [Environment]::GetFolderPath("CommonApplicationData") + "\" + $foldername

}


# Create directory if not already exist
if (!(Test-Path -path $path)) {
New-Item $path -type directory | Out-Null
}


# create filename (YYYYMMDD_username.log) if not already exist
$filename = (get-date).ToString('yyyyMMdd') + "_" + ($env:USERNAME) + ".log"
If ((Test-Path("$path\$filename")) -eq $False){
"Log file" | Out-File "$path\$filename"
}

The 2011 Scripting Games Advanced Event 8: Use PowerShell to Remove Metadata and Resize Images

The 2011 Scripting Games Advanced Event 8: Use PowerShell to Remove Metadata and Resize Images

My personal script:
http://2011sg.poshcode.org/1714
Average Rating: 5.00 by 2 users.
(Download it)


#
#
# 2011 Scripting Games Advanced Event 8: Use PowerShell to Remove Metadata and Resize Images
#
# by F.Richard 2011-04
#
#
# Windows form Generated By: SAPIEN Technologies, Inc., PrimalForms 2009
#

#Requires -Version 2.0



# Gloval variables for preferences
$global:ImageFolder = ""
$global:SaveFolder =""



#----------------------------------------------

function Select-Directory() {
param(
[string] $folder = ""
)
# Solution 1 : System.Windows.Forms.FolderBrowserDialog
# but requires STA (Single Threaded Apartment) mode to function correctly (that means -sta switch)
# or
# Solution 2 : COM object
# http://stackoverflow.com/questions/216817/call-folderbrowserdialog-from-powershell#217527
#
$app = New-Object -COM Shell.Application
$directory = $app.BrowseForFolder( 0, "Select Directory", 0 ) # , $folder
$path = $directory.Self.Path
if( $path ) { return $path }
}




function Set-FilesToListbox() {
param(
[string] $folder = (Split-Path -parent $MyInvocation.MyCommand.Path)
)
$listboxFile.Items.Clear()
# only files # where{!($_.PSISContainer)})
ForEach ($File in Get-ChildItem "$folder\*" -include *.bmp, *.tif, *.tiff, *.gif, *.jpg, *.jpeg, *.png ) {
$listboxFile.Items.Add($File.Name) | Out-Null
}

}


function Get-XMLpreferences() {
$defaultfolder = (Get-Location).Path
if (Test-Path($defaultfolder + "\" + "preferences.xml")) {
$xml = New-Object XML
$xml.Load($defaultfolder + "\" + "preferences.xml")
$lbImageFolder.Text = $xml.Preferences.ImageFolder
Set-FilesToListbox -folder $xml.Preferences.ImageFolder
$lbSaveFolder.Text = $xml.preferences.SaveFolder
} else {
$lbImageFolder.Text = $defaultfolder
Set-FilesToListbox -folder $defaultfolder
$lbSaveFolder.Text = $defaultfolder
}
$global:ImageFolder = $lbImageFolder.Text
$global:SaveFolder = $lbSaveFolder.Text



}



function Set-XMLpreferences() {
$defaultfolder = (Get-Location).Path

$xml = New-Object XML
$xmlroot = $xml.CreateElement("Preferences")
$xml.AppendChild($xmlroot) | Out-Null

$imagefolder = $xml.CreateElement("ImageFolder")
$ImageFolder.PSBase.InnerText = $global:ImageFolder
$xmlroot.AppendChild($ImageFolder) | Out-Null

$savefolder = $xml.CreateElement("SaveFolder")
$savefolder.PSBase.InnerText = $global:Savefolder
$xmlroot.AppendChild($savefolder) | Out-Null

$xml.Save($defaultfolder + "\" + "preferences.xml")
}



function Resize-Image() {
param(
[Array] $files
)
foreach ($file in $files) {
$imagefile = $lbImageFolder.Text + "\" + $file
$OldBitmap = [System.Drawing.Image]::FromFile($imagefile)
$width = [int]($OldBitmap.Width * (1/2))
$height = [int]($OldBitmap.Height * (1/2))
$NewBitmap = New-Object System.Drawing.Bitmap($width,$height)
$graphic=[System.Drawing.Graphics]::FromImage($NewBitmap)
$graphic.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
$graphic.DrawImage($OldBitmap, 0, 0, $width, $height) # resize

$savefile = $lbSaveFolder.Text + "\SHARE_" + $file
if (Test-Path($savefile)) {
Remove-Item ($savefile)
}
$NewBitmap.Save($savefile, ([System.Drawing.Imaging.ImageFormat]::jpeg))
$NewBitmap.Dispose()
$OldBitmap.Dispose()
}
[System.Windows.Forms.MessageBox]::Show("Resize Done","Resize")

}


function Resize-ImageKeepMetadata() {
# with this function we keep metada

param(
[Array] $files
)
foreach ($file in $files) {
$image = New-Object -ComObject Wia.ImageFile
$image.LoadFile($file)
$width = $image.Width * (1/2)
$height = $image.Height * (1/2)

$filter = New-Object -ComObject Wia.ImageProcess
$scale = $filter.FilterInfos.Item("Scale").FilterId
$filter.Filters.Add($scale)
$filter.Filters.Item(1).Properties.Item("PreserveAspectRatio") = $True
$filter.Filters.Item(1).Properties.Item("MaximumWidth") = $width
$filter.Filters.Item(1).Properties.Item("MaximumHeight") = $height

$image = $filter.Apply($image.PSObject.BaseObject)
$savefile = $lbSaveFolder.Text + "\SHARE_" + $file
if (Test-Path($savefile)) {
Remove-Item ($savefile)
}
# $image.SaveFile($savefile)
$image = $null
$filter = $null
}
[System.Windows.Forms.MessageBox]::Show("Resize Done","Resize")

}




#----------------------------------------------
#region Application Functions
#----------------------------------------------

function OnApplicationLoad {
#Note: This function runs before the form is created
#Note: To get the script directory in the Packager use: Split-Path $hostinvocation.MyCommand.path
#Note: To get the console output in the Packager (Windows Mode) use: $ConsoleOutput (Type: System.Collections.ArrayList)
#Important: Form controls cannot be accessed in this function
#TODO: Add snapins and custom code to validate the application load

return $true #return true for success or false for failure
}

function OnApplicationExit {
#Note: This function runs after the form is closed
#TODO: Add custom code to clean up and unload snapins when the application exits

# Save program preferences
Set-XMLpreferences

$script:ExitCode = 0 #Set the exit code for the Packager
}

#endregion

#----------------------------------------------
# Generated Form Function
#----------------------------------------------
function GenerateForm {

#----------------------------------------------
#region Import Assemblies
#----------------------------------------------
[void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
[void][reflection.assembly]::Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
#endregion

#----------------------------------------------
#region Generated Form Objects
#----------------------------------------------
[System.Windows.Forms.Application]::EnableVisualStyles()
$formMain = New-Object System.Windows.Forms.Form
$btPrepareToShareAll = New-Object System.Windows.Forms.Button
$rtbMetadata = New-Object System.Windows.Forms.RichTextBox
$listboxFile = New-Object System.Windows.Forms.ListBox
$btPrepareToShare = New-Object System.Windows.Forms.Button
$lbSaveFolder = New-Object System.Windows.Forms.Label
$btSaveFolder = New-Object System.Windows.Forms.Button
$pictbox = New-Object System.Windows.Forms.PictureBox
$lbImageFolder = New-Object System.Windows.Forms.Label
$btImageFolder = New-Object System.Windows.Forms.Button
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
# User Generated Script
#----------------------------------------------


$FormEvent_Load={
# Load program preferences
Get-XMLpreferences

}

$handler_btImageFolder_Click={
$oldFolder = $lbImageFolder.Text
$newFolder = Select-Directory -folder $oldFolder
if ($newFolder) {
$lbImageFolder.Text = $newFolder
Set-FilesToListbox -folder $newFolder
}
$global:ImageFolder = $newFolder

}

$handler_btSaveFolder_Click={
$oldFolder = $lbSaveFolder.Text
$newFolder = Select-Directory -folder $oldFolder
if ($newFolder) {
$lbSaveFolder.Text = $newFolder
}
$global:SaveFolder = $newFolder

}

$handler_listboxFile_SelectedIndexChanged={
#TODO: Place custom script here
$file = $lbImageFolder.Text + "\" + $listboxFile.Text
$pictbox.Image = [System.Drawing.Image]::Fromfile($file)

$image = New-Object -ComObject Wia.ImageFile
$image.LoadFile($file)

# use EXIF quick reference
# http://nicholasarmstrong.com/2010/02/exif-quick-reference/
# and Display Detailed Image Information / Shared Samples
# http://msdn.microsoft.com/en-us/library/ms630826%28v=vs.85%29.aspx
$content = ""
$content += "Height: " + $image.Height + "`n"
$content += "Width: " + $image.Width + "`n"
$content += "Depth: " + $image.PixelDepth + "`n"
$content += "HorizontalResolution : " + $image.HorizontalResolution + "`n"
$content += "VerticalResolution : " + $image.VerticalResolution + "`n"
$content += "FrameCount : " + $image.FrameCount + "`n"
if ($image.IsIndexedPixelFormat) { $content += "Pixel data contains palette indexes" + "`n" }
if ($image.IsAlphaPixelFormat) { $content += "Pixel data has alpha information" + "`n" }
if ($image.IsExtendedPixelFormat) { $content += "Pixel data has extended color information (16 bit/channel)" + "`n" }
if ($image.IsAnimated) { $content += "Image is animated" + "`n" }
if ($image.Properties.Exists("271")) { $content += "Equipment Maker:" + $image.Properties.Item("271").Value + "`n" }
if ($image.Properties.Exists("272")) { $content += "Equipment Model:" + $image.Properties.Item("272").Value + "`n" }
$orientation = @{ 1 = "Horizontal"; 3 = "Rotate 180 degrees"; 6 = "Rotate 90 degrees clockwise" ; 8 = "Rotate 270 degrees clockwise" }
if ($image.Properties.Exists("274")) { $content += "Orientation:" + $orientation[[int]$image.Properties.Item("274").Value] + "`n" }
if ($image.Properties.Exists("282")) { $content += "X Resolution:" + $image.Properties.Item("282").Value.Value + "`n" }
if ($image.Properties.Exists("283")) { $content += "Y Resolution:" + $image.Properties.Item("283").Value.Value + "`n" }
$unit = @{ 1 = "None"; 2 = "Inches"; 3 = "Centimetres" }
if ($image.Properties.Exists("296")) { $content += "Resolution Unit:" + $unit[[int]$image.Properties.Item("296").Value] + "`n" }
if ($image.Properties.Exists("306")) { $content += "Modified Date Time:" + $image.Properties.Item("306").Value + "`n" }
if ($image.Properties.Exists("33434")) { $content += "Exposure Time:" + $image.Properties.Item("33434").Value.Value + "`n" }
if ($image.Properties.Exists("33437")) { $content += "F Number:" + $image.Properties.Item("33437").Value.Value + "`n" }
if ($image.Properties.Exists("34855")) { $content += "ISO Speed:" + $image.Properties.Item("34855").Value + "`n" }
if ($image.Properties.Exists("36867")) { $content += "Date Taken:" + $image.Properties.Item("36867").Value + "`n" }
if ($image.Properties.Exists("36868")) { $content += "Date Created:" + $image.Properties.Item("36868").Value + "`n" }
if ($image.Properties.Exists("37377")) { $content += "Shutter Speed:" + $image.Properties.Item("37377").Value.Value + "`n" }
if ($image.Properties.Exists("37378")) { $content += "Aperture:" + $image.Properties.Item("37378").Value.Value + "`n" }
if ($image.Properties.Exists("37380")) { $content += "Exposure Compensation:" + $image.Properties.Item("37380").Value.Value + "`n" }
if ($image.Properties.Exists("37381")) { $content += "Maximum Aperature:" + $image.Properties.Item("37381").Value.Value + "`n" }
$metering = @{ 0 = "Unknown"; 1 = "Average"; 2 = "Center-weighted average" ; 3 = "Spot"; 4 = "Multi-spot"; 5 = "Multi-segment"; 6 = "Partial"; 255 = "Unknown" }
if ($image.Properties.Exists("37383")) { $content += "Metering Mode:" + $metering[[int]$image.Properties.Item("37383").Value] + "`n" }
$flash = @{ 0 = "No Flash"; 10 = "Flash off"; 1 = "Flash on"; 11 = "Flash auto" }
if ($image.Properties.Exists("37385")) { $content += "Flash:" +$image.Properties.Item("37385").Value + "`n" }
if ($image.Properties.Exists("37386")) { $content += "Equipment Maker Note:" + $image.Properties.Item("37386").Value.Value + "`n" }
if ($image.Properties.Exists("37510")) { $content += "User Comment:" + $image.Properties.Item("37510").Value.Value + "`n" }
if ($image.Properties.Exists("40961")) { $content += "Color Space:" + $image.Properties.Item("40961").Value + "`n" }
if ($image.Properties.Exists("40962")) { $content += "Pixel X Dimension:" + $image.Properties.Item("40962").Value + "`n" }
if ($image.Properties.Exists("40963")) { $content += "Pixel Y Dimension:" + $image.Properties.Item("40963").Value + "`n" }
if ($image.Properties.Exists("41486")) { $content += "Focal Plane X Resolution:" + $image.Properties.Item("41486").Value + "`n" }
if ($image.Properties.Exists("41487")) { $content += "Focal Plane Y Resolution:" + $image.Properties.Item("41487").Value + "`n" }
$focal = @{ 1 = "None"; 2 = "Inches"; 3 = "Centimetres" ; 4 = "Millimetres"; 5 = "Micrometres" }
if ($image.Properties.Exists("41488")) { $content += "Focal Plane Resolution Unit:" + $focal[[int]$image.Properties.Item("41488").Value] + "`n" }
$sensing = @{ 1 = "Not defined"; 2 = "One-chip colour area"; 3 = "Two-chip colour area" ; 4 = "Three-chip colour area"; 5 = "Colour sequential area"; 7 = "Trilinear"; 8 = "Colour sequential linear" }
if ($image.Properties.Exists("41495")) { $content += "Sensing Method:" + $sensing[[int]$image.Properties.Item("41495").Value] + "`n" }
$filesrc = @{ 1 = "Film scanner"; 2 = "Reflection print scanner"; 3 = "Digital camera" }
if ($image.Properties.Exists("41728")) { $content += "File Source:" + $filesrc[[int]$image.Properties.Item("41728").Value] + "`n" }
$custrender = @{ 0 = "Normal"; 1 = "Custom" }
if ($image.Properties.Exists("41985")) { $content += "Custom Rendered:" + $custrender[[int]$image.Properties.Item("41985").Value] + "`n" }
$exposure = @{ 0 = "Auto"; 1 = "Manual"; 2 = "Auto Bracket" }
if ($image.Properties.Exists("41986")) { $content += "Exposure Mode:" + $exposure[[int]$image.Properties.Item("41986").Value] + "`n" }
$white = @{ 0 = "Auto"; 1 = "Manual" }
if ($image.Properties.Exists("41987")) { $content += "White Balance:" + $white[[int]$image.Properties.Item("41987").Value] + "`n" }
if ($image.Properties.Exists("41988")) { $content += "Digital Zoom Ratio:" + $image.Properties.Item("41988").Value + "`n" }
if ($image.Properties.Exists("41989")) { $content += "Focal Length in 35 mm Format:" + $image.Properties.Item("41989").Value + "`n" }
$scene = @{ 0 = "Standard"; 1 = "Landscape"; 2 = "Portrait"; 3 = "Night" }
if ($image.Properties.Exists("41990")) { $content += "Scene Capture Type:" + $scene[[int]$image.Properties.Item("41990").Value] + "`n" }
$gain = @{ 0 = "None"; 1 = "Low gain up"; 2 = "High gain up"; 3 = "Low gain down"; 4 = "High gain down" }
if ($image.Properties.Exists("41991")) { $content += "Gain Control:" + $gain[[int]$image.Properties.Item("41991").Value] + "`n" }
$contrast = @{ 0 = "Normal"; 1 = "Low"; 2 = "High" }
if ($image.Properties.Exists("41992")) { $content += "Contrast:" + $contrast[[int]$image.Properties.Item("41992").Value] + "`n" }
$saturation = @{ 0 = "Normal"; 1 = "Low"; 2 = "High" }
if ($image.Properties.Exists("41993")) { $content += "Saturation:" + $saturation[[int]$image.Properties.Item("41993").Value] + "`n" }
$sharpness = @{ 0 = "Normal"; 1 = "Soft"; 2 = "Hard" }
if ($image.Properties.Exists("41994")) { $content += "Sharpness:" + $sharpness[[int]$image.Properties.Item("41994").Value] + "`n" }
$sdr = @{ 0 = "Unknown"; 1 = "Macro"; 2 = "Close" ; 3 = "Distant" }
if ($image.Properties.Exists("41996")) { $content += "Subject Distance Range:" + $sdr[[int]$image.Properties.Item("41996").Value] + "`n" }
$image = $null
$rtbMetadata.Lines = $content
}

$handler_btPrepareToShareAll_Click={
$files = @( )
for ($i = 0; $i -lt $listboxFile.items.count; $i++) {
$files += $listboxFile.items.item($i)
}
Resize-Image -files $files
}

$handler_btPrepareToShare_Click={
$files = @( )
#foreach ($objItem in $listboxFile.SelectedItems) {$files += $objItem} # for MultiExtended
$files += $listboxFile.Text
Resize-Image -files $files

}

#----------------------------------------------
# Generated Events
#----------------------------------------------

$Form_StateCorrection_Load=
{
#Correct the initial state of the form to prevent the .Net maximized form issue
$formMain.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
#----------------------------------------------
#
# formMain
#
$formMain.Controls.Add($btPrepareToShareAll)
$formMain.Controls.Add($rtbMetadata)
$formMain.Controls.Add($listboxFile)
$formMain.Controls.Add($btPrepareToShare)
$formMain.Controls.Add($lbSaveFolder)
$formMain.Controls.Add($btSaveFolder)
$formMain.Controls.Add($pictbox)
$formMain.Controls.Add($lbImageFolder)
$formMain.Controls.Add($btImageFolder)
$formMain.ClientSize = New-Object System.Drawing.Size(792,573)
$formMain.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$formMain.Name = "formMain"
$formMain.Text = "Image Resizer"
$formMain.add_Load($FormEvent_Load)
#
# btPrepareToShareAll
#
$btPrepareToShareAll.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$btPrepareToShareAll.Location = New-Object System.Drawing.Point(17,538)
$btPrepareToShareAll.Name = "btPrepareToShareAll"
$btPrepareToShareAll.Size = New-Object System.Drawing.Size(184,23)
$btPrepareToShareAll.TabIndex = 9
$btPrepareToShareAll.Text = "Prepare to Share All Image"
$btPrepareToShareAll.UseVisualStyleBackColor = $True
$btPrepareToShareAll.add_Click($handler_btPrepareToShareAll_Click)
#
# rtbMetadata
#
$rtbMetadata.BackColor = [System.Drawing.Color]::FromArgb(255,212,208,200)
$rtbMetadata.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$rtbMetadata.ForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
$rtbMetadata.Location = New-Object System.Drawing.Point(438,69)
$rtbMetadata.Name = "rtbMetadata"
$rtbMetadata.ReadOnly = $True
$rtbMetadata.Size = New-Object System.Drawing.Size(342,492)
$rtbMetadata.TabIndex = 8
$rtbMetadata.Text = ""
#
# listboxFile
#
$listboxFile.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$listboxFile.FormattingEnabled = $True
$listboxFile.Location = New-Object System.Drawing.Point(17,69)
$listboxFile.Name = "listboxFile"
#$listboxFile.SelectionMode = [System.Windows.Forms.SelectionMode]::MultiExtended
$listboxFile.Size = New-Object System.Drawing.Size(400,134)
$listboxFile.TabIndex = 6
$listboxFile.add_SelectedIndexChanged($handler_listboxFile_SelectedIndexChanged)
#
# btPrepareToShare
#
$btPrepareToShare.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$btPrepareToShare.Location = New-Object System.Drawing.Point(233,538)
$btPrepareToShare.Name = "btPrepareToShare"
$btPrepareToShare.Size = New-Object System.Drawing.Size(184,23)
$btPrepareToShare.TabIndex = 5
$btPrepareToShare.Text = "Prepare to Share Selected Image"
$btPrepareToShare.UseVisualStyleBackColor = $True
$btPrepareToShare.add_Click($handler_btPrepareToShare_Click)
#
# lbSaveFolder
#
$lbSaveFolder.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$lbSaveFolder.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$lbSaveFolder.Location = New-Object System.Drawing.Point(156,39)
$lbSaveFolder.Name = "lbSaveFolder"
$lbSaveFolder.Size = New-Object System.Drawing.Size(624,23)
$lbSaveFolder.TabIndex = 4
#
# btSaveFolder
#
$btSaveFolder.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$btSaveFolder.Location = New-Object System.Drawing.Point(17,39)
$btSaveFolder.Name = "btSaveFolder"
$btSaveFolder.Size = New-Object System.Drawing.Size(133,23)
$btSaveFolder.TabIndex = 3
$btSaveFolder.Text = "Select Save Folder"
$btSaveFolder.UseVisualStyleBackColor = $True
$btSaveFolder.add_Click($handler_btSaveFolder_Click)
#
# pictbox
#
$pictbox.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$pictbox.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$pictbox.Location = New-Object System.Drawing.Point(17,220)
$pictbox.Name = "pictbox"
$pictbox.Size = New-Object System.Drawing.Size(400,300)
$pictbox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::StretchImage
$pictbox.TabIndex = 2
$pictbox.TabStop = $False
#
# lbImageFolder
#
$lbImageFolder.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
$lbImageFolder.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$lbImageFolder.Location = New-Object System.Drawing.Point(156,11)
$lbImageFolder.Name = "lbImageFolder"
$lbImageFolder.Size = New-Object System.Drawing.Size(624,23)
$lbImageFolder.TabIndex = 1
#
# btImageFolder
#
$btImageFolder.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$btImageFolder.Location = New-Object System.Drawing.Point(17,11)
$btImageFolder.Name = "btImageFolder"
$btImageFolder.Size = New-Object System.Drawing.Size(133,23)
$btImageFolder.TabIndex = 0
$btImageFolder.Text = "Select Image Folder"
$btImageFolder.UseVisualStyleBackColor = $True
$btImageFolder.add_Click($handler_btImageFolder_Click)
#endregion Generated Form Code

#----------------------------------------------

#Save the initial state of the form
$InitialFormWindowState = $formMain.WindowState
#Init the OnLoad event to correct the initial state of the form
$formMain.add_Load($Form_StateCorrection_Load)
#Show the Form
return $formMain.ShowDialog()

} #End Function


# Test WIA is installed by testing if "%WINDIR%\system32\wiaaut.dll" exist and
$testWIA = New-Object -ComObject Wia.ImageFile
if ($testWIA -eq $isnull) {
Write-Host "Windows Image Acquisition Library dll seems to be not registered"
Exit
}
$wiafile = "$env:WINDIR\system32\wiaaut.dll"
if (!(Test-Path($wiafile))) {
Write-Host "Windows Image Acquisition Library dll $wiafile is installed but not registered. Run this next commandline to registered it:"
Write-Host "regsvr32 C:\windows\system32\wiaaut.dll"
Exit
}



#Call OnApplicationLoad to initialize
if(OnApplicationLoad -eq $true)
{
#Create the form
GenerateForm | Out-Null

#Perform cleanup
OnApplicationExit
}