Usando Windows Management Instrumentation para diagnóstico

O WCF (Windows Communication Foundation) expõe dados de inspeção de um serviço em tempo de execução por meio de um provedor WMI (Instrumentação de Gerenciamento do Windows) do WCF.

Como habilitar o WMI

O WMI é a implementação da Microsoft do padrão WBEM (Web-Based Enterprise Management). Para obter mais informações sobre o SDK do WMI, confira Instrumentação de Gerenciamento do Windows. O WBEM é um padrão do setor que orienta como os aplicativos expõem a instrumentação de gerenciamento a ferramentas de gerenciamento externas.

Um provedor WMI é um componente que expõe a instrumentação em tempo de execução por meio de uma interface compatível com WBEM. Ele consiste em um conjunto de objetos WMI que têm pares de atributo/valor. Os pares podem ser de vários tipos simples. As ferramentas de gerenciamento podem se conectar aos serviços por meio da interface em tempo de execução. O WCF expõe atributos de serviços como endereços, associações, comportamentos e ouvintes.

O provedor WMI interno pode ser ativado no arquivo de configuração do aplicativo. Isso é feito por meio do atributo wmiProviderEnabled do <diagnóstico> na seção <system.serviceModel>, conforme mostrado na configuração de exemplo a seguir.

<system.serviceModel>  
    …  
    <diagnostics wmiProviderEnabled="true" />  
    …  
</system.serviceModel>  

Essa entrada de configuração expõe uma interface WMI. Os aplicativos de gerenciamento já podem se conectar por meio dessa interface e acessar a instrumentação de gerenciamento do aplicativo.

Como acessar os dados do WMI

Os dados do WMI podem ser acessados de várias formas diferentes. A Microsoft fornece APIs do WMI para scripts, aplicativos Visual Basic, aplicativos C++ e o .NET Framework. Para obter mais informações, confira Como usar o WMI.

Cuidado

Se você usar os métodos fornecidos pelo .NET Framework para acessar os dados do WMI por meio de programação, fique ciente de que esses métodos podem gerar exceções quando a conexão for estabelecida. A conexão não é estabelecida durante a construção da instância de ManagementObject, mas na primeira solicitação envolvendo a troca de dados real. Portanto, você deve usar um bloqueio try..catch para capturar as possíveis exceções.

Você pode alterar o nível de log de rastreamento e de mensagem, bem como as opções de log de mensagens para a origem do rastreamento System.ServiceModel no WMI. Faça isso acessando a instância de AppDomainInfo, que expõe estas propriedades boolianas: LogMessagesAtServiceLevel,LogMessagesAtTransportLevel, LogMalformedMessages e TraceLevel. Portanto, se você configurar um ouvinte de rastreamento para o log de mensagens, mas definir essas opções como false na configuração, poderá alterá-las posteriormente para true quando o aplicativo estiver em execução. Isso habilitará efetivamente o log de mensagens em tempo de execução. Da mesma forma, se você habilitar o log de mensagens no arquivo de configuração, poderá desabilitá-lo em tempo de execução usando o WMI.

Você deve estar ciente de que, se nenhum ouvinte de rastreamento de log de mensagens para o log de mensagens ou nenhum ouvinte de rastreamento System.ServiceModel for especificado no arquivo de configuração, nenhuma das alterações será efetivada, mesmo que as alterações sejam aceitas pelo WMI. Para obter mais informações sobre como configurar corretamente os respectivos ouvintes, confira Como configurar o log de mensagens e Como configurar o rastreamento. O nível de rastreamento de todas as outras fontes de rastreamento especificadas pela configuração entra em vigor quando o aplicativo é iniciado e não pode ser alterado.

O WCF expõe um método GetOperationCounterInstanceName para scripts. Esse método retornará um nome de instância do contador de desempenho se você fornecer um nome de operação. No entanto, ele não valida a entrada. Portanto, se você fornecer um nome de operação incorreto, um nome de contador incorreto será retornado.

A propriedade OutgoingChannel da instância Service não contará os canais abertos por um serviço para se conectar a outro serviço se o cliente WCF ao serviço de destino não for criado dentro do método Service.

Atenção O WMI só dá suporte a um valor TimeSpan de até três pontos decimais. Por exemplo, se o serviço definir uma das propriedades como MaxValue, o valor dela será truncado após três pontos decimais quando exibido por meio do WMI.

