Skip to content

Instantly share code, notes, and snippets.

@schittli
Last active April 9, 2023 21:17
Show Gist options
  • Save schittli/9134de0b34ab18229b2fedf8f9fac2ab to your computer and use it in GitHub Desktop.
Save schittli/9134de0b34ab18229b2fedf8f9fac2ab to your computer and use it in GitHub Desktop.
LibGist: Use-Gists.ps1 #PowerShell #LibGist
# Funktionen, um LibGists zu nützen:
# • LibGist-Update-GistFiles
# Aktualisiert die LibGists alle (per default) 30 Tage
#
# • LibGist-Load-Gists
# Bindet die LibGists in ein Script ein
#
# • LibGist-List-Files
# Listet die verfügbaren LibGist Files
#
# • LibGist-Download-Files
# Lädt alle verfügbaren LibGist Files herunter
#
#
#
# Aktualisiert die Gists im gleichen Verzeichnis von LibGist-Use-Gists.ps1
# Arbeitet mit dem gleichnamigen json-File
# um die Aktualisierung nicht bei jedem ScriptStart zu steuern
#
# ℹ Getting started
# LibGist files in Scripts einbinden
# Download der verfügbaren LibGist Files
# c:\Scripts\PowerShell\-Gist\LibGist-Get-Gist.ps1 -DownloadFile -Verbose -ZielDir .\LibGistFiles
# Die LibGists Files löschen, die nicht benötigt werden
# Zwingend benötigt werden
# LibGist-Get-Gist.ps1
# LibGist-Update-GistFiles.ps1
# Die LibGist Files ins Verzeichnis vom Script kopieren,
# das sie nützen will
# LibGist ins Script einbinden
#
#
#
#
#
# Ex
# Alle Files gem. Zeitplan (default alle 30 Tage) auf Updates prüfen
# C:\Scripts\PowerShell\-Gist\LibGist-Update-GistFiles.ps1 -Now
#
# Alle Files auf Updates prüfen
# C:\Scripts\PowerShell\-Gist\LibGist-Update-GistFiles.ps1 -Now
#
# Die vorhandenen Gist-Files auflisten
# C:\Scripts\PowerShell\-Gist\LibGist-Update-GistFiles.ps1 -ListFiles
#
# Files herunterladen
# C:\Scripts\PowerShell\-Gist\LibGist-Update-GistFiles.ps1 -DownloadFiles file1.txt
#
#
# 001, 220126, tom-agplv3@jig.ch
# 002, 220127, tom-agplv3@jig.ch
# Json Config neu mit: UpdateScheduleDays
# 003, 220127, tom-agplv3@jig.ch
# Neu mit Funktionen
# • LibGist-Get-UseGists-Cfg
# • LibGist-List-Files
# • LibGist-Download-Files
# • LibGist-Update-GistFiles
# 004, 220128
# Fixed: Load-Json
# 005, 220129
# LibGist-Update-GistFiles -Now aktiviert Verbose
# $LibGistVersion_LibGist_Use_Gists_ps1
# Zeigt bei Verbose die geladenen Libversionen an
# LibGist-Get-UseGists-Cfg
# Liefert neu das ZielDir und GistsFilesPattern separat
#
# Für Tests in der Shell müssen wir den $MyInvocation Pfad speichern, um ihn später wieder zu haben
$Script:LibGistUseGistsPath = $MyInvocation.MyCommand.Path
### Config
$LibGistVersion_LibGist_Use_Gists_ps1 = '005'
# Erzeugt die Config für dieses Script
# $ZielDir
# Optional kann ein Zielverzeichnis definiert werden, in dem das Update / Laden durchgeführt wird
# Default: ScriptDir
Function LibGist-Get-UseGists-Cfg() {
[CmdletBinding()]
Param (
[String]$ZielDir,
[String]$GitHubUserName = 'schittli'
)
If ([String]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
$ThisLibGistUseGistsPath = $Script:LibGistUseGistsPath
} Else {
$ThisLibGistUseGistsPath = $MyInvocation.MyCommand.Path
}
$ScriptDir = [IO.Path]::GetDirectoryName($ThisLibGistUseGistsPath)
$ScriptName = [IO.Path]::GetFileName($ThisLibGistUseGistsPath)
If ([String]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
$ThisLibGistUseGistsPath = $Script:LibGistUseGistsPath
} Else {
$ThisLibGistUseGistsPath = $MyInvocation.MyCommand.Path
}
If ([String]::IsNullOrEmpty($ZielDir)) {
$ZielDir = $ScriptDir
}
$GistsUrl_ListPublicGists = "https://api.github.com/users/$GitHubUserName/gists"
$LibGistGetGist_ps1 = 'LibGist-Get-Gist.ps1'
$GistsFilesPattern = 'LibGist-*.ps1'
$ScriptNameWithoutExtension = [IO.Path]::GetFileNameWithoutExtension($ThisLibGistUseGistsPath)
$StateJsonFileName = { Join-Path $ZielDir ("{0}.json" -f $ScriptNameWithoutExtension) }
$StateJsonFileName = Invoke-Command $StateJsonFileName
$LibGistGetGist_ps1 = Join-Path $ZielDir $LibGistGetGist_ps1
Return [PSCustomObject][Ordered]@{
GistsUrl_ListPublicGists = $GistsUrl_ListPublicGists
LibGistGetGist_ps1 = $LibGistGetGist_ps1
ZielDir = $ZielDir
GistsFilesPattern = $GistsFilesPattern
GistsFilesDirAndPattern = (Join-Path $ZielDir $GistsFilesPattern)
ScriptDir = $ScriptDir
ScriptName = $ScriptName
ScriptNameWithoutExtension = $ScriptNameWithoutExtension
StateJsonFileName = $StateJsonFileName
}
}
# Ein schnelles Ping
# 220127
Function Test-Connection-Fast {
<#
.DESCRIPTION
Test-ComputerConnection sends a ping to the specified computer or IP Address specified in the ComputerName parameter. Leverages the System.Net object for ping
and measures out multiple seconds faster than Test-Connection -Count 1 -Quiet.
.PARAMETER ComputerName
The name or IP Address of the computer to ping.
.EXAMPLE
Test-ComputerConnection -ComputerName "THATPC"
Tests if THATPC is online and returns a custom object to the pipeline.
.EXAMPLE
$MachineState = Import-CSV .\computers.csv | Test-ComputerConnection -Verbose
Test each computer listed under a header of ComputerName, MachineName, CN, or Device Name in computers.csv and
and stores the results in the $MachineState variable.
.NOTES
001, 220127
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelinebyPropertyName)]
[Alias('CN', 'MachineName', 'Device Name')]
[String]$ComputerName,
[Int]$TimeoutMs = 500,
[Int]$NoOfPings = 5,
# Versucht stilldie Pings und bricht bei Erfolg ab
[Switch]$TestForSuccess,
# Maximum number of times the ICMP echo message can be forwarded before reaching its destination.
# Results in: TtlExpired
# Range is 1-255. Default is 64
[Int]$TTL = 64,
# Buffer used with this command. Default 32
[Int]$Buffersize = 32,
# Wenn true und das Paket ist für einen Router oder gateway zum Host
# grösser als die MTU: Status: PacketTooBig
[Switch]$DontFragment = $false,
[Switch]$PassThru
)
Begin {
$options = New-Object System.Net.Networkinformation.PingOptions
$options.TTL = $TTL
$options.DontFragment = $DontFragment
$buffer=([System.Text.Encoding]::ASCII).getbytes('a' * $Buffersize)
$ping = New-Object System.Net.NetworkInformation.Ping
# mind. 1 Ping
$NoOfPings = [Math]::Max($NoOfPings, 1)
$DestinationReachedOnce = $False
$ResPing = @()
}
Process {
For ($Cnt = 0; $Cnt -lt $NoOfPings; $Cnt++) {
Try {
$reply = $ping.Send($ComputerName, $TimeoutMs, $buffer, $options)
} Catch {
$ErrorMessage = $_.Exception.Message
Write-Host ($_ | Out-String)
$Res = [PSCustomObject][Ordered]@{
Message = ($_.ToString())
ComputerName = $ComputerName
Success = $False
Timeout = $True
Status = $ErrorMessage
}
}
If ($reply.status -eq 'Success') {
$Res = @{
ComputerName = $ComputerName
Success = $True
Timeout = $False
Status = $reply.status
}
} Else {
$Res = [PSCustomObject][Ordered]@{
ComputerName = $ComputerName
Success = $False
Timeout = $True
Status = $reply.status
}
}
If ($Res.Success) { $DestinationReachedOnce = $True }
If ($TestForSuccess) {
# Die Resultate sammeln
$ResPing +=$Res
# Bei Erfolg stoppen
If ($DestinationReachedOnce) {
If ($PassThru) {
Return $ResPing
} Else {
Return $True
}
}
} Else {
If ($PassThru) {
$Res
} Else {
$Res.Success
}
}
}
If ($TestForSuccess) {
If ($PassThru) {
Return $ResPing
} Else {
Return $DestinationReachedOnce
}
}
}
End{}
}
Function Test-Host-Reachable([URI]$Uri) {
Test-Connection-Fast $Uri.Host -TimeoutMs 500 -TestForSuccess -NoOfPings 3
}
# Listet die verfügbaren LibGist Files
Function LibGist-List-Files {
[CmdletBinding()]
Param (
[String]$ZielDir
)
## Config
$GistsCfg = LibGist-Get-UseGists-Cfg -ZielDir $ZielDir
# Prüfen, ob Github erreichbar ist
If (!(Test-Host-Reachable ([URI]$GistsCfg.GistsUrl_ListPublicGists))) {
Write-Host "Host nicht erreichbar: $(([URI]$GistsCfg.GistsUrl_ListPublicGists).Host)"
Return
}
## Main
$SplatArgs = @{ ListPublicGistsFiles = $True }
If ($VerbosePreference) { $SplatArgs += @{ Verbose = $True} }
$GistData = & $GistsCfg.LibGistGetGist_ps1 @SplatArgs
Return $GistData | select Description, `
@{ Name='FileNames'; Ex={ $_.Files | Select -ExpandProperty filename } }
}
# Lädt alle verfügbaren LibGist Files herunter
Function LibGist-Download-Files {
[CmdletBinding()]
Param (
[String]$ZielDir,
[String[]]$FileNames,
# Lädt zwingend alle Files wieder herunter
[Switch]$Force
)
## Config
$GistsCfg = LibGist-Get-UseGists-Cfg -ZielDir $ZielDir
# Prüfen, ob Github erreichbar ist
If (!(Test-Host-Reachable ([URI]$GistsCfg.GistsUrl_ListPublicGists))) {
Write-Host "Host nicht erreichbar: $(([URI]$GistsCfg.GistsUrl_ListPublicGists).Host)"
Return
}
## Main
$SplatArgs = @{
DownloadFile = $True
FileNames = $FileNames
ZielDir = $GistsCfg.ScriptDir
Verbose = $Force
}
Return & $GistsCfg.LibGistGetGist_ps1 @SplatArgs
}
# Aktualisiert die lokal vorhandenen LibGist- Files
# Die Aktualisierung erfolgt nur alle per Default 30 Tage (siehe .json)
# Returns $true if files were updated
Function LibGist-Update-GistFiles {
[CmdletBinding()]
[OutputType([Boolean])]
Param (
[String]$ZielDir,
# Startet das Update
[Switch]$Now,
# Lädt zwingend alle Fileswieder herunter
[Switch]$Force
)
Try {
$VerbosePreferenceBackup = $VerbosePreference
# Allenfalls Verbose aktivieren
If ($Now) { $VerbosePreference = Continue }
## Config
$GistsCfg = LibGist-Get-UseGists-Cfg -ZielDir $ZielDir
# Prüfen, ob Github erreichbar ist
If (!(Test-Host-Reachable ([URI]$GistsCfg.GistsUrl_ListPublicGists))) {
Write-Host "Host nicht erreichbar: $(([URI]$GistsCfg.GistsUrl_ListPublicGists).Host)"
Return $False
}
# Delayed expansion of variables String
# Alias: Expand-String
Function Invoke-String($str) {
$escapedString = $str -replace '"', '`"'
Invoke-Expression "Write-Output `"$escapedString`""
}
Function Load-Json($JsonFileName) {
$Json = Get-Content -LiteralPath $JsonFileName -Encoding utf8 -ErrorAction SilentlyContinue | ConvertFrom-Json
# Default initialisieren
If ($null -eq $Json) {
[PSCustomObject][Ordered]@{
LastUpdated = [DateTime]::MinValue
UpdateScheduleDays = 30
}
} Else {
# Korrektur der DateTime
Try {
If ([String]::IsNullOrWhiteSpace($Json.LastUpdated.Value)) {
[DateTime]$LastUpdated = $Json.LastUpdated
} Else {
[DateTime]$LastUpdated = $Json.LastUpdated.Value
}
} Catch {
[DateTime]$LastUpdated = [datetime]::MinValue
}
$Json.LastUpdated = $LastUpdated
$Json
}
}
Function Save-Json($Data, $JsonFileName) {
$Data | ConvertTo-Json | Out-File -LiteralPath $JsonFileName -Encoding utf8
}
## Prepare
# Das Status-File laden / initialisieren
$StateJson = Load-Json $GistsCfg.StateJsonFileName
## Main
# Müssen wir updaten?
If ((!$Now) -and ($StateJson.LastUpdated + (New-TimeSpan -Days $StateJson.UpdateScheduleDays)) -gt (Get-Date)) {
Write-Verbose "Updatezeitpunkt erst am: $($StateJson.LastUpdated + (New-TimeSpan -Days $StateJson.UpdateScheduleDays))"
Return $False
}
## Die Files aktualisieren
# Alle LibGist-* Files holen
$LocalGistLibFileNames = Get-ChildItem $GistsCfg.GistsFilesDirAndPattern | Select -ExpandProperty Name
# Allenfalls die LibGist-* Files aktualisieren
Write-Verbose 'Allenfalls die LibGist-* Files aktualisieren'
$SplatArgs = @{
DownloadFile = $True
FileNames = $LocalGistLibFileNames
ZielDir = $GistsCfg.ScriptDir
}
If ($Force) { $SplatArgs += @{ Force = $True} }
If ($VerbosePreference) { $SplatArgs += @{ Verbose = $True} }
$ResUpdate = & $GistsCfg.LibGistGetGist_ps1 @SplatArgs
# Die Config aktualisieren
$StateJson.LastUpdated = Get-Date
Save-Json $StateJson $GistsCfg.StateJsonFileName
Write-Verbose 'done.'
Return $ResUpdate
} Finally {
$VerbosePreference = $VerbosePreferenceBackup
}
}
# Bindet die LibGists in ein Script ein
Function LibGist-Load-Gists() {
[CmdletBinding()]
Param (
[String]$ZielDir
)
## Config
$GistsCfg = LibGist-Get-UseGists-Cfg -ZielDir $ZielDir
# Diese LibGists Scripts werden mit LibGist-Load-Gists nicht in andere Scripts eingebunden
$LibGistsBlacklist = @( [IO.Path]::GetFileName($GistsCfg.LibGistGetGist_ps1), `
[IO.Path]::GetFileName($GistsCfg.ScriptName) )
## Main
Get-ChildItem $GistsCfg.GistsFilesDirAndPattern | ? { $LibGistsBlacklist -notcontains $_.Name } | % {
Write-Verbose "Lade: $_.FullName"
. $_.FullName
}
## Allenfalls die geladenen Versionsinformationen anzeigen
# 'SilentlyContinue'
If ($VerbosePreference -eq 'Continue') {
Get-Variable -Name '$LibGistVersion_*' | % {
Write-Verbose ("{0}: {1}" -f $_.Name, $_.Value)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment