DateTime 对象文化在管道函数之间丢失

Ral*_*ngs 5 powershell

我有两个功能get-foo

Function get-foo{[PSCustomObject]@{Title = 'Some Title' ; CreationTime = [datetime]::Parse('31/01/2023')}}
Run Code Online (Sandbox Code Playgroud)

set-foo

Function set-foo{  
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]$Title,

        [Parameter(ValueFromPipelineByPropertyName)]
        [string]$CreationTime

    )
    Begin{
        ([cultureinfo]::CurrentCulture).Name
    }
    Process{
        $CreationTime
    }
}
Run Code Online (Sandbox Code Playgroud)

get-foo输出一个en-gb日期,正是我想要的日期格式:

[cultureinfo]::CurrentCulture = 'en-GB' ; get-foo

Title      CreationTime
-----      ------------
Some Title 31/01/2023 00:00:00
Run Code Online (Sandbox Code Playgroud)

当我通过管道传递get-foo到时set-foo,它将[dateTime]对象转换为美国日期:

get-foo|set-foo

# en-GB
# 01/31/2023 00:00:00
Run Code Online (Sandbox Code Playgroud)

我尝试通过更改以下行来修复它set-foo

...
[Parameter(ValueFromPipelineByPropertyName)]
        [string]$CreationTime = [datetime]::Parse($CreationTime)  # [datetime]::Parse() respects the sessions culture
        #[string]$CreationTime
...
Run Code Online (Sandbox Code Playgroud)

现在我收到一个错误:

get-foo|set-foo
#ERROR: MethodInvocationException: Exception calling "Parse" with "1" argument(s): "String '' was not recognized as a valid DateTime."
Run Code Online (Sandbox Code Playgroud)

如何set-foo尊重会议文化。我需要将CreationTime参数声明为 a [string],否则ValueFromPipelineByPropertyName使用时就会出现问题。

谢谢你的帮助。

San*_*zon 2

假设您不能/不想更改$CreationDatefrom的类型(这是我建议的),但您想要格式为字符串,那么您可以做的是创建一个类,该类实现将在以下情况下string使用文化:一定会:datetimedatetimeen-GBArgumentTransformationAttribute.ToStringen-GBdatetime-CreationTime

class DateTransform : System.Management.Automation.ArgumentTransformationAttribute {
    static [cultureinfo] $culture = [cultureinfo]::GetCultureInfo('en-GB')

    [Object] Transform(
        [System.Management.Automation.EngineIntrinsics] $engineIntrinsics,
        [Object] $inputData)
    {
        if ($inputData -is [datetime]) {
            return $inputData.ToString([DateTransform]::culture)
        }

        # else, if it's a string or other type, attempt coercion to string
        return $inputData
    }
}

function set-foo {
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipelineByPropertyName)]
        [string] $Title,

        [Parameter(ValueFromPipelineByPropertyName)]
        [DateTransform()]
        [string] $CreationTime
    )

    Begin {
        ([cultureinfo]::CurrentCulture).Name
    }
    Process {
        $CreationTime
    }
}

[PSCustomObject]@{
    Title        = 'Some Title'
    CreationTime = [datetime]::new(2023, 01, 31)
} | set-foo

# Outputs:
# en-US
# 31/01/2023 00:00:00
Run Code Online (Sandbox Code Playgroud)