Friday, August 31, 2012

Item or array?

PowerShell cmdlets behave in interesting way. You can get an array or a single object from one method, so, be ready!
Innocent code snippet:

  1. $processes = Get-Process -Name powershell* -Verbose  
  2. If ($processes.count -gt 1) {  
  3.     "There are several powershell consoles"  
  4. } ElseIf ($processes.count -eq 1) {  
  5.     "There is one powershell console"  
  6. } Else {  
  7.     "There are no powershell consoles at all"  
  8. }  
What can go wrong?

But PowerShell runtime does a following thing:
  • If cmdlet returns several objects, it wraps them in object[] 
  • If only one object is returned to pipe, it returns the object itself (Process class instance in our case)
  • If no results are returned, it returns $null
You will get  "There are no powershell consoles at all" when you have both 0 or 1 console.

The preferred way to work with cmdlet output is pipeline, so most clean and robust solution will be:
  1. $powershellConsoles = 0  
  2. Get-Process -Name powershell* | ForEach-Object { $powershellConsoles++ }  
  3.   
  4. # First way, generic    
  5. If ($powershellConsoles -gt 1) {    
  6.     "There are several powershell consoles"    
  7. } ElseIf ($powershellConsoles -eq 1) {    
  8.     "There is one powershell console"    
  9. } Else {    
  10.     "There are no powershell consoles at all"    
  11. }  

Also, you can handle output like that:
  1. $processes = Get-Process -Name powershell*
  2.   
  3. # First way, generic  
  4. If ($processes -is [array]) {  
  5.     "There are several powershell consoles"  
  6. } ElseIf ($processes -ne $null) {  
  7.     "There is one powershell console"  
  8. } Else {  
  9.     "There are no powershell consoles at all"  
  10. }  
  11.   
  12. # Second way, straight typed  
  13. If ($processes -is [array]) {  
  14.     "There are several powershell consoles"  
  15. } ElseIf ($processes -is [System.Diagnostics.Process]) {  
  16.     "There is one powershell console"  
  17. } Else {  
  18.     "There are no powershell consoles at all"  
  19. }  

Also, notice, that default cmdlets behavior is to write error, if explicit conditions were determined:
  1. # Will silently return $null, if there are no jobs at all  
  2. Get-Job  
  3.   
  4. # Will return null and error message, if there are no jobs reaching conditions  
  5. Get-Job -Name NonexistableJob  

No comments:

Post a Comment