Is it possible to bind New-Item -Value parameter ByPropertyName?
No, because as you have already noticed, the parameter type is System.Object and since all objects inherit from this class every input from pipeline is bound with ValueFromPipeline instead of ValueFromPipelineByPropertyName.
Should the type for this parameter be other than System.Object?
No, because it would conflict with other providers. In example, defining a new function would no longer be possible:
$null = New-Item -Path function:Say-Hello -Value {
'hey there'
}
Say-Hello
Should the -Value parameter be enabled to bind by Property Name?
Probably not, because it can never be bound by it.
Is there a workaround?
You could have a ProxyCommand or wrapper function around New-Item that changes the parameter type from System.Object to System.String, this way the function would be able to work properly taking ValueFromPipeline and ValueFromPipelineByPropertyName. You could then store this wrapper in your $PROFILE and have it available for you each time a new session is started.
For the reasons stated before, this wrapper would only work targetting the FileSystem provider and has been hardcoded for ItemType = File.
function New-File {
[CmdletBinding(DefaultParameterSetName='pathSet', SupportsShouldProcess=$true, ConfirmImpact='Medium', HelpUri='https://go.microsoft.com/fwlink/?LinkID=2096592')]
param(
[Parameter(ParameterSetName='pathSet', Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
[Parameter(ParameterSetName='nameSet', Position=0, ValueFromPipelineByPropertyName=$true)]
[string[]]
${Path},
[Parameter(ParameterSetName='nameSet', Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
[AllowNull()]
[AllowEmptyString()]
[string]
${Name},
[Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[Alias('Target')]
[string]
${Value},
[switch]
${Force}
)
begin {
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref] $outBuffer)) {
$PSBoundParameters['OutBuffer'] = 1
}
$PSBoundParameters['ItemType'] = 'File'
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\New-Item', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = { & $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
}
process {
try {
$steppablePipeline.Process($Value)
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
}
end {
try {
$steppablePipeline.End()
} catch {
$PSCmdlet.ThrowTerminatingError($_)
}
}
<#
.ForwardHelpTargetName Microsoft.PowerShell.Management\New-Item
.ForwardHelpCategory Cmdlet
#>
}
[PSCustomObject]@{ Value = "Lorem ipsum" } | New-File .\BPN_value.txt -Force
"Lorem ipsum" | New-File .\BPN_value2.txt -Force
For reference, the definition of the code used above was autogenerated using:
[System.Management.Automation.ProxyCommand]::Create((Get-Command New-Item))
Then it has been slightly modified and simplified for this specific answer.