Segurança

Como o provedor WMI do WCF permite a descoberta de serviços em um ambiente, você deve ter extrema cautela para permitir acesso a ele. Se você flexibilizar o acesso padrão somente ao administrador, poderá permitir que partes menos confiáveis acessem dados confidenciais no seu ambiente. Especificamente, se você afrouxar permissões no acesso remoto do WMI, poderão ocorrer ataques de inundação. Se um processo for inundado por um excesso de solicitações do WMI, o desempenho dele poderá ser degradado.

Além disso, se você flexibilizar as permissões de acesso para o arquivo MOF, as partes menos confiáveis poderão manipular o comportamento do WMI e alterar os objetos carregados no esquema WMI. Por exemplo, os campos podem ser removidos de modo que os dados críticos sejam ocultos do administrador ou que os campos que não preencham ou causem exceções sejam adicionados ao arquivo.

Por padrão, o provedor WMI do WCF concede as permissões "executar método", "gravação do provedor" e "habilitar conta" ao Administrador e a permissão "habilitar conta" para o ASP.NET, o Serviço Local e o Serviço de Rede. Em particular, em plataformas não Windows Vista, a conta do ASP.NET tem acesso de leitura ao namespace ServiceModel do WMI. Caso não deseje conceder esses privilégios a determinado grupo de usuários, desative o provedor WMI (ele está desabilitado por padrão) ou desabilite o acesso para o grupo de usuários específico.

Além disso, quando você tenta habilitar o WMI por meio da configuração, o WMI pode não ser habilitado devido a privilégios insuficientes do usuário. No entanto, nenhum evento é gravado no log de eventos para registrar essa falha.

Para modificar os níveis de privilégio do usuário, use as etapas a seguir.

  1. Clique em Iniciar e em Executar e digite compmgmt.msc.

  2. Clique com o botão direito do mouse em Serviços e Aplicativo/Controles do WMI para selecionar Propriedades.

  3. Selecione a Guia Segurança e navegue até o namespace Root/ServiceModel. Clique no botão Segurança.

  4. Selecione o grupo ou usuário específico do qual deseja controlar o acesso e use a caixa de seleção Permitir ou Negar para configurar as permissões.

Como conceder permissões de registro do WMI do WCF a usuários adicionais

O WCF expõe dados de gerenciamento ao WMI. Ele faz isso hospedando um provedor WMI em processo, às vezes chamado de "provedor separado". Para que os dados de gerenciamento sejam expostos, a conta que registra esse provedor precisa ter as permissões apropriadas. No Windows, apenas um pequeno conjunto de contas com privilégios pode registrar provedores separados por padrão. Esse é um problema porque os usuários geralmente querem expor dados do WMI por meio de um serviço WCF em execução em uma conta que não está no conjunto padrão.

Para fornecer esse acesso, um administrador precisa conceder as seguintes permissões à conta adicional na seguinte ordem:

  1. Permissão para acessar o namespace WMI do WCF.

  2. Permissão para registrar o provedor WMI separado do WCF.

Para conceder a permissão de acesso ao namespace WMI

  1. Execute o script do PowerShell a seguir.

    write-host ""  
    write-host "Granting Access to root/servicemodel WMI namespace to built in users group"  
    write-host ""  
    
    # Create the binary representation of the permissions to grant in SDDL  
    $newPermissions = "O:BAG:BAD:P(A;CI;CCDCLCSWRPWPRCWD;;;BA)(A;CI;CC;;;NS)(A;CI;CC;;;LS)(A;CI;CC;;;BU)"  
    $converter = new-object system.management.ManagementClass Win32_SecurityDescriptorHelper  
    $binarySD = $converter.SDDLToBinarySD($newPermissions)  
    $convertedPermissions = ,$binarySD.BinarySD  
    
    # Get the object used to set the permissions  
    $security = gwmi -namespace root/servicemodel -class __SystemSecurity  
    
    # Get and output the current settings  
    $binarySD = @($null)  
    $result = $security.PsBase.InvokeMethod("GetSD",$binarySD)  
    
    $outsddl = $converter.BinarySDToSDDL($binarySD[0])  
    write-host "Previous ACL: "$outsddl.SDDL  
    
    # Change the Access Control List (ACL) using SDDL  
    $result = $security.PsBase.InvokeMethod("SetSD",$convertedPermissions)
    
    # Get and output the current settings  
    $binarySD = @($null)  
    $result = $security.PsBase.InvokeMethod("GetSD",$binarySD)  
    
    $outsddl = $converter.BinarySDToSDDL($binarySD[0])  
    write-host "New ACL:      "$outsddl.SDDL  
    write-host ""  
    

    Este script do PowerShell usa a SDDL (Security Descriptor Definition Language) para permitir ao grupo Usuários Internos o acesso ao namespace WMI "root/servicemodel". Ele especifica as seguintes ACLs:

    • BA (conta de administrador interno) – Já tinha o acesso.

    • NS (Serviço de Rede) – já tinha o acesso.

    • LS (Sistema Local) – já tinha o acesso.

    • Usuários Internos – O grupo ao qual o acesso será permitido.

