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'