Simple Version
$windowsExporterUrl='https://github.com/prometheus-community/windows_exporter/releases/download/v0.20.0/windows_exporter-0.20.0-amd64.msi'
$stageFolder='C:\Temp\'
# Download the file
Import-Module BitsTransfer
$fileName=[regex]::match($windowsExporterUrl,'[^/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))')
$msiFile=join-path $stageFolder $fileName
if(!(test-path $stageFolder)){mkdir $stageFolder}
Start-BitsTransfer -Source $windowsExporterUrl -Destination $msiFile
# Install using MSIEXEC
msiexec /i $msiFile ENABLED_COLLECTORS=os,cpu,cs,logical_disk,net,tcp,service,textfile /quiet
# Check whether product is installed
$serviceName='windows_exporter'
function checkUninstall($serviceName){
$cpuArchitecture32bitPointerSize=4
$path=if ([IntPtr]::Size -eq $cpuArchitecture32bitPointerSize) {
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}else{
@('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*')
}
Get-ItemProperty $path |.{process{ if ($_.DisplayName -eq $serviceName -and $_.UninstallString) { $_ } }} |
Select-Object DisplayName, Publisher, InstallDate, DisplayVersion, UninstallString
}
do{
sleep 5
$installed=checkUninstall $serviceName
}until($null -ne $installed)
# Set auto start and restart upon failures
$serviceName='windows_exporter'
& sc.exe failure $serviceName reset= 30 actions= restart/100000/restart/100000/""/300000
Set-Service -Name $serviceName -StartupType 'Automatic'
Installing Prometheus Windows Exporter Client on a List of Windows Servers
# installWindowsExporter.ps1
# version: 0.0.2
# Limitations: this script assumes that the Windows machine has outbound access to github (firewall allowed)
# Current iteration is sequential - next iteration is to run installs in parallel
# User input-variables
$computerNames=@(
'SERVER001',
'SERVER002'
)
$parentUrl='https://github.com/prometheus-community/windows_exporter/releases'
$fileExtension='.msi'
$maxDepth=1
$serviceName='windows_exporter'
$resets=30
$restartWaitMs=100000
$maxWaitSeconds=120
function installWindowsExporter{
param(
$computernames=$env:computername,
$parentUrl='https://github.com/prometheus-community/windows_exporter/releases',
$fileExtension='.msi',
$maxDepth=1,
$serviceName='windows_exporter',
$resets=30,
$restartWaitMs=100000,
$searchTimeout=30,
$maxWaitSeconds=120
)
function installWindowsExporterUsingChoco{
param(
$parentUrl='https://github.com/prometheus-community/windows_exporter/releases',
$fileExtension='.msi',
$maxDepth=1,
$serviceName='windows_exporter',
$resets=30,
$restartWaitMs=100000,
$searchTimeout=30
)
# Check whether product is installed before proceeding
function checkUninstall($serviceName){
$cpuArchitecture32bitPointerSize=4
$path=if ([IntPtr]::Size -eq $cpuArchitecture32bitPointerSize) {
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}else{
@('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*')
}
Get-ItemProperty $path |.{process{ if ($_.DisplayName -eq $serviceName -and $_.UninstallString) { $_ } }} |
Select-Object DisplayName, Publisher, InstallDate, DisplayVersion, UninstallString
}
$installed=checkUninstall $serviceName
if(!$installed){
try{
# Install Chocolatey
if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy Bypass -Scope Process -Force;
$null=iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))}
$null=choco install prometheus-windows-exporter.install -y --ignore-checksums
}catch{
write-warning $_
return $false
}
}else{
write-host "$env:computername already has $servicename installed"
}
try{
# Set auto start and restart upon failures
$null=& sc.exe failure $serviceName reset= $resets actions= restart/$restartWaitMs/restart/$restartWaitMs/""/$($restartWaitMs*3)
Set-Service -Name $serviceName -StartupType 'Automatic'
write-host "$env:computername now has $servicename set to automatically run and reset at $resets and restart wait-time of $restartWaitMs ms."
return $(get-service $serviceName).Status -eq 'Running'
}catch{
write-warning $_
return $false
}
}
$results=@()
$computernames|%{
$job=invoke-command -computername $_ -scriptblock{
param($installWindowsExporterUsingChoco,$parentUrl,$fileExtension,$maxDepth,$serviceName,$resets,$restartWaitMs)
[ScriptBlock]::Create($installWindowsExporterUsingChoco).invoke($parentUrl,$fileExtension,$maxDepth,$serviceName,$resets,$restartWaitMs)
} -ArgumentList ${function:installWindowsExporterUsingChoco},$parentUrl,$fileExtension,$maxDepth,$serviceName,$resets,$restartWaitMs -AsJob -JobName installPrometheusExporter
$count=0
while (($job.State -like "Running") -and ($count -lt $maxWaitSeconds)){
Start-Sleep -Seconds 1
$count++
}
if ($Job.State -like "Running") { $job | Stop-Job }
$success=$job | Receive-Job
$job|Remove-Job
$result=if($success){
[pscustomobject]@{$_=$success}
}else{
[pscustomobject]@{$_=$false}
}
$results+=$result
}
return $results
}
$status=installWindowsExporter $computerNames $parentUrl $fileExtension $maxDepth $serviceName $resets $restartWaitMs $maxWaitSeconds
write-host $status
Previous Version: Install Using Github
# installWindowsExporter.ps1
# version: 0.0.1
# Limitations: this script assumes that the Windows machine has outbound access to github (firewall allowed)
# User input-variables
$parentUrl='https://github.com/prometheus-community/windows_exporter/releases'
$fileExtension='.msi'
$maxDepth=1
function findDownloadUrl{
param(
$startUrl,
$fileExtension,
$maxDepth=3
)
$simultaneousJobs=8
$linksChecked=0
$firstResult=$false
$timer=[System.Diagnostics.Stopwatch]::StartNew()
if(!$startUrl){
write-warning "Cannot start with a blank parent URL"
}elseif($startUrl -notmatch '/$'){
$startUrl=$startUrl+'/'
}
function findFile($parentUrl,$extension){
$ProgressPreference='SilentlyContinue'
$ErrorActionPreference='stop'
if($parentUrl -notmatch '/$'){$parentUrl=$parentUrl+'/'}
try{
$page=Invoke-WebRequest $parentUrl -TimeoutSec 10
}catch{
return @{'result'=$false;'links'=@()}
}
$newLinks=$page.links.href|?{$_ -notlike "*$(Split-Path $parentUrl -parent)"}| `
sort -Descending|%{$(
if($_[0] -eq '/'){
$parentUrl+$_.Substring(1,$_.length-1)
}elseif($_ -match '^http'){
$_
}else{
$parentUrl+$_
}
)}|select -Unique
$matchedExtension=$newLinks|?{$_ -like "*$extension"}|sort -Descending|select -First 1
if($matchedExtension){
return @{'result'=$true;'links'=$matchedExtension}
}elseif($newLinks){
return @{'result'=$false;'links'=$newLinks}
}else{
return @{'result'=$false;'links'=@()}
}
}
write-host "Scanning $startUrl for file extension $fileExtension"
$startLinks=.{$result=findFile $startUrl $fileExtension
return $result['links']
}
if($startLinks -eq $null){
write-warning "There were problems parsing links"
return $null
}elseif($startLinks.gettype() -eq [string]){
return $startLinks
}
$knownLinks=$startLinks
foreach ($link in $startLinks){
$currentDepth=1
write-host "Processing link at current depth: $currentDepth"
$newLinks=@($link)
do{
if($i++ -lt $simultaneousJobs -and !(!$newLinks)){
$thisLink=$newLinks|Select -Unique|select -First 1
if($newLinks.count -gt 1){
$newLinks=$newLinks[1..($newLinks.count-1)]
}else{
$newLinks=@()
}
write-host "Parsing $thisLink"
$job=start-job -ScriptBlock{
param($findFile,$thisLink,$fileExtension)
return [ScriptBlock]::Create($findFile).invoke($thisLink,$fileExtension)
} -Args ${function:findFile},$thisLink,$fileExtension
$linksChecked++
}else{
do{
$results=Get-Job|Receive-Job -wait
get-job -State 'Completed'|remove-job
$results|%{
$currentDepth++
if($_['result']){
write-host "Bingo!" -ForegroundColor Green
get-job|remove-job
$firstResult=$_['links']
}elseif($currentDepth -le $maxDepth){
$addLinks=$_['links']|?{$_ -notin $knownLinks}
if($addLinks){
write-host "Adding new links to depth $currentDepth`:`r`n$(($addLinks|out-string).trim())"
$knownLinks+=$addLinks
$newLinks=$addLinks+$newLinks
}
}
}
$i=(get-job -state 'Running').count
}until($i -lt $simultaneousJobs -or $firstResult)
}
}until((!$newLinks -and !$i) -or $firstResult)
if($firstResult){
$totalMinutes=[math]::round($timer.Elapsed.TotalMinutes,2)
write-host "Minutes elapsed: $totalMinutes"
return $firstResult
}
}
$totalMinutes=[math]::round($timer.Elapsed.TotalMinutes,2)
write-host "$linksChecked links have been checked in $totalMinutes minutes without finding file extension $fileExtension" -ForegroundColor Red
return $false
}
$windowsExporterUrl=findDownloadUrl $parentUrl $fileExtension $maxDepth
# $fileName=[regex]::match($windowsExporterUrl,'(?:.(?!\/))+$') # this negative lookahead includes the '/' slashes
$fileName=[regex]::match($windowsExporterUrl,'[^/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))')
# $windowsExporterUrl='https://github.com/prometheus-community/windows_exporter/releases/download/v0.20.0/windows_exporter-0.20.0-amd64.msi'
# $fileName='windows_exporter-0.20.0-amd64.msi'
$stageFolder='C:\Temp\'
$msiFile=join-path $stageFolder $fileName
# Faster way of installing if there are no firewall problems
# choco install prometheus-windows-exporter.install
# Download the file
Import-Module BitsTransfer
if(!(test-path $stageFolder)){mkdir $stageFolder}
Start-BitsTransfer -Source $windowsExporterUrl -Destination $msiFile
# Install using MSIEXEC
msiexec /i $msiFile ENABLED_COLLECTORS=os,cpu,cs,logical_disk,net,tcp,hyperv,service,textfile /quiet
# Check whether product is installed
$serviceName='windows_exporter'
function checkUninstall($serviceName){
$cpuArchitecture32bitPointerSize=4
$path=if ([IntPtr]::Size -eq $cpuArchitecture32bitPointerSize) {
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
}else{
@('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*')
}
Get-ItemProperty $path |.{process{ if ($_.DisplayName -eq $serviceName -and $_.UninstallString) { $_ } }} |
Select-Object DisplayName, Publisher, InstallDate, DisplayVersion, UninstallString
}
checkUninstall $serviceName
# Set auto start and restart upon failures
$serviceName='windows_exporter'
& sc.exe failure $serviceName reset= 30 actions= restart/100000/restart/100000/""/300000
Set-Service -Name $serviceName -StartupType 'Automatic'
Categories:
Simone
Thanks for the scripts posted.
Currently im using the second script, please can you update it and add to check if the windows_exporter is installed and isn’t the latest version it will uninstall it and install the latest release?
kimconnect
Hi Simone,
I’m currently not using Windows. So, it’s inconvenient for me to find a machine to write & validate PowerShell codes. For what it’s worth, here’s some pseudo code to be inserted into the ELSE portion of the original snippet:
}else{
try{
# Install Chocolatey
if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy Bypass -Scope Process -Force;
$null=iex ((New-Object System.Net.WebClient).DownloadString(‘https://chocolatey.org/install.ps1’))}
# write the cmdlet to gather the available version here
# $availableVersion=(choco list -l|?{$_.Name -eq $serviceName}).Version # I’m currently not using Windows, so I cannot recall the exact lines to gather this info
}catch{
write-warning $_
return $false
}
if([version]$installed.DisplayVersion -lt [version]$availableVersion){
# write the uninstall function here
$null=choco install prometheus-windows-exporter.install -y –ignore-checksums
}else{
write-host “$env:computername already has $servicename installed”
}
}