Para permitir acesso ao registro do provedor

  1. Execute o script do PowerShell a seguir.

    write-host ""  
    write-host "Granting WCF provider registration access to built in users group"  
    write-host ""  
    # Set security on ServiceModel provider  
    $provider = get-WmiObject -namespace "root\servicemodel" __Win32Provider  
    
    write-host "Previous ACL: "$provider.SecurityDescriptor  
    $result = $provider.SecurityDescriptor = "O:BUG:BUD:(A;;0x1;;;BA)(A;;0x1;;;NS)(A;;0x1;;;LS)(A;;0x1;;;BU)"  
    
    # Commit the changes and display it to the console  
    $result = $provider.Put()  
    write-host "New ACL:      "$provider.SecurityDescriptor  
    write-host ""  
    

Como permitir acesso a usuários ou grupos arbitrários

O exemplo desta seção concede privilégios de registro do provedor WMI a todos os usuários locais. Caso deseje permitir acesso a um usuário ou um grupo que não é interno, obtenha o SID (identificador de segurança) desse usuário ou grupo. Não há uma forma simples de obter o SID de um usuário arbitrário. Um método é fazer logon como o usuário desejado e emitir o comando do shell a seguir.

Whoami /user  

Para obter mais informações, confira SIDs conhecidos.

Como acessar instâncias remotas de objeto do WMI

Caso precise acessar instâncias do WMI do WCF em um computador remoto, habilite a privacidade de pacote nas ferramentas que você usa para o acesso. A seção a seguir descreve como obtê-las usando o WMI CIM Studio, o Testador da Instrumentação de Gerenciamento do Windows e o SDK 2.0 do .NET.

WMI CIM Studio

Se você instalou as Ferramentas Administrativas do WMI, use o WMI CIM Studio para acessar as instâncias do WMI. As ferramentas estão localizadas na seguinte pasta:

%windir%\Program Files\WMI Tools\

  1. Na janela Conectar ao namespace, digite root\ServiceModel e clique em OK.

  2. Na janela Logon do WMI CIM Studio, clique no botão Opções >> para expandir a janela. Selecione Privacidade de pacote em Nível de autenticação e clique em OK.

Testador da Instrumentação de Gerenciamento do Windows

Essa ferramenta é instalada pelo Windows. Para executá-la, inicie um console de comando digitando cmd.exe na caixa de diálogo Iniciar/Executar e clique em OK. Em seguida, digite wbemtest.exe na janela de comando. Em seguida, a ferramenta Testador da Instrumentação de Gerenciamento do Windows será iniciada.

  1. Clique no botão Conectar no canto superior direito da janela.

  2. Na nova janela, insira root\ServiceModel no campo Namespace e selecione Privacidade de pacote em Nível de autenticação. Clique em Conectar.

Como usar um código gerenciado

Acesse também as instâncias remotas do WMI por meio de programação usando classes fornecidas pelo namespace System.Management. O exemplo de código a seguir demonstra como fazer isso.

String wcfNamespace = $@"\\{this.serviceMachineName}\Root\ServiceModel");
  
ConnectionOptions connection = new ConnectionOptions();  
connection.Authentication = AuthenticationLevel.PacketPrivacy;  
ManagementScope scope = new ManagementScope(this.wcfNamespace, connection);