Microsoft Graph e Powershell

Gostaria de fazer chamadas para a API do Microsoft Graph utilizando Powershell? Não existe SDK para ele, mas você pode facilmente fazer esta integração chamando a Rest Api diretamente, utilizando Invoke-RestMethod.

Abaixo um exemplo (listar usuários do Azure AD). São duas chamadas:

  • Fazer a autenticação e guardar o token (lembrando que sua aplicação precisa estar registrada, e com as permissões atribuidas. No caso deste exemplo, estou setando estas permissões do tipo “Aplicativo”, passando ClientId, ClientSecret e TenantId).
  • Fazer a chamada para a API desejada (https://graph.microsoft.com/v1.0/users), passando no Header da mesma o token (Bearer).
$clientId = "5e3543b8-8ccd-4c6b-ada1-ef42dc536239"
$clientSecret = "HwQfqX/8mb2=9lLvGFmFTqc4huMpMG/:"
$tenantId = "367d2083-e69a-4817-8af0-b25958285733"

$body = "grant_type=client_credentials&scope=https://graph.microsoft.com/.default&client_id=$clientId&client_secret=$clientSecret"  

$authUrl = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"


Write-Output "Autenticando em $authUrl"

$token = Invoke-RestMethod -Method Post -Uri $authUrl -ContentType "application/x-www-form-urlencoded" -body $body

Write-Host "Token: " $token.access_token

$usersUrl = "https://graph.microsoft.com/v1.0/users"
$header = @{
    Authorization = "Bearer " + $token.access_token 
}


$users = Invoke-RestMethod -Method Get -Uri $usersUrl -Headers $header -ContentType "application/json"

foreach ($user in $users.value)
{
    Write-Host $user.displayName "<"$user.Mail">"
}

É isso. Barbada!

Obviamente os valores de ClientId, ClientSecret e TenantId são fakes 🙂

Cloud Foundry CLI: Error read/writing config

Durante o último final-de-semana fizemos o deploy de alguns artefatos para Pivotal Cloud Foundry, em uma algumas instâncias privadas de Produção na empresa. Como precisei monitorar algumas coisas (log tail princinpalmente), abri vários prompts do Windows e utilizei o CLI do Cloud Foundry em paralelo. Resultado? Após certo tempo, o CLI deixou de funcionar. Para qualquer comando, este erro:

Error read/writing config: invalid character ‘:’ after top-level value

Desinstalei e instalei o CLI algumas vezes. Não resolveu.
Solução? Simples. Só adicionar o valor abaixo nas variáveis de ambiente:

Application Insights – Monitoramento de Endpoint

Já precisou fazer o health-check do endpoint da sua aplicação ou serviço, e ser notificado caso haja problemas? Há pouco tempo atrás, a feature de monitoramento de Endpoints era própria da WebApp no Azure. Na semana passada precisei configurar, e não a encontrei no local que eu costumava. Uma pesquisada rápida e descobri que essa feature foi movida para o Application Insights, atuando de maneira independente da WebApp. Para quem não conhecia/conhece o recurso: ele permite pings (http requests) periódicos de maneira externa a aplicação, a partir de diversas regiões do mundo. Obviamente, também permite a configuração de notificações, seja por e-mail ou webhooks.

A configuração é simples:

  • Crie o recurso Application Insights, caso não tenha feito juntamente com  a criação da WebApp. Para este propósito (http request), utilizei a opção “General”:

Azure Monitoramento de Endpoints Application Insights 1

  • Assim que  estiver que o AppInsights estiver rodando, adicione um teste (“Availability” -> “Create Test”):

Azure Monitoramento de Endpoints Application Insights 2

  • Escolha um nome e adicione a URL a ser monitorada (no meu caso, a URL root da aplicação). Deixei como freqüencia de teste, 5 minutos. Escolhi localidades aleatórias (obviamente isso depende das suas necessidades de negócio): Brasil, Sydney, Moscou e San Jose:

Azure Monitoramento de Endpoints Application Insights 3

  • Critério de sucesso: utilizei o padrão (retorno de um http 200), mas poderia inclusive validar o conteúdo de retorno desta chamada.

Azure Monitoramento de Endpoints Application Insights 4

  • Alertas: diminuí o treshold (se falhar em mais de 2 localidades, dispara a trigger). Por padrão, será enviado um e-mail para o administrador da subscription. Se eu quisesse algo mais personalizado, poderia configurar um webhook (e receber uma ligação de voz com detalhes do alerta, conforme explico neste post):

Azure Monitoramento de Endpoints Application Insights 5

  • Criado o teste, é só deixar rodando:

Azure Monitoramento de Endpoints Application Insights 6

  • Para fins de validação, parei e aplicação e aguardei os erros refletirem no dashboard:

Azure Monitoramento de Endpoints Application Insights 7

Extremamente fácil e útil!

Até a próxima!

[ ]´s

 

IIS AppPool: troca das credenciais

Essa semana passei trabalho com uma conta de serviço (do domínio) que estava sendo bloqueda por tentativas inválidas de login. Esta mesma conta é utilizada na Application Pool de uma aplicação no IIS, para fins de autenticação integrada no acesso a banco e aplicações externas. Em paralelo as investigações para descobrir a origem do lockout, precisei alterar as credenciais utilizadas na Application Pool, pois a conta bloqueada estava causando um HTTP 503, consequentemente derrubando a aplicação. Solução? Powershell. Sempre ele.

# Conta de serviço antiga e nova (com senha)
$oldAppPoolUser     = "CONTOSO.COM\ServiceMyApp"
$newAppPoolUser     = "CONTOSO.COM\ServiceMyAppNew"
$newAppPoolPassword = "mypassword"

Import-Module "WebAdministration"

# Percorre todas Application Pools do IIS
foreach ($appPool in (Get-ChildItem –Path IIS:\AppPools)){
    
    # Verifica as credenciais da Application Pool corrente
    $currentUser = Get-Item (Join-Path 'IIS:\AppPools' $appPool.name) | select -ExpandProperty processModel  | select userName

    # Se a Application Pool utilizar o usuario 'antigo', faz a substituição e restarta a mesma
    if ($currentUser.userName -eq $oldAppPoolUser)
    {
           
     Set-ItemProperty (Join-Path 'IIS:\AppPools' $appPool.name) -Name ProcessModel -Value @{userName=$newAppPoolUser;password=$newAppPoolPassword;identitytype=3}

     Restart-WebAppPool $appPool.name

    }
}

 

Indo além: Azure Resource Groups

Eu sou um grande fã do Azure Resource Manager, devido a versatilidade neste tipo de situação. Simplesmente listo todas VM´s pertencentes ao Resource Group (um agrupamento lógico) e aplico o script para cada umas delas. Assumindo que o nome do meu Resource Group seja AppPoolValidationRG:

    • Opção1: Conectando pelo nome da VM (estando conectado via VPN ao Azure):
Login-AzureRmAccount

$vmList = Get-AzureRMVM -ResourceGroup AppPoolValidationRG

foreach ($vm in $vmList){
    # TODO1: Conectar em Cada VM
    # TODO2: Veriricar se há IIS instalado/rodando
    # TODO3: Chamar FUNCTION que faz a troca do user da AppPool
    # Invoke-Command -ComputerName $ip.PrivateIpAddress -ScriptBlock {...}
}

 

  • Opção 2: Conectando pelo IP privado (estando conectado via VPN ao Azure):
Login-AzureRmAccount

$vmList = Get-AzureRMVM -ResourceGroup AppPoolValidationRG

foreach ($vm in $vmList){
    
    $nics = Get-AzureRmNetworkInterface | where {$_.VirtualMachine.Id -eq $vm.Id}

    foreach ($nic in $nics){
        
        $ip = Get-AzureRmNetworkInterfaceIpConfig -NetworkInterface $nic

        Write-Host $vm.name $ip.PrivateIpAddress

        # TODO1: Conectar em Cada VM
        # TODO2: Veriricar se há IIS instalado/rodando
        # TODO3: Chamar FUNCTION que faz a troca do user da AppPool
        # Invoke-Command -ComputerName $ip.PrivateIpAddress

    }
}

 

  • Opção 3: Conectando pelo IP público (caso exista para todas VM´s):
Login-AzureRmAccount

$publicIPs = Get-AzureRmVM -ResourceGroupName ‘AppPoolValidationRG’ | Get-AzureRmPublicIpAddress

foreach ($publicIP in $publicIPs){
    # TODO1: Conectar em Cada VM
    # TODO2: Veriricar se há IIS instalado/rodando
    # TODO3: Chamar FUNCTION que faz a troca do user da AppPool
    # Invoke-Command -ComputerName $publicIP -ScriptBlock {...}
}

[ ]´s

Azure Resource Manager – SKU da imagem

Há alguns dias atrás, testando deployment de recursos (VM) com o modelo ARM (Azure Resource Manager), precisei utilizar uma SKU específica. Minha necessidade era uma imagem Windows Server 2016 com SQL Server 2016. Diretamente no portal é possível apenas visualizar no nome (descrição), sem detalhes adicionais (offer/SKU).

Solução? Powershell, como sempre.

Import-Module AzureRM

# Login no Azure
Login-AzureRMAccount
# Listar Publishers Disponívies
Get-AzureRmVMImagePublisher -Location brazilsouth | Select PublisherName

Azure RM - SKU da Imagem Azure Resource Manager

 

# Listar as Offers do Publisher (Microsoft SQL Server)
Get-AzureRmVMImageOffer -Location brazilsouth -PublisherName MicrosoftSQLServer

Azure RM - SKU da Imagem Azure Resource Manager

 

# Listar as SKU´s disponíveis para a Offer SQL2016-WS2016
Get-AzureRmVMImageSku -Location brazilsouth -PublisherName MicrosoftSQLServer -Offer SQL2016-WS2016

Azure RM - SKU da Imagem Azure Resource Manager

 

# Detalhes da Imagem SQLDEV
Get-AzureRmVMImage -Location brazilsouth -PublisherName MicrosoftSQLServer -Offer SQL2016-WS2016 -Skus SQLDEV

Azure RM - SKU da Imagem Azure Resource Manager

Pronto! Agora é só utilizar a imagem desejada no seu template ARM.

[ ]´s