0

質問

en-GBカルチャを使用した Windows セッションで実行するときに、PowerShell を強制的にフランス語形式で CSV にエクスポートすることはできますか?

より詳しい情報

フランスのカルチャ ルールを使用して一部のデータを CSV にエクスポートしたいと考えています (つまり、CSV の区切り文字はセミコロンに設定されていますが、小数点以下の桁数にコンマを使用する数値やその他のカルチャ形式の違いもあるため、-Delimiterパラメーターを使用するだけでは十分ではありません)。

以下のコードを思いつきました( https://stackoverflow.com/a/7052955/361842に基づく)

function Set-Culture
{
    [CmdletBinding(DefaultParameterSetName='ByCode')]
    param (
        [Parameter(Mandatory,ParameterSetName='ByCode',Position=1)]
        [string] $CultureCode
        ,
        [Parameter(Mandatory,ParameterSetName='ByCulture',Position=1)]
        [System.Globalization.CultureInfo] $Culture
    )
    begin {
        [System.Globalization.CultureInfo] $Culture = [System.Globalization.CultureInfo]::GetCultureInfo($CultureCode) 
    }
    process {
        [System.Threading.Thread]::CurrentThread.CurrentUICulture = $Culture
        [System.Threading.Thread]::CurrentThread.CurrentCulture = $Culture
    }
}

function Invoke-CommandInCulture {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory,ParameterSetName='ByCode',Position=1)]
        [string]$CultureCode
        ,
        [Parameter(Mandatory,Position=2)]
        [ScriptBlock]$Code
    )
    process {
        $OriginalCulture = Get-Culture
        try 
        {
            Set-Culture $CultureCode
            Write-Verbose (Get-Culture) #this always returns en-GB
            Invoke-Command -ScriptBlock $Code
        }
        finally 
        {
            Set-Culture $OriginalCulture
        }
    }
}

次のコードは、このメソッドが機能することを示しています。

Invoke-CommandInCulture -CultureCode 'fr' -Code {
    [System.Threading.Thread]::CurrentThread.CurrentUICulture
    [System.Threading.Thread]::CurrentThread.CurrentCulture
} #shows that the command's thread's culture is French

Invoke-CommandInCulture -CultureCode 'fr' -Code {
    get-date
} #returns the current date in French 

ただし、PowerShell には、何が起こっているかについての独自の考えがあります。

Invoke-CommandInCulture -CultureCode 'fr' -Code {
    get-culture
    "PSCulture: $PSCulture"
    "PSUICulture: $PSUICulture"        
} #returns my default (en-GB) culture; not the thread's culture

これは、CSV に変換するためのロジックに影響を与えます。

Invoke-CommandInCulture -CultureCode 'fr' -Code {
    get-process | ConvertTo-CSV -UseCulture
} #again, uses my default culture's formatting rules; not the FR ones
4

1 に答える 1

0

回避策 #1: 特定のカルチャで値を文字列に変換するカスタム関数

回避策は次のとおりです。指定されたカルチャを使用して各フィールドを文字列に変換してから、文字列値を CSV に変換します。

function ConvertTo-SpecifiedCulture {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory,ValueFromPipeline)]
        [PSObject]$InputObject
        ,
        [Parameter(Mandatory)]
        [string]$CultureCode
        ,
        [Parameter(ParameterSetName='DefaultParameter', Position=0)]
        [System.Object[]]$Property
    )
    begin {
        [System.Globalization.CultureInfo] $Culture = [System.Globalization.CultureInfo]::GetCultureInfo($CultureCode) 
    }
    process {
        if($Property -eq $null) {$Property = $InputObject.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames}
        $Result = new-object -TypeName PSObject -Property @{}
        $Property | %{
            $Result | Add-Member -MemberType NoteProperty -Name $_ -Value ($InputObject."$_").ToString($Culture) 
        }
        $Result 
    }
}

Get-Process | select -first 2 | ConvertTo-SpecifiedCulture -CultureCode 'fr' | ConvertTo-CSV -Delimiter ';'

回避策 #2: 現在のカルチャをオーバーライドしてターゲット カルチャに一致させる

