The last week or so I've been playing with a new PowerShell project from Dave Carroll for using Twitter from a PowerShell prompt. The module is called BluebirdPS and you can install it from the PowerShell Gallery. The module is very much still in its early stages but is functional and intriguing. The reason you might find this interesting is not so much Twitter, but how Dave leverages the Twitter APIs. You might find yourself working with a different API to build a PowerShell-based tool. As you tackle these projects, you always want to be thinking about "objects in the pipeline", and part of that means creating proper PowerShell property names.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Make It User Friendly
When you build a PowerShell tool, you want the output to be easy to use. To me, this means having clearly defined property names. Dave has a command in the module to get a Twitter user account. Here's what it currently writes to the pipeline.
For the sake of demonstration, assume that the Get-TwitterUser command is your code that is invoking a REST API and returning a custom object to the pipeline.
The property names are mostly clear, although not very PowerShell friendly. How many native PowerShell commands do you run that have properties that look like this? Let's fix this.
Convert-PropertyName
Some property names are multi-word using an underscore as a delimiter. This is typical, but I suppose some API might create a property like default-profile. In PowerShell, I'd argue that a better property name would be DefaultProfile. Here's one way to change it.
First, let me get a sample object.
$me = Get-TwitterUser -ScreenName jeffhicks
How do I get the property names? PowerShell does a lot of abstraction under-the-hood to make it easy to use. The object represented by $me has another layer.
The properties collection can be quite useful.
To "re-define" the property name, walk through the process in your head or write it out.
- Split the name on the _ delimiter
- For each element in the array capitalize the first letter
- Join the array back to a single string with no spaces.
I need a PowerShell function to achieve this task. As you can hopefully see from my list, I've practically written the core code.
Function Convert-PropertyName {
Param(
[Parameter(Mandatory)]
[string]$Name,
#the character used as a delimiter in the native property name
[string]$Delimiter = "_"
)
#split on the underscore delimiter
$split = $name -split $Delimiter
#capitalize the first letter of each item in the array
for ($i=0;$i -lt $split.count;$i++) {
$split[$i] = "{0}{1}" -f $split[$i][0].ToString().ToUpper(),$split[$i].Substring(1)
}
#rejoin with no spaces and write the result to the pipeline
$split -join ""
}
I wrote the function to be flexible and not assuming that all property names will be using the underscore.
Building an Object
With this function in mind, I can write a simple piece of PowerShell code to create a new custom object.
$me.psobject.properties | Foreach-object -Begin {
$newObj = [ordered]@{
PSTypeName = "BlueBirdUser"
}
} -process {
$newProp = Convert-PropertyName $_.Name
$newObj.Add($newProp,$_.value)
} -end {
#write the result as a custom object
[PSCustomObject]$newObj
}
The code is creating an ordered hashtable then adds an entry for each converted property name and the corresponding value from the psobject. At the end of ForEach-Object, I write an actual object to the pipeline.
I could take this code and build tooling around the core API code that now writes a "better" PowerShell object to the pipeline. There are still potential issues with property values. For example, CreatedAt is a string and not a datetime value. That can be addressed later.
Update-TypeData
One last task you might want to undertake is to refine how PowerShell uses your new custom object. Right now, my code writes an object with all properties. While that could be useful, it may be that by default the user only needs to see a subset of properties. Or you might want to fine-tune some of the property names. For example, my output now has a property called StatusesCount. What that really means is the number of tweets. It would be more user-friendly to change that property name.
All of this is where the Update-TypeData cmdlet comes into the picture. In order to use this cmdlet, your object must have a defined and unique type name. None of this will work with a generic pscustomobject. In my code, you may have noticed this:
PSTypeName = "BlueBirdUser"
If I run my code and pipe to Get-Member, I'll see a TypeName of BlueBirdUser. This means I can use Update-TypeData. I'm trusting you will read full help and examples.
First, I want to create some property aliases. PowerShell does this all the time for you.
Update-TypeData -TypeName BlueBirdUser -MemberType AliasProperty -MemberName Followers -Value FollowersCount -force
Update-TypeData -TypeName BlueBirdUser -MemberType AliasProperty -MemberName Tweets -Value StatusesCount -Force
The other step is that I want to define a default set of properties so that when my command is run, and the custom object written to the pipeline, unless the user asks for anything else, it will display a default property set.
Update-TypeData -TypeName BlueBirdUser -DefaultDisplayPropertySet "Name","ScreenName","ID","Location","Description","Followers","Tweets" -force
If you were building a module, you might have Convert-Property as a private function, and a command like this as a public function.
Function Get-TwitterAccount {
[cmdletbinding()]
Param([string]$Username = "jeffhicks")
#Get-TwitterUser could be any REST API related code that creates an objecgt
$TwitterUser = Get-TwitterUser -ScreenName $UserName
$TwitterUser.psobject.properties | ForEach-Object -Begin {
$newObj = [ordered]@{
PSTypeName = "BlueBirdUser"
}
} -Process {
$newProp = Convert-PropertyName $_.Name
$newObj.Add($newProp, $_.value)
} -End {
#write the result as a custom object
[PSCustomObject]$newObj
}
}
Now I have a PowerShell tool that writes proper, well-structured objects to the pipeline that I can use like any other command.
1 thought on “Creating PowerShell Property Names”
Comments are closed.