Combine Lote / WMIC + ANSI / UNICODE Formatação de saída

5

Ao criar uma ferramenta de auditoria para a minha rede, estou descobrindo que a WMIC está saindo com espaços entre cada caractere quando acompanhada por ecoar o texto normal. Por exemplo,

Isto:

@echo off
echo Foo >> "C:\test.txt"
wmic CPU Get AddressWidth >> "C:\test.txt"
wmic CPU Get Description >> "C:\test.txt"

Retorna:

Foo 
A d d r e s s W i d t h     

 6 4                         

 D e s c r i p t i o n                                                       

 I n t e l 6 4   F a m i l y   6   M o d e l   6 9   S t e p p i n g   1     

Se eu remover ( rem ) a linha echo Foo , a saída será formatada muito bem, pois há apenas um tipo de saída:

AddressWidth  
64            
Description                           
Intel64 Family 6 Model 69 Stepping 1  

Estou lendo que isso ocorre porque o WMIC é enviado para UNICODE, enquanto os comandos em lote padrão são enviados para ANSI. Ambos podem ser unidos para compartilhar um formato comum? Alguém pode explicar mais detalhadamente os diferentes tipos de formato, por que a WMIC produziria para um tipo diferente e / ou quaisquer outros fatores que contribuíssem para essa saída? Eu encontrei alguns bread crumbs , mas nada de concreto.

    
por root 16.09.2014 / 14:12

3 respostas

8

Canalize a saída de Wmic a more :
wmic CPU Get AddressWidth |more >> "C:\test.txt"

Editar para um pouco mais de fundo : o problema que você vê deve-se ao wmic output ser unicode utf-16. Isso significa que cada caractere (ou mais corretamente, a maioria deles) é codificado em dois bytes. wmic também coloca a chamada BOM (byte order mark) no início da saída. Veja o conteúdo do byte abaixo:

FF FE 44 00 65 00 73 00-63 00 72 00 69 00 70 00 ..D.e.s.c.r.i.p.

Esses dois primeiros bytes (FF FE) especificam endianness para UTF-16 e permitem que ferramentas de processamento de dados reconheçam a codificação [sendo little endian UTF-16].
Obviamente, type faz essa verificação e, se encontrar a BOM, reconhece corretamente a codificação.
Por outro lado, se você primeiro echo text e, em seguida, anexar Wmic output - não há uma lista de materiais no início e você pode ver uma codificação inconsistente:
74 65 78 74 20 0D 0A 44-00 65 00 73 00 63 00 72 text ..D.e.s.c.r

Se você colocá-lo através de type ele não pode inferir como interpretar, / mais provável / assume um único byte ('ANSI') e isso resulta em espaços produzidos para caracteres não imprimíveis (zeros, sendo de fato bytes de alta ordem codificação de caracteres de dois bytes).

more lida com mais casos (trocadilhos) e produz resultados corretos para caracteres ASCII básicos, por isso é comumente usado como um hack para esse propósito.

Uma nota adicional: alguns editores (sendo o bloco de notas o exemplo mais simples) exibirão corretamente o arquivo codificado utf-16 se ele for consistente - mesmo sem BOM. Existe uma maneira de forçar echo a produzir saída unicode (mas cuidado, ela não produz BOM) - usar cmd /u faz com que a saída para comandos internos seja unicode.

Eu realmente não posso dizer por que o suporte a cmd unicode é tão limitado (ou como diria - quebrado ...) - provavelmente problemas históricos / de compatibilidade.

Por último, se você precisar de um melhor suporte a unicode (entre muitos outros benefícios), eu recomendaria migrar para powershell

    
por 16.09.2014 / 15:14
2

O comando more não parece fazer bem a conversão. Observe o CR duplo (\ r) no arquivo de saída x2.txt.

C:>wmic diskdrive where "model = 'HGST HTS725050A7E630 ATA Device'" get index >x1.txt
C:>wmic diskdrive where "model = 'HGST HTS725050A7E630 ATA Device'" get index | more >x2.txt
C:>odd x1.txt
000000    ff    fe    49    00    6e    00    64    00    65    00    78    00    20    00    20    00
       377 376   I  
Get-WmiObject Win32_diskdrive |
    Where-Object { $_.Model -like '*WD*' } |
    Select-Object -Property Model |
    Out-File -PSPath t1.txt

