I'm looking for a more efficient method (for both typing time and performance) of casting data types during a PowerShell Select-Object
.
Currently, I am wrapping each individual property in an expression to cast the data type. I'm confident this isn't the correct way to do this, it just feels dirty...
The reason I am doing this is that I'm sending the data to a REST API which is applying strict validation using a JSON schema. The data in $Data
is unreliable. For example, a property is sometimes a JSON string "12345"
and occasionally an unexpected JSON Integer 12345
.
The REST API then returns a 403 error because it was not expecting an Integer for that key.
$Results = $Data | select `
@{Name = 'Name'; expression = {[string]$_.DisplayName}},
@{Name = 'Version'; expression = {[string]$_.DisplayVersion}},
@{Name = 'HelpLink'; expression = {[string]$_.HelpLink}},
@{Name = 'InstallLocation'; expression = {[string]$_.InstallLocation}},
@{Name = 'InstallSource'; expression = {[string]$_.InstallSource}},
@{Name = 'Language'; expression = {[int]$_.Language}},
@{Name = 'DisplayIcon'; expression = {[string]$_.DisplayIcon}},
@{Name = 'UninstallString'; expression = {[string]$_.UninstallString}},
@{Name = 'WindowsInstaller'; expression = {[int]$_.WindowsInstaller}},
@{Name = 'AppGUID'; expression = {[string]$_.APP_GUID}},
@{Name = 'URLInfoAbout'; expression = {[string]$_.URLInfoAbout}},
@{Name = 'Vendor'; expression = {[string]$_.Publisher}},
@{Name = 'InstallDate'; expression = {[int]$_.InstallDate}},
@{Name = 'EstimatedSize'; expression = {[int]$_.EstimatedSize}},
@{Name = 'VersionMajor'; expression = {[string]$_.VersionMajor}},
@{Name = 'VersionMinor'; expression = {[string]$_.VersionMinor}},
@{Name = 'SystemComponent'; expression = {[int]$_.SystemComponent}},
@{Name = 'NoModify'; expression = {[string]$_.NoModify}},
@{Name = 'NoRepair'; expression = {[string]$_.NoRepair}},
@{Name = 'ModifyPath'; expression = {[string]$_.ModifyPath}},
@{Name = 'BundleVersion'; expression = {[string]$_.BundleVersion}},
@{Name = 'EngineVersion'; expression = {[string]$_.EngineVersion}}
I would only cast the properties that need to be of type int
. Since PowerShell is a language based on dynamic typing, so you can do the following:
$obj = [PSCustomObject] @{ Number = "123" }
$obj.Number.GetType() # Type is string
$obj.Number = [int] $obj.Number
$obj.Number.GetType() # Type is int
Output:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
True True Int32 System.ValueType
You can find this sample online. So, you should be able to use this approach:
$Data.Language = [int] $Data.Language
In short, you've cast the properties that need to be of type int
.
UPDATE 1
If your object have a "flat" hirarchy you can try the following:
$obj = [PSCustomObject]@{
IntNr = "123"
DecNr = "4,56"
Str = "abc"
}
$result = $obj.PSObject.Properties | ForEach-Object {
[int] $parsedInt = 0
[decimal] $parsedDec = 0.0
if ([int]::TryParse($_.Value, [ref]$parsedInt)) {
$_.Value = $parsedInt
}
elseif ([decimal]::TryParse($_.Value, [ref]$parsedDec)) {
$_.Value = $parsedDec
}
$_
}
$result
Output when dumping $result
:
Value : 123
MemberType : NoteProperty
IsSettable : True
IsGettable : True
TypeNameOfValue : System.Int32
Name : IntNr
IsInstance : True
Value : 456
MemberType : NoteProperty
IsSettable : True
IsGettable : True
TypeNameOfValue : System.Decimal
Name : DecNr
IsInstance : True
Value : abc
MemberType : NoteProperty
IsSettable : True
IsGettable : True
TypeNameOfValue : System.String
Name : Str
IsInstance : True
The sample is available online under this link.