PSOpt2.psm1
# psversion 5 $PrintServer = 'vps.opt2' $sshKey = "$(split-path $MyInvocation.MyCommand.Source)\PSOpt2-key" # Write-color $MyInvocation.MyCommand.Path,$MyInvocation.MyCommand.Definition,$MyInvocation.MyCommand.Source,$sshKey -foreGroundColor Red,Green Class ProgressBarre { #requires -version 5 [int]$Width = $host.ui.RawUI.WindowSize.Width-6 [int]$CursorLeft = [Console]::CursorLeft [int]$CursorTop = [Console]::CursorTop [char]$block = 9632 [char]$empty = 183 [void]write([string]$Percent = '0~0~0'){ $replace = '' ([float]$green, [float]$yellow, [float]$red, $none) = $Percent.split('~') if ($green -lt 0) {$green = 0} elseif ($green -gt 100) {$green = 100} if ($yellow -lt 0) {$yellow = 0} elseif ($yellow -gt 100) {$yellow = 100} if ($red -lt 0) {$red = 0} elseif ($red -gt 100) {$red = 100} $greenLenght = [int]($green / 100 * $this.Width) $yellowLenght = [int]($yellow / 100 * $this.Width) $redLenght = [int]($red / 100 * $this.Width) $noneLenght = $this.Width - $greenLenght - $yellowLenght - $redLenght if ($noneLenght -lt 0) {$noneLenght = 0} elseif ($noneLenght -gt $this.Width) {$noneLenght = $this.Width} $total = [math]::round($green + $yellow + $red, 1) $currentCursorLeft = [Console]::CursorLeft $currentCursorTop = [Console]::CursorTop try{ [Console]::SetCursorPosition($this.CursorLeft, $this.CursorTop) } catch { Write-LogStep '!!!' error } Write-Color "$replace[", ` ''.PadLeft($greenLenght, $this.block) , ` ''.PadLeft($yellowLenght, $this.block) , ` ''.PadLeft($redLenght, $this.block) , ` ''.PadLeft($noneLenght, $this.empty) , ` '] ' ` -ForeGroundColor White, Green, Yellow, Red, gray, White ` -NoNewline $percent = "$('{0:00.0}' -f $total)" try{ [Console]::SetCursorPosition($this.Width - $percent.length - 2 , [Console]::CursorTop) } catch { Write-LogStep '!!!' error } Write-Host $percent -ForegroundColor Cyan -NoNewline try{ [Console]::SetCursorPosition([Console]::CursorLeft + 1, [Console]::CursorTop) } catch { Write-LogStep '!!!' error } Write-Host '%' -NoNewline try{ [Console]::SetCursorPosition($this.Width + 2, [Console]::CursorTop) } catch { Write-LogStep '!!!' error } try{ [Console]::SetCursorPosition($currentCursorLeft, $currentCursorTop) } catch { Write-LogStep '!!!' error } } ProgressBarre(){ $this.write(0) } } # https://app.apiary.io/coaxisasp/editor function script:is-Opt2 { <# .SYNOPSIS Test si un object et bien de type Opt2 .DESCRIPTION check la presence des proprietees .PARAMETER Opt2s Objets OPT2 de type Get-Opt2 .EXAMPLE test si cet objet est valide is-Opt2 @{test=123} .EXAMPLE test si cet objet est valide get-opt2 | is-Opt2 @{test=123} .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [Parameter(ValueFromPipeline = $true)]$Opt2s ) process { foreach ($Opt2 in $Opt2s) { [bool]($Opt2.PSobject.Properties.name -match "id") -and ` [bool]($Opt2.PSobject.Properties.name -match "hostname") -and ` [bool]($Opt2.PSobject.Properties.name -match "ip") -and ` [bool]($Opt2.PSobject.Properties.name -match "subnet") -and ` [bool]($Opt2.PSobject.Properties.name -match "gateway") -and ` [bool]($Opt2.PSobject.Properties.name -match "vlan") -and ` [bool]($Opt2.PSobject.Properties.name -match "Container_id") -and ` $Opt2.IP -match ('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$') } } } function script:is-Opt2Tunnels { <# .SYNOPSIS Test si un object et bien de type Opt2 avec Tunnels .DESCRIPTION check la presence des proprietees .PARAMETER Opt2s Objets OPT2Tunnels de type Get-Opt2Tunnels .EXAMPLE test si cet objet est valide [NON] get-opt2 | is-Opt2Tunnels .EXAMPLE test si cet objet est valide [OUI] get-opt2tunnels | is-Opt2Tunnels .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [Parameter(ValueFromPipeline = $true)]$Opt2s ) process { foreach ($Opt2 in $Opt2s) { (is-Opt2 $Opt2) -and [bool]($Opt2.PSobject.Properties.name -match "Tunnels") } } } function script:is-Tunnels { <# .SYNOPSIS Test si un object et bien de type Tunnels .DESCRIPTION check la presence des proprietees .PARAMETER Tunnels Obj .EXAMPLE test si cet objet est valide [NON] get-opt2tunnels | is-Tunnels .EXAMPLE test si cet objet est valide [OUI] (get-opt2tunnels).tunnels | is-Tunnels .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [Parameter(ValueFromPipeline = $true)] $Tunnels ) process { foreach ($Tunnel in $Tunnels) { [bool]($Tunnel.PSobject.Properties.name -match "Name") -and ` [bool]($Tunnel.PSobject.Properties.name -match "IP") -and ` [bool]($Tunnel.PSobject.Properties.name -match "Channels") -and ` [bool]($Tunnel.PSobject.Properties.name -match "Configs") -and ` $Tunnel.IP -match ('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$') } } } Function Get-Opt2 ([Parameter(ValueFromPipeline = $true)]$filter = '*', [switch]$details = $true) { <# .SYNOPSIS Recupere les Containers OPT2 .DESCRIPTION Retourne les config des container .PARAMETER Filter Filtre de type hostname ou IP ou VLAN .EXAMPLE Tous ce qui ne sont pas a jour Get-Opt2 -details | ?{$_.version -ne 'v1.10.0'} | ft hostname,vlan,name,version,cont* .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> begin { $Containers = $null if ($details -and (Test-Path $sshKey)) { try { $SSHsession = New-SSHSession $PrintServer -Force -KeyFile $sshKey -Credential (New-Object System.Management.Automation.PSCredential("coaxis", $(new-object System.Security.SecureString))) -ea stop -wa 0 -ConnectionTimeout 1 $cmd = "docker ps --no-trunc --format='{{.ID}}|{{.Names}}|{{.Image}}|{{.CreatedAt}}|{{.Status}}'" $Containers = (Invoke-SSHCommand -command $cmd -SessionId $SSHsession.SessionId -ea stop).output | %{ ($CONTAINER_ID,$NAMES,$IMAGE,$CREATED,$Uptime)=($_.split('|')) [PSCustomObject]@{ $CONTAINER_ID = [PSCustomObject]@{ Container_id = $CONTAINER_ID Name = $NAMES Image = $IMAGE Version = $IMAGE.split(':')[-1] Created = $CREATED Uptime = $Uptime # Inspect = $INSPECT } } } Write-LogStep "> SSH $PrintServer ", 'Listing des containers' ok } catch { Write-LogStep "> SSH $PrintServer ", $_ error # $SSHsession | Remove-SSHSession -ea 0 | Out-Null } } } process { if (Test-TcpPort $PrintServer -port 80 -ConfirmIfDown -Quick) { if($filter -is [string] -and $Filter -notmatch "\*" -and $filter -match '[A-Za-z]'){ if ($filter -match '\.opt(|2)$') { $filter = [System.Net.Dns]::GetHostByName("$filter").addressList.IPAddressToString } elseif([System.Net.Dns]::GetHostByName("$filter.opt2")) { $filter = [System.Net.Dns]::GetHostByName("$filter.opt2").addressList.IPAddressToString } elseif([System.Net.Dns]::GetHostByName("$filter.opt")) { $filter = [System.Net.Dns]::GetHostByName("$filter.opt").addressList.IPAddressToString } Write-LogStep '> Listing containers ', "Filtre = '$Filter'", 'par resolution DNS' wait } else { Write-LogStep '> Listing containers ', "Filtre = '$Filter'" wait } foreach ($Opt2 in ((Invoke-RestMethod "http://$PrintServer/api/daemons/?format=json").results | ? {$_.ip -like $Filter -or $_.vlan -like $Filter -or $_.hostname -like $Filter})) { Write-LogStep "> Containers [$($Opt2.hostname)] ", "Vlan $($Opt2.vlan)", $Opt2.ip ok [PSCustomObject]@{ id = $Opt2.id hostname = $Opt2.hostname ip = $Opt2.ip subnet = $Opt2.subnet gateway = $Opt2.gateway vlan = $Opt2.vlan Container_id = $Opt2.Container_id Name = $Containers.($Opt2.Container_id).Name #Image = $Containers.($Opt2.Container_id).Image Version = $Containers.($Opt2.Container_id).Version Created = $Containers.($Opt2.Container_id).Created Uptime = $Containers.($Opt2.Container_id).Uptime IpPublic = $(if($details){Invoke-Opt2Command $Opt2 -Commands "curl icanhazip.com --connect-timeout 1 --max-time 1 || curl -s http://checkip.dyndns.org --connect-timeout 1 --max-time 1 | sed -e 's/.*Current IP Address: //' -e 's/<.*$//' --connect-timeout 1 --max-time 1 || curl ipecho.net/plain --connect-timeout 1 --max-time 1 || echo 'NoWeb!'"}) DockerInspect = $(if($details){(Invoke-SSHCommand -SessionId $SSHsession.SessionId -command "docker inspect $($Containers.($Opt2.Container_id).Name)" -ea stop).output | ConvertFrom-Json}) } } } else { Write-LogStep "> Http API $PrintServer ", 'Injoignable !' error throw "Impossible de joindre l'API Rest sur $PrintServer !" } } end { $SSHsession | Remove-SSHSession -ea 0 | Out-Null } } Function Get-Opt2Tunnels () { <# .SYNOPSIS Recupere la liste des Tunnels .DESCRIPTION Retourne la liste des Sites (Tunnels) d'un enssemble de Dockers .PARAMETER Opt2s Objets OPT2 de type Get-Opt2 ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN .PARAMETER Filter Filtre de type hostname ou IP ou Nom de site .EXAMPLE toute les conf de tous les Opt2 Get-Opt2Tunnels .EXAMPLE toute les confs de acom Get-Opt2Tunnels -Opt2s acom .EXAMPLE toute les confs de acom Get-Opt2 -Opt2s acom | Get-Opt2Tunnels .EXAMPLE toute les confs dont le site contiend 'bdx' Get-Opt2Tunnels -filter bdx .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param( [Parameter(ValueFromPipeline = $true)] $Opt2s = '*', $filter = '*', [switch]$details = $false ) process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2 $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2] valide" warn return Get-Opt2 -filter $Opt2 -details:$details | Get-Opt2Tunnels -filter $filter -details:$details } if ((Test-TcpPort $Opt2.ip -port 80 -ConfirmIfDown).time) { try { $apiSite = Invoke-RestMethod "http://$($Opt2.ip)/api/sites/" -ea stop $Tunnels = $apiSite.results | Where-Object { $_.id -like $Filter -or $_.hostname -like $Filter } | ForEach-Object { try { $conf = (Invoke-RestMethod -Method Get -Uri "http://$($Opt2.ip)/api/config/$($_.id)" -ea 0) $confs = [PSCustomObject]@{ BandwidthLimitation = [boolean] $conf.BandwidthLimitation UploadLimit = [int] $conf.UploadLimit DownloadLimit = [int] $conf.DownloadLimit } } catch { $confs = [PSCustomObject]@{ BandwidthLimitation = [boolean] $true UploadLimit = [int] 100 DownloadLimit = [int] 10000 } } [PSCustomObject]@{ Name = $_.id IP = $_.hostname Channels = $_.Channels | % { [PSCustomObject]@{ Name = $_.description IP = $_.hostname Ports = $_.ports } } Configs = $confs IpPublic = $(if($details){Invoke-OptBoxCommand -ip ($_.hostname) -Commands "curl icanhazip.com --connect-timeout 1 --max-time 1 || curl -s http://checkip.dyndns.org --connect-timeout 1 --max-time 1 | sed -e 's/.*Current IP Address: //' -e 's/<.*$//' --connect-timeout 1 --max-time 1 || curl ipecho.net/plain --connect-timeout 1 --max-time 1 || echo 'NoWeb!'"}) } } Write-LogStep '> Listing Tunnels ', $Opt2.hostname, "Filtre = '$Filter'" ok } catch { Write-LogStep '> Listing Tunnels ', $Opt2.hostname, "Filtre = '$Filter'", $_ Error $Tunnels = "$($Opt2.hostname)/api/sites/ ne repond pas correctement !" } } else { Write-LogStep '> Listing Tunnels ', $Opt2.hostname, "Filtre = '$Filter'" Error $Tunnels = "$($Opt2.hostname) ne repond pas !" } try{ $Opt2 | Add-Member -MemberType NoteProperty -Name 'Tunnels' -Value $null -ea 0 }catch{} $Opt2.tunnels = $Tunnels Write-LogStep "> Total filtered [$($opt2.hostname)] ", "$($opt2.tunnels.IP.count) Sites", "$($opt2.tunnels.channels.IP.count) Imprimantes" ok $Opt2 } } } Function Export-Opt2Config ( [Parameter(ValueFromPipeline = $true)] $Opt2s = '*', $Path = '\\vdiv05.coaxis-asp.com\e$\Saves\OPT2.conf') { <# .SYNOPSIS Exporte dans un fichier les JSON tes tunnels et des imprimantes en OPT2 .DESCRIPTION Retourne les chemin des fichier exporte .PARAMETER Opt2s Objets OPT2 de type Get-Opt2 ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN .PARAMETER Path Chemin de sauvegarde des JSON .EXAMPLE Exporte 1 seul site Get-Opt2Tunnels *shared2* -filter ed00 | Export-Opt2Config .EXAMPLE Exporte tous Get-Opt2Tunnels | Export-Opt2Config .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2Tunnels $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2Tunnels] valide" warn return $Opt2 | Get-Opt2Tunnels -filter * -details | Export-Opt2Config -Path $Path } $dns = $Opt2.hostname -replace ('http:') -replace ('/') $outfile = "$path\$dns\SitesImps_$(get-date -Format 'yyyy-MM-dd').json" try { if (!(test-path "$path\$dns")) { New-Item -Path "$path\$dns" -ItemType Directory -wa 0 -Force | out-null Start-Sleep -m 150 } $Opt2 | ConvertTo-Json -Depth 5 | Out-File $outfile -Encoding utf8 $outfile Write-LogStep "[$($opt2.hostname)]", "$($opt2.tunnels.IP.count) Sites", "$($opt2.tunnels.channels.IP.count) Imprimantes" OK } catch { Write-LogStep "Recup. des Configs [$($Opt2.hostname)]", $_ error } } } end { Write-LogStep '','Fin des Exports !' ok } } function import-Opt2Config { <# .SYNOPSIS Genere les Site/Tunnels sur une interface OPT2 .DESCRIPTION - creation du container s'il n'existe pas tente l'ajoute : - des tunnels - des imprimantes (respecet le port d'origine) - update les bandWith .PARAMETER Files Fichiers d'import valide ! chacun de ces fichiers sera lu pour creation avec l'API .EXAMPLE Importe une config complete import-Opt2Config .\SitesImps_2018-10-19.json .EXAMPLE restauration manuelle dans le fichier de conf du docker $toptex = Get-Content '\\vdiv05.coaxis-asp.com\e$\Saves\OPT2.conf\toptex.opt2\SitesImps_2019-05-06_toulouse.json' | ConvertFrom-Json $i=0 ($toptex.Tunnels.Channels | %{ "[$i]=`"L *:$($_.ports.listen):$($_.IP):$($_.ports.send) # $($_.Name)`"" $i++ }) -join(' ') .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param( [Parameter(ValueFromPipeline = $true)] [ValidateScript( { $_ | Test-Path })] $Files = '\\vdiv05.coaxis-asp.com\e$\Saves\OPT2.conf\shared2.opt2\SitesImps_2018-10-00.json' ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } } process { foreach ($File in $Files) { try { $Opt2 = (get-content $File | convertFrom-json) Write-LogStep "Configs [$($file | Split-Path -Leaf)]", $opt2.hostname, "$($opt2.tunnels.IP.count) Sites", "$($opt2.tunnels.channels.IP.count) Imprimantes" wait $WorkOnOpt2 = [PSCustomObject]@{ hostname = $Opt2.hostname ip = $Opt2.ip subnet = $Opt2.subnet gateway = $Opt2.gateway vlan = $Opt2.vlan Container_id = $null } | New-Opt2 $Opt2.id = $WorkOnOpt2.id $Opt2.Container_id = $WorkOnOpt2.Container_id if($wait){ $waitingNew = [progressBarre]::new() $percent = $wait * 3 while ($percent -and !(Test-TcpPort $Opt2.ip -port 80 -timeout 50 -ConfirmIfDown).time) { $percent-- Start-Sleep -Milliseconds 333 $waitingNew.write("~~$((($wait*3-$percent)/($wait*3))*100)") #Write-ProgressBarreColor -Percents "~$((($wait*3-$percent)/($wait*3))*100)" -replaceLine } # $waitingNew.write("~30") # $waitingNew.write("~40") if ((Test-TcpPort $Opt2.ip -port 80 -timeout 50 -ConfirmIfDown).time){ # $waitingNew.write("~~80") # $waitingNew.write("~~90") $waitingNew.write("100") # Write-ProgressBarreColor -Percents 100 -replaceLine }else{ $waitingNew.write("~~100") # Write-ProgressBarreColor -Percents "~~100" -replaceLine throw "Impossible de joindre l'API [$($Opt2.ip):80], verifier le Routage du Vlan $($Opt2.vlan)" } Start-Sleep -s 1 Write-Host '' } $Opt2 | Add-Opt2Tunnels | Set-Opt2BandWidth | Add-Opt2Channels | out-null $Opt2 | Restart-Opt2 | Get-Opt2Tunnels } catch { Write-LogStep "BackEnd API request $($opt2.hostname)", $_ error } } } } function Add-Opt2Channels { <# .SYNOPSIS Ajoute un item dans un tunnel existant .DESCRIPTION parcoure tous les tunnels fournis et ajoute tous les items qui y sont specifie .PARAMETER Opt2s Objets OPT2Tunnels de type Get-Opt2Tunnels ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN Par defaut Rien! .EXAMPLE recharge les imprimantes sur chaque sites de la sauvegarde Add-Opt2Channels -opt2s $sauvegardeOpt2 .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [ValidateNotNullOrEmpty()][Parameter(ValueFromPipeline = $true)] $Opt2s = $null ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } } process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2Tunnels $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2Tunnels] valide" error return $null # return Get-Opt2 -detail:$false -filter $Opt2 | Set-Opt2BandWidth } foreach ($site in $Opt2.Tunnels) { if (!(is-Tunnels $site)) { Write-LogStep "Verrification de l'oject [$site]", "N'est pas un Object [Tunnel] valide" error } else { Write-LogStep "| |--> identification du Port ", 'Auto / Force' ok $site.channels | ? {$_.name -and $_.ip} | ForEach-Object { if ($_.ports.listen -or $_.ports.send){ $channel = [PSCustomObject]@{ site = $site.Name description = $_.name hostname = $_.ip ports = $_.ports } } else { $channel = [PSCustomObject]@{ site = $site.Name description = $_.name hostname = $_.ip } } try { # ajout des imprimante en port automatique $post = Invoke-RestMethod -Method Post -Uri "http://$($Opt2.ip)/api/printers/" -Headers $header -Body ($channel | convertto-json -Compress) if ($post.cmd.exit_status -eq $true) { Write-LogStep "| |--> Add Item [$($_.Name)] ", $_.ip, "[Tcp: $($_.ports.listen)]" ok } else { Write-LogStep "| |--> Add Item [$($_.Name)] ", $_.ip, "[Tcp: $($_.ports.listen)]" error } Start-Sleep -m 250 } catch { Write-LogStep "| |--> Add Item [$($channel.description)] ", $_.Exception.Response.StatusDescription, $channel.hostname, "[Tcp: $($channel.ports.listen)]" error } } } } $Opt2 } } } function Add-Opt2Tunnels { <# .SYNOPSIS Connecte un OptBox (tunnel) sur l'interface .DESCRIPTION supprime l'IP du KnownHost, ajoute un Site avec l'ensemble des configs Name, IP, UploadLimit, DownloadLimit... .PARAMETER Opt2s Objets OPT2Tunnels de type Get-Opt2Tunnels valide Par defaut Rien! .EXAMPLE Ajoute un Site a l'interface OPT2 $opt2 | Add-Opt2Tunnels .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [ValidateNotNullOrEmpty()][Parameter(ValueFromPipeline = $true)] $Opt2s = $null ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } } process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2Tunnels $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2Tunnels] valide" warn return } foreach ($site in $Opt2.tunnels) { try { Invoke-Opt2Command -Opt2s $Opt2 -Commands "ssh-keygen -f /home/mast/.ssh/known_hosts -R $($site.IP) && ssh-keygen -f /root/.ssh/known_hosts -R $($site.IP)" | out-null $post = Invoke-RestMethod -Method Post -Uri "http://$($Opt2.ip)/api/sites/" -Headers $header -Body ( @{'id' = $site.name; 'hostname' = "$($site.IP)"} | convertto-json -Compress ) if ($post.results[-1] -like '*failed*' -and $post.cmd.exit_status -eq $true ) { Write-LogStep "|--> Add Tunnel [$($site.Name)]", "$($site.IP)", (($post.results | ? {$_ -match 'failed'}) -replace ('.* +\((.+ .*)\)', '$1!')) warn } elseif ($post.cmd.exit_status -eq $true) { Write-LogStep "|--> Add Tunnel [$($site.Name)]", "$($site.IP)" ok } else { if ((Test-TcpPort $site.ip -port 22 -ConfirmIfDown).time) { Write-LogStep "|--> Add Tunnel [$($site.Name)]", "$($site.IP):22", 'Injoignable!', (($post.results | ? {$_ -match 'failed'}) -replace ('.* +\((.+ .*)\)', '$1!')) error } else { Write-LogStep "|--> Add Tunnel [$($site.Name)]", "$($site.IP)", (($post.results | ? {$_ -match 'failed'}) -replace ('.* +\((.+ .*)\)', '$1!')) error } } [PSCustomObject]@{ hostname = $Opt2.hostname ip = $Opt2.ip subnet = $Opt2.subnet gateway = $Opt2.gateway vlan = $Opt2.vlan Container_id = $Opt2.Container_id Tunnels = $site } } catch { Write-LogStep "|--> Add Tunnel $($Opt2.hostname) ", $site.Name, $site.IP, (((($_.ErrorDetails.Message | ConvertFrom-Json).results | ? {$_ -match 'failed'})[0]) -replace (' *failed *', ' [Failed!] ')) error } } } } } function Remove-Opt2Tunnels { <# .SYNOPSIS Supprime de l'interface un tunnel OptBox .DESCRIPTION Arrete le tunnel et le supprime ainsi que tous les channels qui s'y trouve .PARAMETER Opt2s Objets OPT2Tunnels de type Get-Opt2Tunnels valide, chacun des tunnels sera supprime Par defaut Rien! .EXAMPLE Add-Opt2Tunnels $opt2 -filter 'paris' .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [ValidateNotNullOrEmpty()][Parameter(ValueFromPipeline = $true)] $Opt2s = $null ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } } process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2Tunnels $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2Tunnels] valide" warn return } foreach ($site in $Opt2.tunnels) { if (!(is-Tunnels $site)) { Write-LogStep "Verrification de l'oject [$site]", "N'est pas un Object [Tunnel] valide" error } else { try { Invoke-RestMethod -Method Put -Uri "http://$($Opt2.ip)/api/sites/$($site.name)" -Headers $header -Body ( @{'action' = 'stop'; 'id' = $($site.name); 'hostname' = "$($site.IP)"} | convertto-json -Compress ) | Out-Null Start-Sleep -s 1 Invoke-RestMethod -Method Delete -Uri "http://$($Opt2.ip)/api/sites/$($site.name)" -Headers $header | Out-Null Write-LogStep "|--> Suppression du site ","[$($site.Name)]", "$($site.IP)" ok } catch { Write-LogStep "|--> Suppression du site $($Opt2.hostname) ", $site.Name, $site.IP, (((($_.ErrorDetails.Message | ConvertFrom-Json).results | ? {$_ -match 'failed'})[0]) -replace (' *failed *', ' [Failed!] ')) error } } } $Opt2 | Get-Opt2Tunnels } } end { } } function Restart-Opt2Tunnels { <# .SYNOPSIS Redemare un tunnel OptBox .DESCRIPTION Redemare le tunnel et les channels qui s'y trouve .PARAMETER Opt2s Objets OPT2Tunnels de type Get-Opt2Tunnels valide, chacun des tunnels sera supprime Par defaut Rien! .EXAMPLE Add-Opt2Tunnels $opt2 -filter 'paris' .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [ValidateNotNullOrEmpty()][Parameter(ValueFromPipeline = $true)] $Opt2s = $null ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } $Tunnels = @() } process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2Tunnels $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2Tunnels] valide" warn return } foreach ($site in $Opt2.tunnels) { if (!(is-Tunnels $site)) { Write-LogStep "Verrification de l'oject [$site]", "N'est pas un Object [Tunnel] valide" error } else { try { Invoke-RestMethod -Method Put -Uri "http://$($Opt2.ip)/api/sites/$($site.name)" -Headers $header -Body ( @{'action' = 'restart'; 'id' = $($site.name); 'hostname' = "$($site.IP)"} | convertto-json -Compress ) | Out-Null Write-LogStep "|--> Redemarage du site ","[$($site.Name)]", "$($site.IP)" ok $Tunnels += ($Opt2 | Get-Opt2Tunnels -filter $site.Name).tunnels } catch { Write-LogStep "|--> Redemarage du site $($Opt2.hostname) ", $site.Name, $site.IP, (((($_.ErrorDetails.Message | ConvertFrom-Json).results | ? {$_ -match 'failed'})[0]) -replace (' *failed *', ' [Failed!] ')) error } } } } $Opt2s.tunnels = $Tunnels $Opt2s } end { } } # if(($post = Invoke-RestMethod -Method Post -Uri "http://shared2.opt2/api/sites/" -Headers $header -Body ( # @{'id'= "abce231"; 'hostname'= "8.67.177.199"} | convertto-json -Compress # ) -ea 0).exit_status -eq $true){'YES'} function Set-Opt2BandWidth ([ValidateNotNullOrEmpty()][Parameter(ValueFromPipeline = $true)] $Opt2s = $null, [ValidateRange(10, 2500)]$Uploadlimit = $null) { <# .SYNOPSIS Change la vitessse d'un tunnel .DESCRIPTION Modifie la config de vitesse d'un site, puis l'applique retourne la config modifie .PARAMETER Opt2s Objets OPT2Tunnels de type Get-Opt2Tunnels ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN Par defaut Rien! .PARAMETER UploadLimit bande passante de l'asp vers le local valeur valide entre : 10-2500 .EXAMPLE change la bande passante du site scih bandol get-opt2Tunnels *scih* -filter *bandol* | Set-Opt2BandWidth 250 .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } } process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2Tunnels $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2Tunnels] valide" error return $null # return Get-Opt2 -detail:$false -filter $Opt2 | Set-Opt2BandWidth } $Opt2.Tunnels | % { try { if (!(is-Tunnels $_)) { Write-LogStep "Verrification de l'oject [$_]", "N'est pas un Object [Tunnel] valide" error } else { if (!$Uploadlimit -and $_.Configs.UploadLimit -gt 10) { $Uploadlimit = $_.Configs.UploadLimit } $realSpeed = Invoke-RestMethod -Method Put -Uri "http://$($Opt2.ip)/api/config/$($_.name)" -Headers $header -Body (@{ UploadLimit = $Uploadlimit # Case Sensitive DownloadLimit = $Uploadlimit * 100 # Case Sensitive } | convertto-json -Compress) $_.Configs.UploadLimit = $realSpeed.UploadLimit $_.Configs.DownloadLimit = $realSpeed.DownloadLimit # il faut aussi redemarer le tunnels Invoke-RestMethod -Method Put -Uri "http://$($Opt2.ip)/api/sites/$($_.name)" -Headers $header -Body ( @{'action' = 'restart'; 'id' = $($_.name); 'hostname' = "$($_.IP)"} | convertto-json -Compress ) | Out-Null Write-LogStep "|--> Change Speed ", $_.name,"$($_.Configs.UploadLimit) Ko/sec" ok } } catch { Write-LogStep "|--> Change Speed ", $_ Error } } $Opt2 } } } function Update-Opt2 { <# .SYNOPSIS Mise a jour du containeur .DESCRIPTION Detecte la derniere version OPT2 presente sur l'hote et relance les OPT2 sur cette version .PARAMETER Opt2s Objets OPT2 de type Get-Opt2 ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN .PARAMETER Version Numero de version a utiliser, si il n'est pas fournis la mise a jour sera faire en derniere version .EXAMPLE mettre a jour un seul container Get-Opt2 *shared2* | Update-Opt2 .EXAMPLE mettre a jour tous les containeurs Update-Opt2 .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [Parameter(ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] $Opt2s = $null, $Version = $null ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } $Opt2Versions = (Invoke-RestMethod -Method GET -Uri "http://$PrintServer/api/daemon-versions/?format=json") | ? { $_ -match 'v\d\.\d+\.\d+' } if (!$Version -or $Opt2Versions -notcontains $Version) { # on cherche le meilleure version $Version = 'v' + (($Opt2Versions | % { [version]($_.trimstart('v')) } | Sort-Object -Descending -Unique)[0]).ToString() if ($Opt2Versions -notcontains $Version) { # si pas de version Numerique $Version = 'latest' } } Write-LogStep "Best Version [$($Version)] ", "Avalaible versions [$($Opt2Versions)]" # $BestOpt2Version = $Opt2Versions[0] } process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2 $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2] valide" warn return Get-Opt2 -detail:$false -filter $Opt2 | Update-Opt2 } # mise a jour Invoke-RestMethod -Method POST -Uri "http://$PrintServer/api/containers/" -Headers $header -Body (@{ id = $Opt2.id action = "upgrade" version = $Version } | convertto-json -Compress) | Out-Null Start-Sleep -Seconds 1 Write-LogStep "Update/Restart Container ", $Opt2.hostname ok $Opt2.vlan | Get-Opt2 -details } } } function New-Opt2 { <# .SYNOPSIS Genere un containeur .DESCRIPTION verrifi les config puis genere le container, retoune l'oject correspondant .PARAMETER Opt2s Objets OPT2 de type Get-Opt2 Par defaut Rien! .EXAMPLE cree un nouveau containeur New-Opt2 -IpAddress 10.128.12.175 -maskCIDR 26 -Gateway 10.128.12.180 -Vlan 1350 -ClientName toto .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [Parameter(Mandatory = $true, ParameterSetName = 'NewDefined')] [ValidatePattern('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$')] $IpAddress, [Parameter(Mandatory = $true, ParameterSetName = 'NewDefined')] [ValidateSet(16, 22, 23, 24, 25, 26, 27, 28)] [int]$maskCIDR, [Parameter(Mandatory = $true, ParameterSetName = 'NewDefined')] [ValidatePattern('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$')] $Gateway, [Parameter(Mandatory = $true, ParameterSetName = 'NewDefined')] [ValidateRange(200, 4096)] [int]$Vlan, [Parameter(Mandatory = $true, ParameterSetName = 'NewDefined')] [string]$ClientName, [Parameter(ValueFromPipeline = $true, Mandatory = $true, ParameterSetName = 'AlreadyDefined')] [ValidateNotNullOrEmpty()] $Opt2s = $null ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } $AlreadyExistOpt2s = Get-Opt2 -details:$false if (!$Opt2s) { $Opt2s = [pscustomobject][ordered]@{ vlan = $Vlan ip = $IpAddress subnet = "$IpAddress/$maskCIDR" gateway = $gateway hostname = "http://$clientName.opt2" Container_id = $null } } } process { foreach ($Opt2 in $Opt2s) { try { if ($Opt2.ip -notmatch '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$') { Write-LogStep "IP [$($Opt2.ip)] ", 'Doit etre une IP valide' Error $HasError = $Opt2 } else { $isUp = (ping $Opt2.ip -ports 0, 22, 80, 135, 445 -loop 3 -Intervale 250 -timeout 20).status | Sort-Object -Unique if ($isUp.count -ne 1 -or $isUp -notlike '0%') { Write-LogStep "Check IP [$($Opt2.ip)] ", 'Doit etre une libre !' Error $HasError = $Opt2 } } if ($AlreadyExistOpt2s.vlan -contains $Opt2.vlan) { Write-LogStep "Check Vlan [$($Opt2.vlan)] ", 'Il existe deja un Opt2 sur ce Vlan' Error $HasError = $Opt2 Get-Opt2 $Opt2.vlan } elseif ($Opt2.vlan -gt 4096 -or $Opt2.vlan -lt 200) { Write-LogStep "Check Vlan [$($Opt2.vlan)] ", 'Doit etre un numero de VLAN valide!' Error $HasError = $Opt2 } if ($Opt2.hostname -notlike 'http://*.opt2') { Write-LogStep "Check hostname [$($Opt2.hostname)] ", 'Doit etre de la forme "http://*.opt2"' Error $HasError = $Opt2 } if ($Opt2.subnet -notmatch '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/(16|22|23|24|25|26|27|28)$') { Write-LogStep "Check Subnet [$($Opt2.subnet)] ", 'Doit etre de la forme "IP/CIDR"' Error $HasError = $Opt2 } if ($Opt2.gateway -notmatch '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$') { Write-LogStep "Check GateWay [$($Opt2.gateway)] ", 'Doit etre de la forme "IP"' Error $HasError = $Opt2 } if (!$HasError) { $Opt2.hostname | New-Opt2DnsEntry -IpAddress $Opt2.IP $Opt2 | Add-Member -MemberType NoteProperty -Name 'client_id' -Value '96da4115-9578-4272-acb9-de32283d4574' $NewOpt2 = $Opt2 | ConvertTo-Json -Compress if ((Invoke-WebRequest -Uri "http://$PrintServer/api/daemons/" -Method Post -Body $NewOpt2 -Headers $Header).StatusCode -eq 201) { Write-LogStep "Creation [$($Opt2.hostname)] ", "Vlan $($Opt2.vlan)", "IP $($Opt2.ip)", "SubNet $($Opt2.subnet)", "Gateway $($Opt2.Gateway)" ok } Get-Opt2 $Opt2.vlan } } catch { Write-LogStep "BackEnd API request $($opt2.hostname)", $_ error } } } } function New-Opt2DnsEntry { <# .SYNOPSIS Ajoute une entree DNS dans la zone OPT2 .DESCRIPTION ajoute une entré DNS pour un nouvel OPT2 et teste la resolution .PARAMETER Name Nom pour l'entre de type A .PARAMETER IpAddress Address IP pour l'entre de type A .PARAMETER Wait Temps d'attente pour validation .EXAMPLE cree une nouvelle entre dns sur le split pour duoconseils New-Opt2DnsEntry -Names duoconseils -IpAddress 10.128.12.175 .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [Parameter(ValueFromPipeline = $true,Mandatory = $true)] [ValidateNotNullOrEmpty()] $Names = $null, [Parameter( Mandatory = $true)] [ValidatePattern('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$')] $IpAddress = $null, $wait = 10 ) begin{ $SplitDns = [PSCustomObject]@{ IP = '172.16.1.1' Credential = Get-CredentialByRegistry -ntAccountName 'Berlin8' } } process { foreach ($Name in $Names) { $Name = $name.ToLower().replace('.opt2','').replace('http://','') try { Write-LogStep "Add DNS on splitDns [$($SplitDns.IP)] ", "${name}.opt2", $IpAddress wait if ($wait) { # $script:CursorLeft = $script:CursorTop = $null $percent = $wait *3 $percent-- # Write-ProgressBarreColor -Percents "~$((($wait*3-$percent)/($wait*3))*100)" -replaceLine } start-job -ScriptBlock { param($SplitDns,$name,$IpAddress) Invoke-WmiMethod -ComputerName $SplitDns.IP -Credential $SplitDns.Credential -Path win32_process -Name create -ArgumentList "dnscmd /recordadd opt2 $Name A $ipaddress" } -arg $SplitDns,$name,$IpAddress | Out-Null if ($wait) { $waitingDns = [progressBarre]::new() while ($percent -and !(Resolve-DnsName -Name "${name}.opt2" -Server $SplitDns.ip -Type A -ea 0)) { $percent-- Start-Sleep -Milliseconds 333 $waitingDns.write("~$((($wait*3-$percent)/($wait*3))*100)") # Write-ProgressBarreColor -Percents "~$((($wait*3-$percent)/($wait*3))*100)" -replaceLine } while ($percent -and !([System.Net.Dns]::GetHostByName("${name}.opt2").addressList.IPAddressToString -contains $IpAddress)) { $percent = $percent - 3 Start-Sleep -Milliseconds 1000 $waitingDns.write("~$((($wait*3-$percent)/($wait*3))*100)") # Write-ProgressBarreColor -Percents "$((($wait*3-$percent)/($wait*3))*100)" -replaceLine Clear-DnsClientCache } if ([System.Net.Dns]::GetHostByName("${name}.opt2").addressList.IPAddressToString -contains $IpAddress){ [PSCustomObject]@{ $IpAddress = "${name}.opt2" } $waitingDns.write("100") # Write-ProgressBarreColor -Percents 100 -replaceLine }else{ $waitingDns.write("~~100") # Write-ProgressBarreColor -Percents "~~100" -replaceLine } Write-Host '' } Write-LogStep "Add DNS on splitDns [$($SplitDns.IP)] ", "${name}.opt2", $IpAddress, 'Type A ' ok } catch { Write-LogStep "Add DNS on splitDns [$($SplitDns.IP)] ", $_ error } } } } # function remove-Opt2 ($opt2s){ # <# # .SYNOPSIS # [Descriptif en quelques mots] # .DESCRIPTION # [Descriptif en quelques lignes] # .PARAMETER Opt2s # Objets OPT2 de type Get-Opt2 # ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN # Par defaut * # .EXAMPLE # remove-Opt2 # .NOTES # Alban LOPEZ 2018 # alban.lopez@gmail.com # http://git/PowerTech/ # #> # begin{ # $Header = @{ # 'Content-Type' = 'application/json' # 'Accept' = 'application/json' # } # } # # # Invoke-WebRequest -Uri 'http://$PrintServer/api/networks/' -Method GET # authentification requise # # GET http://$PrintServer/api/networks/ # # # Invoke-WebRequest -Uri 'http://$PrintServer/api/networks/a3e9466b70cd543f7783f7328da8709ff7194651774369fea5b6b62e013c53d1/' -Method DELETE -Headers $Header # authentification requise # # DELETE http://$PrintServer/api/networks/a3e9466b70cd543f7783f7328da8709ff7194651774369fea5b6b62e013c53d1/ # } function Restart-Opt2 { <# .SYNOPSIS Redemare un containeur .DESCRIPTION Retourne les propriete du containneur opt apres le reboot .PARAMETER Opt2s Objets OPT2Tunnels de type Get-Opt2Tunnels ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN Par defaut Rien! .EXAMPLE Redemare le shared2 Get-Opt2 *shared2* | Restart-Opt2 .EXAMPLE Update-Opt2 .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [Parameter(ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] $Opt2s = $null, [ValidateRange(0, 60)][int]$wait = 15 ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } } process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2 $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2] valide" warn return Get-Opt2 -detail:$false -filter $Opt2 | restart-Opt2 -wait $wait } try { $Opt2Restarted = (Invoke-RestMethod -Method POST -Uri "http://$PrintServer/api/containers/" -Headers $header -Body (@{ id = $Opt2.id action = "restart" } | convertto-json -Compress)) if($wait){ $waitingRestart = [progressBarre]::new() #Write-LogStep 'Redemarage Docker ',$Opt2.hostname wait # $script:CursorLeft = $script:CursorTop = $null $percent = $wait * 3 while ($percent -and !(Test-TcpPort $Opt2.ip -port 80 -timeout 50 -ConfirmIfDown).time) { $percent-- Start-Sleep -Milliseconds 333 $waitingRestart.write("~$((($wait*3-$percent)/($wait*3))*100)") #Write-ProgressBarreColor -Percents "~$((($wait*3-$percent)/($wait*3))*100)" -replaceLine } if ((Test-TcpPort $Opt2.ip -port 80 -timeout 50 -ConfirmIfDown).time){ $waitingRestart.write("100") # Write-ProgressBarreColor -Percents 100 -replaceLine }else{ $waitingRestart.write("~~100") #Write-ProgressBarreColor -Percents "~~100" -replaceLine } Write-Host '' Start-Sleep -Seconds 1 } $Opt2.id = $Opt2Restarted.ID $Opt2.container_id = $Opt2Restarted.container_id $Opt2 } catch { Write-Object $opt2 Write-LogStep '',$_ Error } } } } function Restart-OptBox { <# .SYNOPSIS Redemare un boitier distant .DESCRIPTION se connecte en ssh et demande un reboot au boitier .PARAMETER IpAddresses Addresse IP du boitier local .PARAMETER cred Credential du boitier .PARAMETER Wait Temps d'attente pour validation .EXAMPLE redemade le RPi '10.48.50.7', '10.48.50.7' | Restart-OptBox .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> param ( [Parameter(ValueFromPipeline = $true, Mandatory = $true)] [ValidatePattern('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$')] [string] $IpAddresses, $cred = (Get-CredentialByRegistry 'coaxis'), $wait = 60 ) begin{ $waitingOptBox = @() } process { foreach ($IpAddress in $IpAddresses) { try { $cmd = 'sudo reboot' $SSHsession = New-SSHSession $IpAddress -Credential $cred -Force -wa 0 -ea stop $stream = $SSHsession.Session.CreateShellStream("PS-SSH", 0, 0, 0, 0, 100) Invoke-SSHStreamExpectSecureAction -ShellStream $stream -Command $cmd -ExpectString "[sudo] password for $($cred.UserName):" -SecureAction $cred.Password | Out-Null Write-LogStep "OptBox SSH request [$IpAddresses] ", $cmd, 'Wait 1 min' ok if($wait){ $waitingOptBox += [PSCustomObject]@{ IP = $IpAddress Waiting = [progressBarre]::new() isUp = $false } Write-Host '' } } catch { Write-LogStep "OptBox SSH request [$IpAddresses] ", "Echec '$cmd' !",$_ error } $SSHsession | Remove-SSHSession -ea 0 | Out-Null } } end{ if($wait){ Start-Sleep -Seconds 1 $percent = $wait while ($percent -and $waitingOptBox.isUp -contains $false) { $percent-- $zero = Get-Date foreach ($box in $waitingOptBox){ if (!(Test-TcpPort $IpAddress -port 80 -timeout 100).time){ $box.waiting.write("~$((($wait-$percent)/($wait))*100)") } elseif ((Test-TcpPort $IpAddress -port 80 -timeout 100 -ConfirmIfDown).time){ $box.waiting.write("100") $box.isUp = $true Invoke-RestMethod -Method Get -Uri "http://$IpAddress/libs/system.php" | %{[PSCustomObject]@{ HostName = $_.hostname Uptime = $_.Uptime IP = ((Invoke-RestMethod -Method Get -Uri "http://$IpAddress/libs/network.php") | ?{$_.ip -match $IpAddress}).ip -split('<br>') }} }else{ $box.waiting.write("~~100") } } Start-Sleep -Milliseconds (1000-((get-date)-$zero).TotalMilliseconds) -ea 0 } Write-Host '' } } } function Invoke-OptBoxCommand { <# .SYNOPSIS Execute une commande sur le boitier OptBox local .DESCRIPTION chacune des commandes sera executé dans l'orde retourne les resultats .PARAMETER IpAddresses Addresse IP du boitier local .PARAMETER cred Credential du boitier .PARAMETER Commands liste de commande a executer .EXAMPLE recherche l'IP publique du boitier OptBox Invoke-OptBoxCommand -ip '10.232.11.188' -commands "curl icanhazip.com --connect-timeout 1 --max-time 1" .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, Mandatory = $true)] [ValidatePattern('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$')] [string] $IpAddresses, $cred = (Get-CredentialByRegistry 'coaxis'), [string[]]$Commands = @( "curl icanhazip.com || curl -s http://checkip.dyndns.org | sed -e 's/.*Current IP Address: //' -e 's/<.*$//' || curl ipecho.net/plain" ) ) begin { } process { foreach ($IpAddress in $IpAddresses) { if((Test-TcpPort $IpAddress -port 22 -ConfirmIfDown).time){ try { $SSHsession = New-SSHSession $IpAddress -Credential $cred -Force -wa 0 -ea stop $Commands | %{ (Invoke-SSHCommand -command $_ -SessionId $SSHsession.SessionId -ea stop).output Write-LogStep "|--> SSH [$IpAddress] ", $_ ok } }catch{ Write-LogStep "|--> SSH [$IpAddress] ",$_ Error 'Error!' } $SSHsession | Remove-SSHSession -ea 0 | Out-Null } else { 'Injoignable!' } } } end { } } function Invoke-Opt2Command { <# .SYNOPSIS Execute une serie de commande dans les dockers .DESCRIPTION chacune des commandes sera executé dans l'orde retourne les resultats .PARAMETER Opt2s Objets OPT2 de type Get-Opt2 ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN Par defaut Rien! .PARAMETER Commands liste de commande a executer .EXAMPLE Affiche les Boitiers OPT2 Conu dasn le ssh know_host Invoke-Opt2Command shared2 -command 'ssh-keygen -l -f /home/mast/.ssh/known_hosts' .EXAMPLE retourne les process qui utilise un port specifique Invoke-Opt2Command shared2 -command 'ps -eo command | grep 9112:' .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> [CmdletBinding()] param( [Parameter(ValueFromPipeline = $true, Mandatory = $true)] [ValidateNotNullOrEmpty()] $Opt2s = $null, [string[]]$Commands = @( "ssh-keygen -l -f /home/mast/.ssh/known_hosts" # "ssh-keygen -f /home/mast/.ssh/known_hosts -R $IpAddress && ssh-keygen -f /root/.ssh/known_hosts -R $IpAddress" ) ) process { if ((Test-Path $sshKey)) { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2 $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2] valide",'Recherche...' warn return Get-Opt2 -detail:$false -filter $Opt2 | Invoke-Opt2Command -Commands $Commands } try { $SSHsession = New-SSHSession $PrintServer -Force -KeyFile $sshKey -Credential (New-Object System.Management.Automation.PSCredential("coaxis", $(new-object System.Security.SecureString))) -ea stop -wa 0 $Docker_ID = (($Opt2.Container_id)[0..12]) -join ('') $Commands | %{ (Invoke-SSHCommand -command "docker exec $Docker_ID sh -c `"$_`"" -SessionId $SSHsession.SessionId -ea stop).output # | out-null | ? {$_} | ForEach-Object { Write-LogStep "|--> SSH [$($opt2.hostname)]", $_ ok } } catch { Write-LogStep "|--> SSH [$($opt2.hostname)] ", $_ error } $SSHsession | Remove-SSHSession -ea 0 | Out-Null } } else { Write-LogStep "|--> SSH ",'PrivateKey Missing' error } } end { } } function Repair-OptBox { <# .SYNOPSIS Refait l'association SSH des tunnel .DESCRIPTION supprime l'IP du KnownHost, ajoute un faux Site et le supprime .PARAMETER Opt2s Objets OPT2 de type Get-Opt2 ou un filtre de type DNS, Pattern-Name, Pattern-IP ou Pattern-VLAN Par defaut * .PARAMETER Filter Filtre IP ou Nom d'un Site/OptBox .EXAMPLE Repair-OptBox *shared2* -filter paris .NOTES Alban LOPEZ 2018 alban.lopez@gmail.com http://git/PowerTech/ #> [Alias('Replace-OptBox')] param( [ValidateNotNullOrEmpty()][Parameter(ValueFromPipeline = $true)] $Opt2s = '*', $filter = '*' ) begin { $Header = @{ 'Content-Type' = 'application/json' 'Accept' = 'application/json' } } process { foreach ($Opt2 in $Opt2s) { if (!(is-Opt2Tunnels $Opt2)) { Write-LogStep "Verrification de l'oject [$Opt2]", "N'est pas un Object [Opt2Tunnels] valide" warn return Get-Opt2Tunnels $opt2 -filter $filter -detail:$false | Repair-OptBox } foreach ($site in $Opt2.tunnels) { try { $tmpOpt2 = [PSCustomObject]@{ # un object valide ! hostname = $Opt2.hostname ip = $Opt2.ip subnet = $Opt2.subnet gateway = $Opt2.gateway vlan = $Opt2.vlan Container_id = $Opt2.Container_id Tunnels = [PSCustomObject]@{ name = "tmp-$((get-md5 (get-date))[0..10] -join(''))" ip = $Site.ip channels = $null Configs = $null } } | Add-Opt2Tunnels if ($tmpOpt2) { $true Invoke-RestMethod -Method Put -Uri "http://$($TmpOpt2.ip)/api/sites/$($TmpOpt2.Tunnels[0].name)" -Headers $header -Body ( @{'action' = 'stop'; 'id' = $($TmpOpt2.Tunnels[0].name); 'hostname' = "$($site.IP)"} | convertto-json -Compress ) | Out-Null Start-Sleep -s 1 Invoke-RestMethod -Method Delete -Uri "http://$($TmpOpt2.ip)/api/sites/$($TmpOpt2.Tunnels[0].name)" -Headers $header | Out-Null Write-LogStep "|--> Acouplement : Opt2 <=> Box ","[$($site.Name)]", "$($site.IP)" ok [PSCustomObject]@{ # un object valide ! hostname = $Opt2.hostname ip = $Opt2.ip subnet = $Opt2.subnet gateway = $Opt2.gateway vlan = $Opt2.vlan Container_id = $Opt2.Container_id Tunnels = $site } | Restart-Opt2Tunnels } } catch { Write-LogStep "|--> Acouplement : Opt2 <=> Box ", $TmpOpt2.hostname, $site.Name, $site.IP, (((($_.ErrorDetails.Message | ConvertFrom-Json).results | ? {$_ -match 'failed'})[0]) -replace (' *failed *', ' [Failed!] ')) error } } } } } function Test-Opt2Channels { <# .SYNOPSIS [Descriptif en quelques mots] .DESCRIPTION [Descriptif en quelques lignes] .PARAMETER hostName .PARAMETER Port .PARAMETER Tunnels .PARAMETER Channels .EXAMPLE Test-Opt2Channels .NOTES Alban LOPEZ 2019 alban.lopez@gmail.com http://git/PowerTech/ #> [alias('Test-PrinterPort')] <# .SYNOPSIS Test avance d'un port Tcp .DESCRIPTION effectu une requette JetDirect sur un port OPT2 et verifie qu'il est bien unique .PARAMETER IP HostName ou Addresse IP .PARAMETER Port Numero de Port Tcp .EXAMPLE teste tous les port du boitier OPTBox '10.208.1.251' chez toptex (Get-Opt2Tunnels toptex -filter 10.208.1.251) | Test-Opt2Channels | Out-GridView .NOTES Alban LOPEZ 2019 alban.lopez@gmail.com http://git/PowerTech/ #> [CmdletBinding()] param ( [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true, ParameterSetName = 'Tcp')] [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true, ParameterSetName = 'Channels')] [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true, ParameterSetName = 'Tunnels')] [alias('Address','HostAddress','IP')] [string]$hostName, [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true, ParameterSetName = 'Tcp')] [alias('PortNumber')] [int]$Port, [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true, ParameterSetName = 'Tunnels')] $Tunnels, [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true, ParameterSetName = 'Channels')] $Channels # [string]$Query = "@PJL INFO ID`n", # n'est pas pris en charge, a cause du 'ParameterSetName' # [int]$timeOut = 250 # n'est pas pris en charge, a cause du 'ParameterSetName' ) begin { [string]$Query = "@PJL INFO ID`n" # n'est pas pris en charge comme parametre, a cause du 'ParameterSetName' [int]$timeOut = 200 # n'est pas pris en charge comme parametre, a cause du 'ParameterSetName' } process { # Write-Object $PSCmdlet.ParameterSetName -backGroundColor Red # $PSBoundParameters | Write-Object -fore Magenta -backGroundColor Gray switch($PSCmdlet.ParameterSetName){ 'Tcp' { $status = [PSCustomObject]@{ Listening = $null Query = [PSCustomObject]@{ Accepted = $Null Reply = $Null Error = $Null } Conflit = $null } Write-LogStep 'Connectivite JetDirect ',"${HostName}:${Port}" Wait $timeMs = (Measure-Command { $tcpClient = New-Object System.Net.Sockets.TCPClient $connect = $tcpClient.BeginConnect($HostName, $Port, $null, $null) write-verbose "${HostName}:${Port} Connecting..." $connect.AsyncWaitHandle.WaitOne($timeOut, $false) | Out-Null }).TotalMilliseconds if ($tcpClient.Connected) { $status.Listening = $true $timeMs += (Measure-Command { $stream = $TcpClient.GetStream() # pour vider la sortie std avant de faire une demande write-verbose "${HostName}:${Port} Query : $($Query.trim("`n"))" $data = [System.Text.Encoding]::ASCII.GetBytes($Query) $stream.Write($data, 0, $data.Length) | Out-Null $status.Query.Accepted = $true $step = 200 $i = ($timeOut * 10) / $step # $waitTcp = [progressBarre]::new() # $waitTcp.write("~~") While ([int64]$tcpClient.Available -le 0 -and $i-- -gt 0) { Start-Sleep -Milliseconds $step # $waitTcp.write("~$((($timeOut * 20) - ($i * $step)) / ($timeOut * 20) * 100)") } # write-host }).TotalMilliseconds If ([int64]$tcpClient.Available -gt 0) { # $waitTcp.write("100") $stringBuilder = New-Object Text.StringBuilder try { $timeMs += (Measure-Command { $stream = $TcpClient.GetStream() $bindResponseBuffer = New-Object Byte[] -ArgumentList $tcpClient.Available [Int]$response = $stream.Read($bindResponseBuffer, 0, $bindResponseBuffer.count) $Null = $stringBuilder.Append(($bindResponseBuffer | ForEach-Object {[char][int]$_}) -join '') }).TotalMilliseconds $status.Query.Reply = $stringBuilder.Tostring().split("`r`n`f")[2] Write-Verbose "Read reply = $($status.Query.value)`n$($stringBuilder.Tostring())" } catch { $status.Query.Error = $_ } } elseif($i -gt 0) { $status.Query.Error = 'Reply is Empty!' $status.Query.Reply = $true # $waitTcp.write("~100~") } else { $status.Query.Error = 'Reply TimeOut!' $status.Query.Reply = $false # $waitTcp.write("~~100") } } write-verbose "${HostName}:${Port} > Reply ${timeMs}ms > $status !" $tcpClient.Close() | Out-Null $tcpClient.Dispose() | Out-Null $command = $msg = $count = $null if (($Site = (Invoke-RestMethod "http://$HostName/api/sites/" -ea 0).results)) { $Listening = Invoke-Opt2Command $HostName -command "ps -eo command | grep autossh | grep :${port}:" | ?{$_ -match 'coaxis@'} | ?{$_} | %{ Write-Verbose $_ [pscustomobject]@{ Tunnels = ($_ -split 'coaxis@')[-1] Channels = $_ -split(' -L ') -split(' ') | ?{$_ -match "\*\:${port}\:.+\:[0-9]+"} # Commands = $command } } if($Listening.Channels.count -gt 1){ $status.Conflit = $true Write-LogStep "Conflit Tcp Port [${hostName}:$port] ","Restart-Opt2 -opt $hostName" Error } elseif(!$Listening.Channels){ $status.Query.Error = "Aucun Tunnel n'ecoute sur le Port:${port}" } } [PSCustomObject]@{ IP = $HostName Port = $Port Status = $status Time = [math]::round($timeMs,1) Listening = $Listening } } 'Tunnels' { $Tunnels | %{ Write-LogStep 'Connectivite Tunnels ',"$HostName $($Tunnels.IP)" Warn [PSCustomObject]@{ HostName = ($hostName -split('//'))[1] Channels = $_.channels } } | Test-Opt2Channels } 'Channels' { $Channels | %{ Write-LogStep 'Connectivite Channels ',"$HostName $($Channels.IP) $($Channels.Ports.listen)" Warn [PSCustomObject]@{ HostName = $HostName Port = $_.Ports.listen } } | Test-Opt2Channels } } } end {} } if (Get-Module PsWrite) { # Export-ModuleMember -Function Convert-RdSession, Get-RdSession Write-LogStep 'Chargement du module ',$PSCommandPath ok } else { function Script:Write-logstep { param ( [string[]]$messages, $mode, $MaxWidth, $EachLength, $prefixe, $logTrace ) Write-Verbose "$($messages -join(',')) [$mode]" } } <# Creation d'un port + Imp # Powershell V4+ Windows 2012R2 # Creaton du port Add-PrinterPort -Name "GZ_%vps%:%port%_%imp%" -PrinterHostAddress "%vps%" -PortNumber %port% # Creaton du port de secour en direct Add-PrinterPort -Name "DIRECT_%imp%" -PrinterHostAddress "%imp%" # Install du driver if (Get-PrinterDriver -Name "MS Publisher Color Printer") { Write-Host "Pilote Generique deja present" } else { Write-Host "Installation du pilote generique : MS Publisher Color Printer" Add-PrinterDriver "MS Publisher Color Printer" } # Creation de l’objet imprimante Add-Printer -name "%name%" -PortName "GZ_%vps%:%port%_%imp%" -Location "%site%" -Comment "GZ par tunnel SSH (%UTC%)" -DriverName "MS Publisher Color Printer" #> function Rename-Opt2Item { <# .SYNOPSIS [Descriptif en quelques mots] .DESCRIPTION [Descriptif en quelques lignes] .PARAMETER Opt2s .EXAMPLE Rename-Opt2Item .NOTES Alban LOPEZ 2019 alban.lopez@gmail.com http://git/PowerTech/ #> [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] $Opt2s = $null ) begin { # sed -i 's/original/new/g' file.txt } process { foreach ($Opt2 in $Opt2s) { } } end {} } |