Get-WmiObject Win32_diskdrive |
    Where-Object { $_.Model -like '*WD*' } |
    Select-Object -Property Model |
    Out-File -PSPath t2.txt -Encoding default
n
Get-CimInstance CIM_DiskDrive |
    Where-Object { $_.Model -like '*WD*' } |
    Select-Object -Property Model |
    Out-File -PSPath t1.txt

Get-CimInstance CIM_DiskDrive |
    Where-Object { $_.Model -like '*WD*' } |
    Select-Object -Property Model |
    Out-File -PSPath t2.txt -Encoding default
d
C:>wmic diskdrive where "model = 'HGST HTS725050A7E630 ATA Device'" get index >x1.txt
C:>wmic diskdrive where "model = 'HGST HTS725050A7E630 ATA Device'" get index | more >x2.txt
C:>odd x1.txt
000000    ff    fe    49    00    6e    00    64    00    65    00    78    00    20    00    20    00
       377 376   I  
Get-WmiObject Win32_diskdrive |
    Where-Object { $_.Model -like '*WD*' } |
    Select-Object -Property Model |
    Out-File -PSPath t1.txt

Get-WmiObject Win32_diskdrive |
    Where-Object { $_.Model -like '*WD*' } |
    Select-Object -Property Model |
    Out-File -PSPath t2.txt -Encoding default
n
Get-CimInstance CIM_DiskDrive |
    Where-Object { $_.Model -like '*WD*' } |
    Select-Object -Property Model |
    Out-File -PSPath t1.txt

Get-CimInstance CIM_DiskDrive |
    Where-Object { $_.Model -like '*WD*' } |
    Select-Object -Property Model |
    Out-File -PSPath t2.txt -Encoding default
d %pre% e %pre% x %pre% %pre% %pre% 000010 0d 00 0a 00 30 00 20 00 20 00 20 00 20 00 20 00 \r %pre% \n %pre% 0 %pre% %pre% %pre% %pre% %pre% %pre% 000020 20 00 0d 00 0a 00 %pre% \r %pre% \n %pre% 000026 C:>odd x2.txt 000000 49 6e 64 65 78 20 20 0d 0d 0a 30 20 20 20 20 20 I n d e x \r \r \n 0 000010 20 0d 0d 0a 0d 0d 0a 0d 0a \r \r \n \r \r \n \r \n
e %pre% x %pre% %pre% %pre% 000010 0d 00 0a 00 30 00 20 00 20 00 20 00 20 00 20 00 \r %pre% \n %pre% 0 %pre% %pre% %pre% %pre% %pre% %pre% 000020 20 00 0d 00 0a 00 %pre% \r %pre% \n %pre% 000026 C:>odd x2.txt 000000 49 6e 64 65 78 20 20 0d 0d 0a 30 20 20 20 20 20 I n d e x \r \r \n 0 000010 20 0d 0d 0a 0d 0d 0a 0d 0a \r \r \n \r \r \n \r \n

Atualizar Parece que o PowerShell pode lidar com isso melhor.

%pre%

Está claro que a CIM é a direção que o PowerShell está seguindo no futuro. Melhor começar a usá-lo agora.

%pre%     
por 11.05.2015 / 16:51
0

Se precisarmos apenas que o WMIC adicione seus dados a um arquivo de log, tente o seguinte:

Test.bat

set Log=%~dpn0.log&::
set L=^>^>"%Log%" 2^>^&1 echo&::

%L% ^
wmic /APPEND:"%Log%" /locale:ms_409 service get name,startname,state,status&::
wmic /APPEND:"%Log%" /locale:ms_409 service get name,startname,state,status&::

notepad "%Log%"

exit

O arquivo Test.log resultante será semelhante a:

wmic /APPEND:"D:\Test\T.log" /locale:ms_409 service get name,startname,state,status
Name                                      StartName                    State    Status  
AdobeARMservice                           LocalSystem                  Running  OK      
AJRouter                                  NT AUTHORITY\LocalService    Stopped  OK      
ALG                                       NT AUTHORITY\LocalService    Stopped  OK      
AppHostSvc                                LocalSystem                  Running  OK      
AppIDSvc                                  NT Authority\LocalService    Stopped  OK      
    
por 28.09.2018 / 13:49