Hey, Scripting Guy! I am not into all those fancy scripts you seem to write. I am just a basic, everyday network administrator, and I simply need to use scripts to make my job easier. Because of this, I am not interested in displaying progress bars, writing stuff to Excel or Word or even PowerPoint. I am interested simply in having my Windows PowerShell script display information on the screen. What is the best way to do this?
– CO
Hi CO,
At times it seems like only yesterday, but when I started out in the field of IT, I also was a basic, everyday network administrator. The days were never boring because the problems were never the same. I would show up in my office, and there would be a message from a user stating they could not get logged on to the network; while I was resetting their password, I would check my e-mail and find out that someone else was having problems creating a macro in Office Excel. As I checked my project board, I saw that I needed to get a new network drop installed in a remote office. I also had to teach a class in the afternoon on basic Office Outlook for a dozen new users. Yep, being a basic, everyday network administrator was a lot of fun. I never got bored.
The one thing I never had was free time. Back then I used to drink coffee, but I don’t think I ever actually finished a cup of coffee before it was cold. I actually got to where I could drink cold coffee without cringing and shuddering. Because I was so busy running from problem to problem, I seldom wrote scripts. When I did write a script, it would display information on the screen because I always ran the scripts in an interactive fashion. Years later, after I began working at Microsoft, my good friend Jason and I went to Hong Kong where I learned a new appreciation for interactive displays. Here is a good picture of Victoria Harbor I took from a hydrofoil on my way to Macau.
CO, when displaying information on the screen, the most important thing to remember is that it is easy. In many cases, you do not have to do anything more complicated than to run the cmdlet. When you do, you are automatically rewarded with nicely formatted output that is displayed on the screen:
The reason the output is nicely formatted is the Windows PowerShell team created several format.ps1xml files that are used to control the way different objects are formatted when they are displayed. These XML files are located in the Windows PowerShell installation directory. Luckily, there is an automatic variable, $pshome, that can be used to refer to the Windows PowerShell installation directory. To obtain a listing of all the format.ps1xml files that are installed on your computer, use the Get-ChildItem cmdlet and specify a path that will retrieve any file with the name format in it. Pipeline the resulting fileinfo objects to the Select-Object cmdlet and choose the name property. This is seen here:
PS C:> Get-ChildItem -Path $PSHOME/*format* | Select-Object -Property name
Name
—-
certificate.format.ps1xml
dotnettypes.format.ps1xml
filesystem.format.ps1xml
help.format.ps1xml
powershellcore.format.ps1xml
powershelltrace.format.ps1xml
registry.format.ps1xml
These format.ps1xml files are used by the Windows PowerShell Extended Type System to determine how to display objects. This is required because most objects do not know how to display themselves. Because the format files are XML files, it is possible to edit them to change the default display behavior. This should not be undertaken lightly, though, because the files are rather complicated. If you wish to edit the files, make sure you have a good backup copy of the files before you start messing around with them. Direct manipulation of the format.ps1xml files could result in unexpected behavior. It is also possible to write your own format.ps1xml file (in fact Marc Van Orsouw [MOW] created his own format data file to tune the default output format for the Trace-Route function he wrote as a guest commentator for the 2009 Summer Scripting Games.
The dotnettypes.format.ps1xml file is used to control the output that is displayed by a number of the cmdlets (Get-Process, Get-Service, Get-EventLog, etc.) that return .NET Framework objects. A portion of the dotnettypes.format.ps1xml file is seen in the next image. This is the section of the file that controls the output from the Get-Process cmdlet that is seen in the previous image. Under the <TableHeaders> section, each column heading is specified by the <TableColumnHeader> tag. And under the <TableColumnHeader>, there are three nodes: <Label>, <Width>, and <Alignment>. <Label> controls the column heading, <Width> controls how wide the column is, and <Alignment> is used to specify the alignment (left, center, right) of the data within the column. This is seen here:
To display information in the Command Prompt window, you do not need to worry about format XML files or anything like that. You can rely upon the defaults and allow Windows PowerShell to make the decision for you. To display a string, you place the string in quotation marks and it is displayed in the Command Prompt window. This is seen here:
PS C:> “this string is displayed to the console”
this string is displayed to the console
PS C:>
The important thing to keep in mind is that when the string is shown in the Command Prompt window, it retains its type; that is, it is still a string. This is seen here:
PS C:> “this string is displayed to the console” | Get-Member
TypeName: System.String
Name MemberType Definition
—- ———- ———-
Clone Method System.Object Clone()
CompareTo Method int CompareTo(System.Object value), i…
Contains Method bool Contains(string value)
CopyTo Method System.Void CopyTo(int sourceIndex, c…
EndsWith Method bool EndsWith(string value), bool End…
Equals Method bool Equals(System.Object obj), bool …
GetEnumerator Method System.CharEnumerator GetEnumerator()
GetHashCode Method int GetHashCode()
GetType Method type GetType()
GetTypeCode Method System.TypeCode GetTypeCode()
IndexOf Method int IndexOf(char value), int IndexOf(…
IndexOfAny Method int IndexOfAny(char[] anyOf), int Ind…
Insert Method string Insert(int startIndex, string …
IsNormalized Method bool IsNormalized(), bool IsNormalize…
LastIndexOf Method int LastIndexOf(char value), int Last…
LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), int…
Normalize Method string Normalize(), string Normalize(…
PadLeft Method string PadLeft(int totalWidth), strin…
PadRight Method string PadRight(int totalWidth), stri…
Remove Method string Remove(int startIndex, int cou…
Replace Method string Replace(char oldChar, char new…
Split Method string[] Split(Params char[] separato…
StartsWith Method bool StartsWith(string value), bool S…
Substring Method string Substring(int startIndex), str…
ToCharArray Method char[] ToCharArray(), char[] ToCharAr…
ToLower Method string ToLower(), string ToLower(Syst…
ToLowerInvariant Method string ToLowerInvariant()
ToString Method string ToString(), string ToString(Sy…
ToUpper Method string ToUpper(), string ToUpper(Syst…
ToUpperInvariant Method string ToUpperInvariant()
Trim Method string Trim(Params char[] trimChars),…
TrimEnd Method string TrimEnd(Params char[] trimChars)
TrimStart Method string TrimStart(Params char[] trimCh…
Chars ParameterizedProperty char Chars(int index) {get;}
Length Property System.Int32 Length {get;}
If you use one of the Out-* cmdlets such as Out-Host or Out-Default, you destroy the object-oriented nature of the string. That is, it is no longer an instance of a system.string .NET Framework class. This is seen here:
PS C:> “this string is displayed to the console” | Out-Host | Get-Member
this string is displayed to the console
Get-Member : No object has been specified to the get-member cmdlet.
At line:1 char:66
+ “this string is displayed to the console” | Out-Host | Get-Member <<<<
+ CategoryInfo : CloseError: (:) [Get-Member], InvalidOperationEx
ception
+ FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Command
s.GetMemberCommand
PS C:>
As a best practice you should avoid using the Out-Host cmdlet or the Out-Default cmdlet unless there is a reason for using it. This is because you lose your object after you send the output to these two cmdlets. The only reason for using Out-Host is to use the –paging parameter. This is seen here:
PS C:> Get-WmiObject -Class win32_process | Out-Host -Paging
__GENUS : 2
__CLASS : Win32_Process
__SUPERCLASS : CIM_Process
__DYNASTY : CIM_ManagedSystemElement
__RELPATH : Win32_Process.Handle=”0″
__PROPERTY_COUNT : 45
__DERIVATION : {CIM_Process, CIM_LogicalElement, CIM_ManagedSyste
mElement}
__SERVER : VISTA
__NAMESPACE : rootcimv2
__PATH : \VISTArootcimv2:Win32_Process.Handle=”0″
Caption : System Idle Process
CommandLine :
CreationClassName : Win32_Process
CreationDate :
CSCreationClassName : Win32_ComputerSystem
CSName : VISTA
Description : System Idle Process
ExecutablePath :
ExecutionState :
Handle : 0
HandleCount : 0
InstallDate :
KernelModeTime : 151488730096
MaximumWorkingSetSize :
MinimumWorkingSetSize :
Name : System Idle Process
OSCreationClassName : Win32_OperatingSystem
OSName : Microsoftr Windows VistaT Business |C:Windows|De
viceHarddisk0Partition1
OtherOperationCount : 0
OtherTransferCount : 0
PageFaults : 0
PageFileUsage : 0
ParentProcessId : 0
PeakPageFileUsage : 0
PeakVirtualSize : 0
PeakWorkingSetSize : 0
Priority : 0
PrivatePageCount : 0
<SPACE> next page; <CR> next line; Q quit
If you are not using the paging parameter, there is no advantage to using the Out-Host cmdlet. From a display perspective, the following commands are identical:
Get-Process
Get-Process | Out-Host
Get-Process | Out-Default
In fact, on most systems Out-Default and Out-Host do the same thing. This is because by default Out-Host is the default outputter. The only reason to use Out-Default would be if you anticipated changing the default outputter, and you did not want to rewrite the script. By using Out-Default the output from the script will always go to the default outputter, which may or may not be the host.
CO, that is about all there is to say for now about writing to the host. Join us tomorrow as we will continue talking about handling output from scripts. If you want to keep up to date with the Scripting Guys, you can follow us on Twitter. You can also look us up on Facebook. Until tomorrow peace!
0 comments