Google App Script, Powershell e inventário de equipamentos

Pedro Robson Leão
8 min readMay 23, 2020

--

Este artigo explora possibilidades de projetos usando soluções GSuite, que se tornaram ainda mais forte durante o período de pandemia do COVID-19, e sua integração com outras tecnologias.

O GSuite possui poderosas funcionalidades, além do ambiente para gestão e edição de documentos, e-mail, planilhas, apresentações, formulários, arquivos.

A criação de macros torna o ambiente ainda mais poderoso.

Macros, Simples como o bom e velho VBA, utilizado para macros no Excel. Não explorei a fundo o Office 365 para falar sobre como estão hoje estes recursos.

Desafio

Criar um sistema para gestão de inventário de hardware e software de máquinas windows utilizando as ferramentas:

  1. Google Spreadsheet
  2. Powershell

Projeto

O projeto visa a criação de uma planilha no google drive onde serão registrados todos os dados das máquinas windows a serem inventariadas.

Como interface de acesso à planilha será criado um weebhook usando Google App Script para escrever nas linhas e colunas da planilha.

O cliente será um script PowerShell porque irá coletar as informações da máquina cliente e fazer o post das informações que serão publicadas na planilha.

A Planilha/Google App Script - (server side)

Create a new empty spreadsheet

Vamos começar nosso projeto criando uma planilha simples no Google Spreadsheet.

Google Spreadsheet

Nomeie a planilha com um nome a sua escolha.

Script editor

Ferramentas > Editor de script

Abra a tela do editor de scripts:

Script Editor

Copie o código abaixo:

Trata-se do nosso código escrito em Google App Script.

let configuration = {
has: function () {
if (this.sheet == null) {
this.sheet = SpreadsheetApp.getActive().getSheetByName('settings');
this.tokenlist = {};
this.sheet.getRange("A:B").getValues()
.filter(obj => { return (obj[0] != "" && obj[0] != "User") })
.forEach(obj => {
this.tokenlist[obj[1]] = obj[0];
});
}
return (this.sheet != null);
},
get: function (token) {
return this.tokenlist[token.trim()];
}
};
let Data = {
setUser: function(user) {
this.user = user;
},
setServiceTag: function(serviceTag) {
this.serviceTag = serviceTag;
},
setHeader: function(header) {
this.header = header;
},
set: function(data) {
this.data = data;
},
get: function() {
let values = [];

this.data._user = this.user;
this.data._date = new Date();

if(this.serviceTag) {
this.data.service_tag = this.serviceTag;
}

this.header.forEach((key,idx) => {
if (this.data[key]) {
values[idx] = this.data[key];
}
});
return values;
}
};
//this is a function that fires when the webapp receives a GET request
function doGet(e) {
return HtmlService.createHtmlOutput("request received");
}
//this is a function that fires when the webapp receives a POST request
function doPost(e) {
if(e.postData && e.postData.contents) {
let params = JSON.stringify(e.postData.contents);
params = JSON.parse(params);
let data = JSON.parse(e.postData.contents);
let responseMsg = "discarded post";

if (configuration.has()) {
let user = configuration.get(data.token);
if (user) {
var sheet = SpreadsheetApp.getActive().getSheetByName(data.sheet_name);
if (sheet) {
let header = sheet.getRange("A1:ZZ1").getValues();

Data.setUser(user);
Data.setHeader(header[0]);
Data.setServiceTag(data.service_tag);

if (Array.isArray(data.data)) {
data.data.forEach(_data => {
Data.set(_data);
sheet.appendRow(Data.get());
});
} else {
Data.set(data.data);
sheet.appendRow(Data.get());
}
responseMsg = "post accepted";
SpreadsheetApp.flush();
}
}
}
return HtmlService.createHtmlOutput(responseMsg);
}
}
function uuid() {
return Utilities.getUuid();
}

Selecione o código que aparece no editor:

cole o novo código:

salve e nomeie seu projeto:

publique seu script como aplicativo da web:

Deploy as web app

click em [Deploy]

clicar [Analisar permissões]

copie a url apresentada, este é o endpoint do seu webhook:

https://script.google.com/macros/s/<id>/exec

Após copiar a url click em [OK].

concluimos aqui o lado server side.

PowerShell — (client side)

Ultimamente, a necessidade em automatizar pequenos processos em ambiente MS Windows me levou de volta ao bom e velho .bat Dos. Como usuário de bash com nível avançado imaginem a irritação devido a forma que algumas coisas são feitas.

Fui encorajado então pelo Ricardo a dar uma olhada em scripts powershell, cara feia, torcida no nariz e voilà!

Comecei a gostar da coisa!

Umas pesquisas na net me levaram à um script que pegava as informações que eu precisava.
Get Server Inventory: CPU, Memory, and OS information. Export to CSV.

Achei o código um pouco bagunçado à primeira vista da linguagem, mas bastante promissor. Então erá só estudar e adaptar para o que eu queria.

