首页 > 解决方案 > CSV 脚本的 PowerShell 获取计数器,编码问题

问题描述

下午好。我正在尝试将性能计数器从 Windows 机器读取到 CSV 文件。我能够成功地做到这一点。问题是,尽管我将编码设置为 UTF8,但我仍然无法在 CSV 结果中获得像“ç”或“õ”这样的字符。相反,当我使用 Excell 查看提取时,我得到 '??' 代替他们的角色。

从与网络相关的问题中,我无法找到适合我的“问题”的解决方案。提前谢谢各位。

#Define Input and output filepath

$servers=get-content ...
$outfile=...

################################################################################################################

#Function to have the customized output in CSV format
function Export-CsvFile {
[CmdletBinding(DefaultParameterSetName='Delimiter',
  SupportsShouldProcess=$true, ConfirmImpact='Medium')]
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true,
           ValueFromPipelineByPropertyName=$true)]
[System.Management.Automation.PSObject]
${InputObject},

[Parameter(Mandatory=$true, Position=0)]
[Alias('PSPath')]
[System.String]
${Path},

#region -Append 
[Switch]
${Append},
#endregion 

[Switch]
${Force},

[Switch]
${NoClobber},

[ValidateSet('Unicode','UTF7','UTF8','ASCII','UTF32','BigEndianUnicode','Default','OEM')]
[System.String]
${Encoding},

[Parameter(ParameterSetName='Delimiter', Position=1)]
[ValidateNotNull()]
[System.Char]
${Delimiter},

[Parameter(ParameterSetName='UseCulture')]
[Switch]
${UseCulture},

[Alias('NTI')]
[Switch]
${NoTypeInformation})

begin
{
# This variable will tell us whether we actually need to append
# to existing file
$AppendMode = $false

 try {
  $outBuffer = $null
  if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  {
      $PSBoundParameters['OutBuffer'] = 1
  }
  $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Export-Csv',
    [System.Management.Automation.CommandTypes]::Cmdlet)


                #String variable to become the target command line
                $scriptCmdPipeline = ''

                # Add new parameter handling
                #region Dmitry: Process and remove the Append parameter if it is present
                if ($Append) {

                                $PSBoundParameters.Remove('Append') | Out-Null

  if ($Path) {
   if (Test-Path $Path) {        
    # Need to construct new command line
    $AppendMode = $true

    if ($Encoding.Length -eq 0) {
     # ASCII is default encoding for Export-CSV
     #$Encoding = 'ASCII'
     $Encoding = 'UTF8'
    }


    # For Append we use ConvertTo-CSV instead of Export
    $scriptCmdPipeline += 'ConvertTo-Csv -NoTypeInformation '

    # Inherit other CSV convertion parameters
    if ( $UseCulture ) {
     $scriptCmdPipeline += ' -UseCulture '
    }
    if ( $Delimiter ) {
     $scriptCmdPipeline += " -Delimiter '$Delimiter' "
    } 

    # Skip the first line (the one with the property names) 
    $scriptCmdPipeline += ' | Foreach-Object {$start=$true}'
    $scriptCmdPipeline += '{if ($start) {$start=$false} else {$_}} '

    # Add file output
    $scriptCmdPipeline += " | Out-File -FilePath '$Path' -Encoding '$Encoding' -Append "

    if ($Force) {
     $scriptCmdPipeline += ' -Force'
    }

    if ($NoClobber) {
     $scriptCmdPipeline += ' -NoClobber'
    }   
   }
  }
} 



 $scriptCmd = {& $wrappedCmd @PSBoundParameters }

 if ( $AppendMode ) {
  # redefine command line
  $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
      $scriptCmdPipeline
    )
} else {
  # execute Export-CSV as we got it because
  # either -Append is missing or file does not exist
  $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
      [string]$scriptCmd
    )
}

# standard pipeline initialization
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)

 } catch {
   throw
}

}

process
{
  try {
      $steppablePipeline.Process($_)
  } catch {
      throw
  }
}

end
{
  try {
      $steppablePipeline.End()
  } catch {
      throw
  }
}

}

################################################################################################################


#Actual script starts here 
#"Global": Function's Scope
function Global:Convert-HString {      
[CmdletBinding()]            
 Param             
   (
    [Parameter(Mandatory=$false,
               ValueFromPipeline=$true,
               ValueFromPipelineByPropertyName=$true)]
    [String]$HString
   )#End Param

Begin 
{
    Write-Verbose "Converting Here-String to Array"
}#Begin
Process 
{
    $HString -split "`n" | ForEach-Object {

        $ComputerName = $_.trim()
        if ($ComputerName -notmatch "#")
            {
                $ComputerName
            }    


        }
}#Process
End 
{
    # Nothing to do here.
}#End

}#Convert-HString


#Performance counters declaration

function Get-CounterStats { 
param 
    ( 
    [String]$ComputerName = $ENV:ComputerName

    ) 

$Object =@()

######################################List of the desired Counters#########################333

$CounterEN = @" 
Processor(_Total)\*
Memory\*
"@ 

        (Get-Counter -ComputerName $ComputerName -Counter (Convert-HString -HString $CounterEN)) |  
        ForEach-Object { 
        $path = $_.path 
        New-Object PSObject -Property @{
        computerName=$ComputerName
        Counter        = ($path  -split "\\")[-2,-1] -join "-" 
        Item        = $_.InstanceName 
        Value = [Math]::Round($_.CookedValue,2)
        datetime=(Get-Date -format "yyyy-MM-d hh:mm:ss")
        } 

        }


} 

#Collecting counter information for target servers

foreach($server in $Servers)
{
$d=Get-CounterStats -ComputerName $server |Select-Object computerName,Counter,Item,Value,datetime
$d |Export-CsvFile $outfile  -Append -NoTypeInformation -Encoding UTF8

}

#End of Script

标签: powershellperformancecountercmdletexport-csv

解决方案


它应该可以工作,除非您附加到文件开头没有 Utf8 BOM (EF BB BF) 的文件。

get-content file.csv -Encoding byte | select -first 3 | format-hex


           Path:

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   EF BB BF                                         

推荐阅读