Reputation: 21
Good afternoon. I'm trying to read the performance counters from a Windows machine to a CSV file. I was able to do'it with success. The problem is that, although I set the Encoding to UTF8 I still can't get characters like 'ç' or 'õ' in my CSV result. Instead, when I use Excell to see the extraction I get '??' characters in their place.
From the web related problems, I was not able to find a solution that fit my "problem". Thanks in advance guys.
#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
Upvotes: 1
Views: 677
Reputation: 21
So, I redo my script in order to solve the problem. I'm making it available to someone that may need him for future work.
#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
}
Upvotes: 1
Reputation: 27576
It should work, unless you're appending to a file that doesn't have a Utf8 BOM (EF BB BF) at the beginning of the file.
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 
Upvotes: 1