CSV 脚本的 PowerShell 获取计数器,编码问题
Posted
技术标签:
【中文标题】CSV 脚本的 PowerShell 获取计数器,编码问题【英文标题】:PowerShell Get-Counter to CSV Script, Encoding Problem 【发布时间】:2020-03-07 16:18:09 【问题描述】:下午好。我正在尝试将性能计数器从 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
【问题讨论】:
【参考方案1】:它应该可以工作,除非您附加到文件开头没有 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 
【讨论】:
我能够通过以下示例导出到具有正确编码的 CSV:$CounterPT = "\Processor(*)*" $CounterPT |获取计数器 - 连续 | Export-CsvFile $outfile -Append -NoTypeInformation -encoding UTF8 因此这让我相信问题出在自定义CSV格式的代码中。 感谢您的帮助。这是导出并使用您的行后的结果: Path: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00000000 22 63 6F "co 我会使用export-csv
。或add-content
。 Out-file -append
不检查 BOM。【参考方案2】:
所以,我重做我的脚本以解决问题。 我正在将它提供给可能需要他用于未来工作的人。
#Get IP and Machine Name
$IPAddress = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object $_.Ipaddress.length -gt 1
$IPAddress = $IPAddress.ipaddress[0].ToString()
$IPAddress = $IPAddress -replace '\.', '_'
#Define output filepath
$TimeStamp=Get-Date -Format "#dd_MM_yyyy#HH_mm_ss"
$TimeStamp =$TimeStamp.ToString()
$TimeStamp = $TimeStamp -replace ':', '_'
$outfile="C:\" + $env:computername + '#'+ $IPAddress + $TimeStamp + "#CounterResults" + '.csv'
$outfileErrors="C:\" + $env:computername + '#'+ $IPAddress + $TimeStamp + "#CounterErrors" + '.txt'
################################################################################################################
################################################################################################################
#Actual script starts here
$Counters = @(
'\Memory\*'
)
try
$ErrorActionPreference = "Stop"; #Make all errors terminating so that try/catch works
Get-Counter -Counter $Counters -Continuous | ForEach
$_.CounterSamples | ForEach
[pscustomobject]@
TimeStamp = $_.TimeStamp
ComputerName=[String]$ENV:ComputerName
Path = ($_.Path -split "\\")[-2,-1] -join "-" ;
Value = [Math]::Round($_.CookedValue,2)
| Export-Csv -Path $outfile -Append -NoTypeInformation -Encoding UTF8
catch
$_|Out-File $outfileErrors -Append
【讨论】:
以上是关于CSV 脚本的 PowerShell 获取计数器,编码问题的主要内容,如果未能解决你的问题,请参考以下文章
如何使用Powershell脚本获取Azure VM来宾指标(性能计数器)
powershell Powershell脚本获取OU的所有活动目录用户并生成计数
获取与 powershell 计数器一起使用的 cpu 百分比
输出 csv 文件时,Powershell 脚本在服务器上使用大量内存