O resultado foi o script a seguir, que pode ser executado via powershell em nossas máquinas windows a fim de coletar as informações e enviar à nosso webhook para alimentar a planilha.

<#
.SYNOPSIS
Get Windows Host information
.DESCRIPTION
This script will get the CPU specifications, memory usage statistics, and OS configuration of any Server or Computer listed in $servers variable and post data to $webhook url.
.NOTES
The script will execute the commands on multiple machines sequentially using non-concurrent sessions. This will process all servers from $servers variable listed order.
The info will be exported to a csv format.
Requires:
File Name : MyInventory.ps1
Author: Pedro Robson Leao <pedro.leao@gmail.com>
http://github.com/pedrorobsonleao
References:
https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Script-Get-beced710
https://github.com/ian8667/powershell/blob/master/Get-ServerInfo.ps1
#>

# server or server list to execute this script
$servers = @("localhost")

# webhook endpoint and access token to write in this sheet
$webhook = "https://script.google.com/macros/s/<id>/exec"
$token = "xxxxxxxxxxxx-xxxxxxxxxx-xxxxxxxxx-xxxxx"

# config class to get information and sheet to write this information
$configs = '[
{ "class": "Win32_SystemEnclosure", "sheet": "manufacture" },
{ "class": "Win32_Processor", "sheet": "cpu" },
{ "class": "Win32_OperatingSystem", "sheet": "operacional_system" },
{ "class": "CIM_PhysicalMemory", "sheet": "memory" },
{ "class": "Win32_UserAccount", "sheet": "users" },
{ "class": "Win32_Product", "sheet": "softwares" },
{ "class": "Win32_Volume", "sheet": "volumes"},
{ "class": "Service", "sheet": "services" }
]' | ConvertFrom-Json

# start data object to post with the token
$data = @{
"token" = $token
}

# server list iterator
ForEach ($server in $servers) {
# config lines iterator
ForEach ($config in $configs) {
# set sheet name to write
$data.sheet_name = $config.sheet

Try {
if ($config.class -eq "Service") {
# to Service need consult Get-Service information
$data.data = Get-Service -ComputerName $server -ErrorAction Stop
} else {
# to another information use Get-WmiObject with the class
$data.data = Get-WmiObject -ComputerName $server -Class $config.class -ErrorAction Stop
}

if($config.sheet -eq "manufacture") {
# the service tag only is read in manufacture session. I save this information to use in another posts data
$data.service_tag = $data.data.SerialNumber
}

# convert data powershell to json to post
$dt = $data | ConvertTo-Json

# post data to endpoint
$response = Invoke-WebRequest -UseBasicParsing -Uri $webhook -Method Post -ContentType "application/json;charset=UTF-8" -Body $dt
# show status, description and posted data
Write-Host $config.sheet $response.StatusCode $response.StatusDescription
$dt
} Catch {
# when error - show error information
Write-Host $config.sheet $_.Exception
}
}
}

Integrando server e client

Agora que toda a codificação necessária foi feita, vamos comecar a integrar as coisas.

O primeiro passo necessário é criar na planilha a página settings.

Inclua na página settings as colunas User e Token.

Você pode usar a função uuid() na planilha para gerar um novo token, porém lembre-se de copiar o resultado da função e usar a opção colar especial para salvar o número na coluna. Usar a função direto na coluna token irá fazer a planilha mudar o token sempre que for aberta.

Edite o script MyInventory.ps1 e inclua o endpoint e o token no trecho de código que segue:

# webhook endpoint and access token to write in this sheet
$webhook = "https://script.google.com/macros/s/<id>/exec"
$token = "xxxxxxxxxxxx-xxxxxxxxxx-xxxxxxxxx-xxxxx"

Após editar o arquivo com as informações, abra um terminal powershell e execute o script:

PS C:\Users\User\Desktop> .\MyInventory2.ps1 >.\object.json
manufacture 200 OK
cpu 200 OK
operacional_system 200 OK
memory 200 OK
users 200 OK
softwares 200 OK
volumes 200 OK
services 200 OK

O arquivo object.json gerado terá todos os objetos coletados no host e postados à planilha. Você pode usar este arquivo para identificar informações que poderão ser incluidas em sua planilha de informações.

Basta criar o nome do campo na primeira linha da planilha.

Os campos _user e _date são incluidos automáticamente pelo servidor ao objeto. O campo serialNumber do objeto manufacture é copiado a todos os outros objetos como service_tag.

Para nosso exemplo vou criar as páginas informadas na execução do script:

  • manufacture
  • cpu
  • operacional_system
  • memory
  • users
  • softwares
  • volumes

Após a devida configuração das páginas da planilha, aí é só executar o script em suas máquinas:

Conclusão

Existem no mercado várias ferramentas conceituadas para inventariar hardware e software. Existem opções pagas e open-source e todas de grande qualidade.

A idéia aqui é usar o problema, inventariar máquinas, como case para demonstrar e explorar todo o potencial do ambiente GSuite/Google Drive.

Referencias

--

--