もう 1 つのオプションは、現在のカルチャの設定を変更して、必要なカルチャの設定を共有することです。これはもっとハックに感じます。ただし、シナリオによっては、上記よりもクリーンで実用的なものになる場合があります。

たとえば、FR の数値形式を使用するには、現在のカルチャの数値形式を FR に一致するように更新するだけです。

$(Get-Culture).NumberFormat = ([System.Globalization.CultureInfo]'FR').NumberFormat

...そして、残りの (設定可能な) プロパティについても同様に行うことができます:

function Set-CurrentCulture {
    [CmdletBinding()]
    param (
        [string]$CultureCode
    )
    begin {
        $Global:FakedCurrentCulture = $CultureCode #in case we need a reference to the current culture's name
        [System.Globalization.CultureInfo]$NewCulture = [System.Globalization.CultureInfo]::GetCultureInfo($CultureCode)
        [System.Globalization.CultureInfo]$ReferenceToCurrentCulture = Get-Culture
        Write-Verbose "Switching Defintion to $($NewCulture.Name)"
    }
    process {
        #NB: At time of writing, the only settable properties are NumberFormatInfo & DateTimeFormatInfo
        $ReferenceToCurrentCulture.psobject.properties | ?{$_.isSettable} | %{
            $propertyName = $_.Name
            write-verbose "Setting property $propertyName"
            write-verbose "- from: $($ReferenceToCurrentCulture."$propertyName")"
            write-verbose "- to: $($NewCulture."$propertyName")"
            $ReferenceToCurrentCulture."$propertyName" = $NewCulture."$propertyName"
        }
        #ListSeparator
        $ReferenceToCurrentCulture.TextInfo.psobject.properties | ?{$_.isSettable} | %{
            $propertyName = $_.Name
            write-verbose "Setting property TextInfo.$propertyName"
            write-verbose "- from: $($ReferenceToCurrentCulture.TextInfo."$propertyName")"
            write-verbose "- to: $($NewCulture.TextInfo."$propertyName")"
            $ReferenceToCurrentCulture.TextInfo."$propertyName" = $NewCulture."$propertyName"
        }
        #for some reason this errors
        #Localized, TwoDigitYearMax
        <#
        $ReferenceToCurrentCulture.Calendar.psobject.properties | ?{$_.isSettable} | %{
            $propertyName = $_.Name
            write-verbose "Setting property Calendar.$propertyName"
            write-verbose "- from: $($ReferenceToCurrentCulture.Calendar."$propertyName")"
            write-verbose "- to: $($NewCulture.Calendar."$propertyName")"
            $ReferenceToCurrentCulture.Calendar."$propertyName" = $NewCulture."$propertyName"
        }
        #>
    }
}

function Reset-CurrentCulture {
    [CmdletBinding()]
    param ()
    process {
        Set-CurrentCulture -CultureCode ((get-culture).Name)
    }
}

function Test-It {
    [CmdletBinding()]
    param ()
    begin {
        write-verbose "Current Culture: $Global:FakedCurrentCulture" 
    }
    process {
         1..5 | %{
            New-Object -TypeName PSObject -Property @{
                Integer = $_
                String = "Hello $_"
                Numeric = 2.139 * $_
                Money = (2.139 * $_).ToString('c')
                Date = (Get-Date).AddDays($_)
            }
         } | ConvertTo-Csv -NoTypeInformation
    }
}


Set-CurrentCulture 'fr' -Verbose
Test-It
Set-CurrentCulture 'en-GB' -Verbose
Test-It
Set-CurrentCulture 'en-US' -Verbose
Test-It
Set-CurrentCulture 'ar-DZ' -Verbose
Test-It

Reset-CurrentCulture -Verbose
Test-It

さらに進んで、読み取り専用プロパティの上書きを検討する可能性があります (これは可能です: https://learn-powershell.net/2016/06/27/quick-hits-writing-to-a-read-only-property/ )...しかし、これはすでに非常に厄介です。私のニーズには上記で十分だったので、私はそこに行くつもりはありません。

于 2016-11-29T16:41:43.617 に答える