Summary: Ed Wilson, Microsoft Scripting Guy, talks about using a compound string command.
Microsoft Scripting Guy, Ed Wilson, is here. The other day, the Scripting Wife and I headed to Nashville for a couple of speaking engagements. We decided to head through Alabama instead of going through Atlanta for a couple of reasons. We have never driven the length of Alabama, so we were looking for a bit of different scenery. Secondly, because we always spend a couple of hours trying to drive through Atlanta and all of the associated communities in the greater Atlanta metropolitan area (hmmmm….Gamma)?
Anyway, it was a lovely day to drive. Here is a picture I took when we got out to walk around a bit. It is really pretty, and some of the trees are actually starting to change colors. The palm trees we have in Florida don’t really change colors (that I recall), so it was a nice change of pace.
The Nashville PowerShell User Group combined with the SQL User Group, and the event was sold out. Nearly 90 people filled the meeting room at the Microsoft office. One of the questions I received was about a line of code that works with strings. In fact, there were several questions in the room, and even more comments about it on Twitter.
Compounding object notation
The line of code in question is shown in the following script:
$datain = import-csv C:\DataIn\DataDump.csv
Foreach ($d in $datain)
{
If($d.name -match ',')
{
$name = (Get-Culture).textinfo.ToTitleCase($d.name).Split(',').trim()
[PSCustomObject]@{
Lname = $name[0]
Fname = $name[1] }}
ELSE {
$name = $d.Name.Split().trim()
[PSCustomObject]@{
Fname = $name[0]
Lname = $name[1] } }
}
Basically, the script reads a CSV file that contains user names, and it title cases the name, splits it into pieces at the comma, and then trims off the extra spaces from the beginning and the end of the name. Here is the exact line of code:
$name = (Get-Culture).textinfo.ToTitleCase($d.name).Split(',').trim()
What makes this line of code a bit complicated, is that it actually contains three objects. It also has an object and three methods in it. Here are the objects:
First of all, Get-Culture returns an instance of a CultureInfo object:
PS C:\> (get-culture).gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
False False ISECultureInfo System.Globalization.CultureInfo
This object has a number of methods and properties, as shown here:
PS C:\> get-culture | gm
TypeName: Microsoft.Windows.PowerShell.Gui.Internal.ISECultureInfo
Name MemberType Definition
---- ---------- ----------
ClearCachedData Method void ClearCachedData()
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
Equals Method bool Equals(System.Object value)
GetConsoleFallbackUICulture Method cultureinfo GetConsoleFallbackUICulture()
GetFormat Method System.Object GetFormat(type formatType), System.Object IFormat...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Calendar Property System.Globalization.Calendar Calendar {get;}
CompareInfo Property System.Globalization.CompareInfo CompareInfo {get;}
CultureTypes Property System.Globalization.CultureTypes CultureTypes {get;}
DateTimeFormat Property System.Globalization.DateTimeFormatInfo DateTimeFormat {get;set;}
DisplayName Property string DisplayName {get;}
EnglishName Property string EnglishName {get;}
IetfLanguageTag Property string IetfLanguageTag {get;}
IsNeutralCulture Property bool IsNeutralCulture {get;}
IsReadOnly Property bool IsReadOnly {get;}
KeyboardLayoutId Property int KeyboardLayoutId {get;}
LCID Property int LCID {get;}
Name Property string Name {get;}
NativeName Property string NativeName {get;}
NumberFormat Property System.Globalization.NumberFormatInfo NumberFormat {get;set;}
OptionalCalendars Property System.Globalization.Calendar[] OptionalCalendars {get;}
Parent Property cultureinfo Parent {get;}
TextInfo Property System.Globalization.TextInfo TextInfo {get;}
ThreeLetterISOLanguageName Property string ThreeLetterISOLanguageName {get;}
ThreeLetterWindowsLanguageName Property string ThreeLetterWindowsLanguageName {get;}
TwoLetterISOLanguageName Property string TwoLetterISOLanguageName {get;}
UseUserOverride Property bool UseUserOverride {get;}
Notice that the TextInfo property actually contains another object. It is a TextInfo object from the System.Globalization namespace—the same namespace that contains the CultureInfo object.
The TextInfo object also has the following methods and properties associated with it:
PS C:\> ((get-culture).textinfo) | gm
TypeName: System.Globalization.TextInfo
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
OnDeserialization Method void IDeserializationCallback.OnDeserialization(System.Object sender)
ToLower Method char ToLower(char c), string ToLower(string str)
ToString Method string ToString()
ToTitleCase Method string ToTitleCase(string str)
ToUpper Method char ToUpper(char c), string ToUpper(string str)
ANSICodePage Property int ANSICodePage {get;}
CultureName Property string CultureName {get;}
EBCDICCodePage Property int EBCDICCodePage {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsRightToLeft Property bool IsRightToLeft {get;}
LCID Property int LCID {get;}
ListSeparator Property string ListSeparator {get;set;}
MacCodePage Property int MacCodePage {get;}
OEMCodePage Property int OEMCodePage {get;}
One of these methods is the ToTitleCase method. It accepts a string, and returns a string.
When we have a string object, we have access to string methods and properties. This is shown here:
PS C:\> (Get-Culture).textinfo.ToTitleCase($d.name) | Gm
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
CompareTo Method int CompareTo(System.Object value), int CompareTo(string strB), in...
Contains Method bool Contains(string value)
CopyTo Method void CopyTo(int sourceIndex, char[] destination, int destinationIn...
EndsWith Method bool EndsWith(string value), bool EndsWith(string value, System.St...
Equals Method bool Equals(System.Object obj), bool Equals(string value), bool Eq...
GetEnumerator Method System.CharEnumerator GetEnumerator(), System.Collections.IEnumera...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
GetTypeCode Method System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTyp...
IndexOf Method int IndexOf(char value), int IndexOf(char value, int startIndex), ...
IndexOfAny Method int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int sta...
Insert Method string Insert(int startIndex, string value)
IsNormalized Method bool IsNormalized(), bool IsNormalized(System.Text.NormalizationFo...
LastIndexOf Method int LastIndexOf(char value), int LastIndexOf(char value, int start...
LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf,...
Normalize Method string Normalize(), string Normalize(System.Text.NormalizationForm...
PadLeft Method string PadLeft(int totalWidth), string PadLeft(int totalWidth, cha...
PadRight Method string PadRight(int totalWidth), string PadRight(int totalWidth, c...
Remove Method string Remove(int startIndex, int count), string Remove(int startI...
Replace Method string Replace(char oldChar, char newChar), string Replace(string ...
Split Method string[] Split(Params char[] separator), string[] Split(char[] sep...
StartsWith Method bool StartsWith(string value), bool StartsWith(string value, Syste...
Substring Method string Substring(int startIndex), string Substring(int startIndex,...
ToBoolean Method bool IConvertible.ToBoolean(System.IFormatProvider provider)
ToByte Method byte IConvertible.ToByte(System.IFormatProvider provider)
ToChar Method char IConvertible.ToChar(System.IFormatProvider provider)
ToCharArray Method char[] ToCharArray(), char[] ToCharArray(int startIndex, int length)
ToDateTime Method datetime IConvertible.ToDateTime(System.IFormatProvider provider)
ToDecimal Method decimal IConvertible.ToDecimal(System.IFormatProvider provider)
ToDouble Method double IConvertible.ToDouble(System.IFormatProvider provider)
ToInt16 Method int16 IConvertible.ToInt16(System.IFormatProvider provider)
ToInt32 Method int IConvertible.ToInt32(System.IFormatProvider provider)
ToInt64 Method long IConvertible.ToInt64(System.IFormatProvider provider)
ToLower Method string ToLower(), string ToLower(cultureinfo culture)
ToLowerInvariant Method string ToLowerInvariant()
ToSByte Method sbyte IConvertible.ToSByte(System.IFormatProvider provider)
ToSingle Method float IConvertible.ToSingle(System.IFormatProvider provider)
ToString Method string ToString(), string ToString(System.IFormatProvider provider...
ToType Method System.Object IConvertible.ToType(type conversionType, System.IFor...
ToUInt16 Method uint16 IConvertible.ToUInt16(System.IFormatProvider provider)
ToUInt32 Method uint32 IConvertible.ToUInt32(System.IFormatProvider provider)
ToUInt64 Method uint64 IConvertible.ToUInt64(System.IFormatProvider provider)
ToUpper Method string ToUpper(), string ToUpper(cultureinfo culture)
ToUpperInvariant Method string ToUpperInvariant()
Trim Method string Trim(Params char[] trimChars), string Trim()
TrimEnd Method string TrimEnd(Params char[] trimChars)
TrimStart Method string TrimStart(Params char[] trimChars)
Chars ParameterizedProperty char Chars(int index) {get;}
Length Property int Length {get;}
One of these string methods is the Split method. It also returns a string:
PS C:\> (Get-Culture).textinfo.ToTitleCase($d.name).split(',') | gm
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
CompareTo Method int CompareTo(System.Object value), int CompareTo(string strB), in...
Contains Method bool Contains(string value)
CopyTo Method void CopyTo(int sourceIndex, char[] destination, int destinationIn...
EndsWith Method bool EndsWith(string value), bool EndsWith(string value, System.St...
Equals Method bool Equals(System.Object obj), bool Equals(string value), bool Eq...
GetEnumerator Method System.CharEnumerator GetEnumerator(), System.Collections.IEnumera...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
GetTypeCode Method System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTyp...
IndexOf Method int IndexOf(char value), int IndexOf(char value, int startIndex), ...
IndexOfAny Method int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int sta...
Insert Method string Insert(int startIndex, string value)
IsNormalized Method bool IsNormalized(), bool IsNormalized(System.Text.NormalizationFo...
LastIndexOf Method int LastIndexOf(char value), int LastIndexOf(char value, int start...
LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf,...
Normalize Method string Normalize(), string Normalize(System.Text.NormalizationForm...
PadLeft Method string PadLeft(int totalWidth), string PadLeft(int totalWidth, cha...
PadRight Method string PadRight(int totalWidth), string PadRight(int totalWidth, c...
Remove Method string Remove(int startIndex, int count), string Remove(int startI...
Replace Method string Replace(char oldChar, char newChar), string Replace(string ...
Split Method string[] Split(Params char[] separator), string[] Split(char[] sep...
StartsWith Method bool StartsWith(string value), bool StartsWith(string value, Syste...
Substring Method string Substring(int startIndex), string Substring(int startIndex,...
ToBoolean Method bool IConvertible.ToBoolean(System.IFormatProvider provider)
ToByte Method byte IConvertible.ToByte(System.IFormatProvider provider)
ToChar Method char IConvertible.ToChar(System.IFormatProvider provider)
ToCharArray Method char[] ToCharArray(), char[] ToCharArray(int startIndex, int length)
ToDateTime Method datetime IConvertible.ToDateTime(System.IFormatProvider provider)
ToDecimal Method decimal IConvertible.ToDecimal(System.IFormatProvider provider)
ToDouble Method double IConvertible.ToDouble(System.IFormatProvider provider)
ToInt16 Method int16 IConvertible.ToInt16(System.IFormatProvider provider)
ToInt32 Method int IConvertible.ToInt32(System.IFormatProvider provider)
ToInt64 Method long IConvertible.ToInt64(System.IFormatProvider provider)
ToLower Method string ToLower(), string ToLower(cultureinfo culture)
ToLowerInvariant Method string ToLowerInvariant()
ToSByte Method sbyte IConvertible.ToSByte(System.IFormatProvider provider)
ToSingle Method float IConvertible.ToSingle(System.IFormatProvider provider)
ToString Method string ToString(), string ToString(System.IFormatProvider provider...
ToType Method System.Object IConvertible.ToType(type conversionType, System.IFor...
ToUInt16 Method uint16 IConvertible.ToUInt16(System.IFormatProvider provider)
ToUInt32 Method uint32 IConvertible.ToUInt32(System.IFormatProvider provider)
ToUInt64 Method uint64 IConvertible.ToUInt64(System.IFormatProvider provider)
ToUpper Method string ToUpper(), string ToUpper(cultureinfo culture)
ToUpperInvariant Method string ToUpperInvariant()
Trim Method string Trim(Params char[] trimChars), string Trim()
TrimEnd Method string TrimEnd(Params char[] trimChars)
TrimStart Method string TrimStart(Params char[] trimChars)
Chars ParameterizedProperty char Chars(int index) {get;}
Length Property int Length {get;}
The Split method returns a string, and one of those methods is the Trim method, which you can see here:
PS C:\> (Get-Culture).textinfo.ToTitleCase($d.name).split(',') | gm
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
CompareTo Method int CompareTo(System.Object value), int CompareTo(string strB), in...
Contains Method bool Contains(string value)
CopyTo Method void CopyTo(int sourceIndex, char[] destination, int destinationIn...
EndsWith Method bool EndsWith(string value), bool EndsWith(string value, System.St...
Equals Method bool Equals(System.Object obj), bool Equals(string value), bool Eq...
GetEnumerator Method System.CharEnumerator GetEnumerator(), System.Collections.IEnumera...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
GetTypeCode Method System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTyp...
IndexOf Method int IndexOf(char value), int IndexOf(char value, int startIndex), ...
IndexOfAny Method int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int sta...
Insert Method string Insert(int startIndex, string value)
IsNormalized Method bool IsNormalized(), bool IsNormalized(System.Text.NormalizationFo...
LastIndexOf Method int LastIndexOf(char value), int LastIndexOf(char value, int start...
LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf,...
Normalize Method string Normalize(), string Normalize(System.Text.NormalizationForm...
PadLeft Method string PadLeft(int totalWidth), string PadLeft(int totalWidth, cha...
PadRight Method string PadRight(int totalWidth), string PadRight(int totalWidth, c...
Remove Method string Remove(int startIndex, int count), string Remove(int startI...
Replace Method string Replace(char oldChar, char newChar), string Replace(string ...
Split Method string[] Split(Params char[] separator), string[] Split(char[] sep...
StartsWith Method bool StartsWith(string value), bool StartsWith(string value, Syste...
Substring Method string Substring(int startIndex), string Substring(int startIndex,...
ToBoolean Method bool IConvertible.ToBoolean(System.IFormatProvider provider)
ToByte Method byte IConvertible.ToByte(System.IFormatProvider provider)
ToChar Method char IConvertible.ToChar(System.IFormatProvider provider)
ToCharArray Method char[] ToCharArray(), char[] ToCharArray(int startIndex, int length)
ToDateTime Method datetime IConvertible.ToDateTime(System.IFormatProvider provider)
ToDecimal Method decimal IConvertible.ToDecimal(System.IFormatProvider provider)
ToDouble Method double IConvertible.ToDouble(System.IFormatProvider provider)
ToInt16 Method int16 IConvertible.ToInt16(System.IFormatProvider provider)
ToInt32 Method int IConvertible.ToInt32(System.IFormatProvider provider)
ToInt64 Method long IConvertible.ToInt64(System.IFormatProvider provider)
ToLower Method string ToLower(), string ToLower(cultureinfo culture)
ToLowerInvariant Method string ToLowerInvariant()
ToSByte Method sbyte IConvertible.ToSByte(System.IFormatProvider provider)
ToSingle Method float IConvertible.ToSingle(System.IFormatProvider provider)
ToString Method string ToString(), string ToString(System.IFormatProvider provider...
ToType Method System.Object IConvertible.ToType(type conversionType, System.IFor...
ToUInt16 Method uint16 IConvertible.ToUInt16(System.IFormatProvider provider)
ToUInt32 Method uint32 IConvertible.ToUInt32(System.IFormatProvider provider)
ToUInt64 Method uint64 IConvertible.ToUInt64(System.IFormatProvider provider)
ToUpper Method string ToUpper(), string ToUpper(cultureinfo culture)
ToUpperInvariant Method string ToUpperInvariant()
Trim Method string Trim(Params char[] trimChars), string Trim()
TrimEnd Method string TrimEnd(Params char[] trimChars)
TrimStart Method string TrimStart(Params char[] trimChars)
Chars ParameterizedProperty char Chars(int index) {get;}
Length Property int Length {get;}
So, it would be possible to rewrite the one line of code in about five other lines. It might appear like this:
$culture = (Get-Culture)
$txtInfo = $culture.textinfo
$titleCase = $textInfo.ToTitleCase($d.name)
$splitTitle = $titleCase.Split(',')
$trimedSplitTitle = $splitTitle.trim()
But in reality, I am not sure that code is easier to read. In fact, for me it is not easier to read. It might be better for beginners, so that they can easily see what object they are dealing with at each stage of the progression; but otherwise, it really doesn’t make sense to use five different variables for each stage of the progression. In fact, after you learn how to read the code, it makes sense to present it on a single line.
There is no Windows PowerShell cmdlet that will do this for you. So if you want to groom the string, you need to write a complicated RegEx expression or use these string methods. For me, the string methods are easier to understand.
Now you know how to use Windows PowerShell to work with strings. Join me tomorrow when I will talk about more cool stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy