Misc
These are parts of my personal profile.ps1 which I usually install to my Windows boxes either system wide or in my home directory.
Installation
Powershell version 5+
Systemwide installation: c:\windows\system32\windowspowershell\v1.0\profile.ps1
Per user installation: c:\users\$($env:username)\documents\WindowsPowerShell\profile.ps1
Powershell version 7+
Systemwide installation: C:\Program Files\PowerShell\7\profile.ps1
Per user installation: C:\Users\$($env:username)\Documents\PowerShell\profile.ps1
Get all locations
$PROFILE | Select-Object *
Environment
Error handling
Maybe you want to set some preferences for your error handling
$global:ErrorActionPreference = "Stop"
$global:WarningPreference = "SilentlyContinue"
$global:InformationPreference = "SilentlyContinue"
$global:VerbosePreference = "SilentlyContinue"
$global:DebugPreference = "SilentlyContinue"
$global:ProgressPreference = "SilentlyContinue"
$global:OutputEncoding = New-Object Text.Utf8Encoding -ArgumentList (,$false)
[Console]::OutputEncoding = $global:OutputEncoding
Prefer TLS1.2
On some older systems you might need to force TLS1.2 version to create connections to https locations
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Prefer Actice Directory server
If you will write funtions that work on AD you might want to force your global catalog to not run into sync issues
> $gcAD = (Get-ADDomainController -Discover -Service GlobalCatalog `
-erroraction silentlycontinue) | select -expandproperty hostname
> $gcAD = "$($gcAD):3268"
> $PSDefaultParameterValues = @{
"*-AD*:Server" = "$($gcAD)"
}
Parse SSH personal config
I like to have my $env:USERPROFILE\.ssh\config parsed
Goal is to have the system names in my config available as command to ssh directly into that system
In Linux OS you simply create Aliases while in Windows an Alias is somehow different. Here you need to create functions, as Aliases don’t take parameters or such.
So, here’s my Windows Powershell solution for that
If you have an .ssh\config file it will parse it
if([System.IO.File]::Exists("$($env:USERPROFILE)\.ssh\config")) {
cat "$($env:USERPROFILE)\.ssh\config" | select-string "^host" | % {
$h = $_ -replace "host ",""
$s = $h.split(" ")
foreach($hst in $s) {
$cmd = "ssh $hst"
if($hst -eq $null -or $hst -eq "") { continue; }
New-Item -force -Path "Function:/$hst" -Value @"
$cmd
"@ 2>&1 | out-null
}
}
}
Keep the $cmd variable at the beginning of the line!
Regular aliases
if(!(get-alias l) 2>&1 | out-null) {
new-alias l Get-ChildItem
}
if(!(get-alias epss) 2>&1 | out-null) {
new-alias epss enter-pssession
}
if(!(get-alias npss) 2>&1 | out-null) {
new-alias npss new-pssession
}
if(!(get-alias wol) 2>&1 | out-null) {
new-alias wol Invoke-WakeOnLan
}
if(!(get-alias mtr) 2>&1 | out-null) {
new-alias mtr winmtr
}
if(!(get-alias grep) 2>&1 | out-null) {
new-alias grep select-string
}
# I normaly have curl installed so I delete the default
# Windows curl alias pointing to Invoke-Webrequest
if((get-alias curl) 2>&1 | out-null) {
Remove-Item Alias:curl -erroraction silentlycontinue | out-null
}
Handy functions
Snippets
# elevate powershell
function _elevatePrompt5($user) {
if($user -and $user -ne "") {
Start-Process powershell -Credential (get-credential $user)
} else {
Start-Process powershell -Verb RunAs
}
}
function _elevatePrompt7($user) {
if($user -and $user -ne "") {
Start-Process pwsh -Credential (get-credential $user)
} else {
Start-Process pwsh -Verb RunAs
}
}
function elevatePrompt($user) {
if($PSVersionTable.PSVersion.Major -eq 7) {
_elevatePrompt7($user)
} else {
_elevatePrompt5($user)
}
}
# File/Folder exists?
function dirExists($file) {
return [System.IO.Directory]::Exists($file)
}
function fileExists($file) {
return [System.IO.File]::Exists($file)
}
function exists($file) {
# test if file or directory
if((get-item $file -erroraction silentlycontinue).PSIsContainer) { return dirExists $file }
else { return fileExists $file }
}
# get uptime
function uptime() {
(get-date) - (gcim Win32_OperatingSystem).LastBootUpTime
}
# convert date to windows epoch
function get-windowsEpoch() {
param(
[parameter(Mandatory=$false,ValueFromPipeline=$True,`
ValueFromPipelineByPropertyName=$True,Position = 0)]
[DateTime]$date
)
try {
if ($date) {
$windowsEpoch = (Get-Date $date).ToFileTime()
} else {
$windowsEpoch = (Get-Date).ToFileTime()
}
return $windowsEpoch
} catch {
return $_
}
}
# convert windows epoch to date
function convert-windowsEpoch() {
#[datetime]::FromFileTime($_.pwdLastSet)
param(
[parameter(Mandatory=$true,ValueFromPipeline=$True,`
ValueFromPipelineByPropertyName=$True,Position = 0)]
$date
)
return [datetime]::FromFileTime($date)
}
# generate random passwords
function pwgen {
# define parameters
param([int]$PasswordLength = 20)
# ASCII Character set for Password
$CharacterSet = @{
Lowercase = (97..122) | Get-Random -Count 10 | % {[char]$_}
Uppercase = (65..90) | Get-Random -Count 10 | % {[char]$_}
Numeric = (48..57) | Get-Random -Count 10 | % {[char]$_}
SpecialChar = (33..47)+(58..64)+(91..96)+(123..126) `
| Get-Random -Count 10 | % {[char]$_}
}
# Frame Random Password from given character set
$StringSet = $CharacterSet.Uppercase + $CharacterSet.Lowercase `
+ $CharacterSet.Numeric + $CharacterSet.SpecialChar
$result = (-join(Get-Random -Count $PasswordLength -InputObject $StringSet))
return $result
}
# UUIDGEN / GUIDGEN
function uuidgen() {
[guid]::NewGuid().ToString().toupper()
}
function guidgen() { uuidgen; }
Wake on LAN
function Invoke-WakeOnLan
{
param
(
# one or more MACAddresses
[Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
# mac address must be a following this regex pattern:
[ValidatePattern('^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$')]
[string[]]
$MacAddress
)
begin
{
# instantiate a UDP client:
$UDPclient = [System.Net.Sockets.UdpClient]::new()
}
process
{
foreach($_ in $MacAddress)
{
try {
$currentMacAddress = $_.toupper()
# get byte array from mac address:
$mac = $currentMacAddress -split '[:-]' |
# convert the hex number into byte:
ForEach-Object {
[System.Convert]::ToByte($_, 16)
}
#$mac = $mac.toupper()
#region compose the "magic packet"
# create a byte array with 102 bytes initialized to 255 each:
$packet = [byte[]](,0xFF * 102)
# leave the first 6 bytes untouched, and
# repeat the target mac address bytes in bytes 7 through 102:
6..101 | Foreach-Object {
# $_ is indexing in the byte array,
# $_ % 6 produces repeating indices between 0 and 5
# (modulo operator)
$packet[$_] = $mac[($_ % 6)]
}
#endregion
$IP = [System.Net.IPAddress]::Broadcast
$IP = New-Object Net.IPEndPoint $IP, 9
Write-Verbose "Connecting to $($IP.address.tostring())"
# connect to port 400 on broadcast address:
#$UDPclient.Connect($IP,9)
# send the magic packet to the broadcast address:
$null = $UDPclient.Send($packet, $packet.Length, $IP)
Write-Verbose "sent magic packet to $currentMacAddress..."
Write-Verbose "Packet:`n$($packet)"
} catch {
Write-Warning "Unable to send ${mac}: $_"
}
}
}
end
{
# release the UDP client and free its memory:
$UDPclient.Close()
$UDPclient.Dispose()
}
}
Merge-PDF
For this to work you need to install Ghostscript x64 for windows
function Merge-PDF($filepattern) {
if($gs = Get-Command gswin64c) {
& "$($gs)" -dNOPAUSE -sDEVICE=pdfwrite -dBATCH `
-sOUTPUTFILE="merged.pdf" $(ls $filepattern).fullname
} else {
write-error "You need to install Ghostscript for windows!"
return
}
}
Split file
function Split-File() {
<#
.SYNOPSIS
Splits a file into multiple parts
.DESCRIPTION
Splits a file into smaller parts. The maximum size of the part files can be specified. The number of parts required is calculated.
.EXAMPLE
Split-File -Path 'c:\test.zip' -PartSizeBytes 2.5MB
Splits the file c:\test.zip in as many parts as necessary. Each part file is no larger than 2.5MB
.EXAMPLE
Split-File -Path 'c:\test.zip' -PartSizeBytes 2.5MB -AddSelfExtractor
Splits the file c:\test.zip in as many parts as necessary. Each part file is no larger than 2.5MB
Adds a powershell script that joins the parts when run, and adds a shortcut file to
run the PowerShell extractor script on double-click, essentially adding a self-extractor
#>
param (
# Path to the file you want to split
[Parameter(Mandatory,HelpMessage='Path to the file you want to split')]
[String]
$Path,
# maximum size of file chunks (in bytes)
[int]
$PartSizeBytes = 1MB,
# when specified, add a an extractor script and link file to easily convert
# chunks back into the original file
[Switch]
$AddSelfExtractor
)
try
{
# get the path parts to construct the individual part
# file names:
$fullBaseName = [IO.Path]::GetFileName($Path)
$baseName = [IO.Path]::GetFileNameWithoutExtension($Path)
$parentFolder = [IO.Path]::GetDirectoryName($Path)
$extension = [IO.Path]::GetExtension($Path)
# get the original file size and calculate the
# number of required parts:
$originalFile = New-Object -TypeName System.IO.FileInfo `
-ArgumentList ($Path)
$totalChunks = [int]($originalFile.Length / $PartSizeBytes) + 1
$digitCount = [int][Math]::Log10($totalChunks) + 1
# read the original file and split into chunks:
$reader = [IO.File]::OpenRead($Path)
$count = 0
$buffer = New-Object -TypeName Byte[] -ArgumentList $PartSizeBytes
$moreData = $true
# read chunks until there is no more data
while($moreData)
{
# read a chunk
$bytesRead = $reader.Read($buffer, 0, $buffer.Length)
# create the filename for the chunk file
$chunkFileName = "$parentFolder\$fullBaseName.{0:D$digitCount}.part" -f $count
Write-Verbose -Message "saving to $chunkFileName..."
$output = $buffer
# did we read less than the expected bytes?
if ($bytesRead -ne $buffer.Length)
{
# yes, so there is no more data
$moreData = $false
# shrink the output array to the number of bytes
# actually read:
$output = New-Object -TypeName Byte[] -ArgumentList $bytesRead
[Array]::Copy($buffer, $output, $bytesRead)
}
# save the read bytes in a new part file
[IO.File]::WriteAllBytes($chunkFileName, $output)
# increment the part counter
++$count
}
# done, close reader
$reader.Close()
# add self-extractor
if ($AddSelfExtractor)
{
Write-Verbose -Message "Adding extractor scripts..."
# define the self-extractor powershell script:
$extractorName = "${fullBaseName}.{0:D$digitCount}.part.ps1" `
-f $count
$extractorPath = Join-Path -Path $parentFolder `
-ChildPath $extractorName
$filePath = '$PSScriptRoot\' + "$baseName$extension"
# define the self-extractor shortcut file that launches
# the powershell script on double-click:
$linkName = "Extract ${fullBaseName}.lnk"
$linkPath = Join-Path -Path $parentFolder -ChildPath $linkName
# this will be used inside the extractor script to find the
# part files via relative path:
$currentFile = '"$PSCommandPath"'
$currentFolder = '"$PSScriptRoot"'
# write the extractor script source code to file:
"
# copy the join-file source code into the extractor script:
function Join-File {
${function:Join-File}
}
# join the part files and delete the part files after joining:
Join-File -Path ""$filePath"" -Verbose -DeletePartFiles
# remove both extractor scripts:
(Join-Path -Path $currentFolder -ChildPath '$linkName') `
| Remove-Item
Remove-Item -Path $currentFile
# open the extracted file in windows explorer
explorer.exe ""/select,""""$filepath""""""
" | Set-Content -Path $extractorPath
# create a shortcut file that launches the extractor script
# when it is double-clicked:
$shell = New-Object -ComObject WScript.Shell
$scut = $shell.CreateShortcut($linkPath)
$scut.TargetPath = "powershell.exe"
$scut.Arguments = "-nop -executionpolicy bypass `
-file ""$extractorPath"""
$scut.WorkingDirectory = ""
$scut.IconLocation = "$env:windir\system32\shell32.dll,162"
$scut.Save()
}
}
catch
{
throw "Unable to split file ${Path}: $_"
}
}
if(!(get-alias splitFileBySize) 2>&1 | out-null) {
new-alias splitFileBySize Split-File
}
Or split by lines
function splitFileByLines() {
Param(
[parameter(Mandatory=$true)]
[string]$file = $null,
[parameter(Mandatory=$true)]
[int]$lines = 0,
[parameter(Mandatory=$true)]
[string]$outdir = $null
)
# check file exists
if($f = get-item $file) {
$basename = $f.basename
$ext = $f.Extension
} else {
write-error "File not found"
break;
}
# check outdir
if(!exists($outdir)) {
mkdir $outdir
}
$i=0;
get-content $f.fullname -readcount $lines -encoding UTF8 `
| % { $i++; $_ | out-file "$($outdir)\$($basename)_part$($i).$(ext)" }
}
Measure network speed
function Measure-NetworkSpeed {
param(
[Parameter(Position=0, mandatory=$false)]
[Alias('size')]
[string]$downloadsize = "100"
)
write-host ""
write-host "Usage: Measure-NetworkSpeed [-size] <100|1000|10000> (default: 100MB) [-proxy]"
write-host ""
switch($downloadsize.toupper()) {
"100M" { $downloadsize = "100"; }
"100MB" { $downloadsize = "100"; }
"1G" { $downloadsize = "1000"; }
"1GB" { $downloadsize = "1000"; }
"10G" { $downloadsize = "10000"; }
"10GB" { $downloadsize = "10000"; }
}
[int]$size = $downloadsize
$URLS = @{ "100"='https://nbg1-speed.hetzner.com/100MB.bin';
"1000"='https://nbg1-speed.hetzner.com/1GB.bin';
"10000"='https://nbg1-speed.hetzner.com/10GB.bin'
}
$URL = $URLS["$downloadsize"]
# The test file has to be a 10MB file for the math to work.
# If you want to change sizes, modify the math to match
$TestFile = $URL
$TempFile = Join-Path -Path $env:TEMP -ChildPath 'testfile.tmp'
$WebClient = New-Object Net.WebClient
#write-host "WebclientProxy: $($WebClient.proxy)"
$TimeTaken = Measure-Command { $trash = $WebClient.DownloadData($TestFile); } | Select-Object -ExpandProperty TotalSeconds
$SpeedMbps = ($size / $TimeTaken) * 8
$Message = "{0:N2} Mbit/sec" -f ($SpeedMbps)
return $Message
}
if(!(get-alias speedtest) 2>&1 | out-null) {
new-alias speedtest Measure-NetworkSpeed
}
Measure network utilization
function get-bandwidth() {
#Get-Bandwidth.ps1
# Measure the Network interface IO over a period of half a minute (0.5)
$startTime = Get-Date
$endTime = $startTime.addMinutes(0.5)
$timeSpan = new-timespan $startTime $endTime
$count = 0
$totalBandwidth = 0
$totalKbit = 0
while ($timeSpan -gt 0) {
# Get an object for the network interfaces, excluding any that are currently disabled.
$colInterfaces = Get-CimInstance -class Win32_PerfFormattedData_Tcpip_NetworkInterface
#$colInterfaces | Select-Object BytesTotalPersec, CurrentBandwidth,PacketsPersec | Where-Object {$_.PacketsPersec -gt 0}
ForEach ($interface in $colInterfaces) {
$bitsPerSec = $interface.BytesTotalPersec * 8
$totalBits = $interface.CurrentBandwidth
# Exclude Nulls (any WMI failures)
if ($totalBits -gt 0) {
$result = (( $bitsPerSec / $totalBits) * 100)
$resultPrint = "{0:N8}" -f $result
if($bitsPerSec -gt 1000000000) {
$bw = $bitsPerSec/1000/1000/1000
$bwUnit = "Gbit/s"
} elseif($bitsPerSec -gt 1000000) {
$bw = $bitsPerSec/1000/1000
$bwUnit = "Mbit/s"
} else {
$bw = $bitsPerSec/1000
$bwUnit = "Kbit/s"
}
$kbit = $($bitsPerSec/1000)
$kbitPrint = "{0:N2}" -f $($bw)
Write-Host "Bandwidth utilized:`t $resultPrint % - $($kbitPrint) $($bwUnit)"
$totalBandwidth = $totalBandwidth + $result
$totalKbit = $totalKbit + $kbit
$count++
}
}
Start-Sleep -milliseconds 100
# recalculate the remaining time
$timeSpan = new-timespan $(Get-Date) $endTime
}
"Measurements:`t`t $count"
$averageBandwidth = $totalBandwidth / $count
$value = "{0:N2}" -f $averageBandwidth
if($totalKbit -gt 1000000) {
$bw = $totalKbit/1000/1000
$bwUnit = "Gbit/s"
} elseif($totalKbit -gt 1000) {
$bw = $totalKbit/1000
$bwUnit = "Mbit/s"
} else {
$bw = $totalKbit
$bwUnit = "Kbit/s"
}
$averageKbit = $bw / $count
$averageKbitPrint = "{0:N2}" -f $averageKbit
Write-Host "Average Bandwidth utilized:`t $value % - $($averageKbitPrint) $($bwUnit)"
}
mtr like script (traceroute)
<#
.SYNOPSIS
An MTR clone for PowerShell.
Written by Tyler Applebaum.
Version 2.0
.LINK
https://gist.github.com/tylerapplebaum/dc527a3bd875f11871e2
http://www.team-cymru.org/IP-ASN-mapping.html#dns
.DESCRIPTION
Runs a traceroute to a specified target; sends ICMP packets to each hop to measure loss and latency.
Big shout out to Team Cymru for the ASN resolution.
Thanks to DrDrrae for a bugfix on PowerShell v5
.PARAMETER Target
Input must be in the form of an IP address or FQDN. Should be compatible with most TLDs.
.PARAMETER PingCycles
Specifies the number of ICMP packets to send per hop. Default is 10.
.PARAMETER DNSServer
An optional parameter to specify a different DNS server than configured on your network adapter.
.INPUTS
System.String, System.Int32
.OUTPUTS
PSObject containing the traceroute results. Also saves a file to the desktop.
.EXAMPLE
PS C:\> Get-Traceroute 8.8.4.4 -b 512
Runs a traceroute to 8.8.4.4 with 512-byte ICMP packets.
.EXAMPLE
PS C:\> Get-Traceroute amazon.com -s 75.75.75.75 -f amazon.com
Runs a traceroute to amazon.com using 75.75.75.75 as the DNS resolver and saves the output as amazon.com.txt.
#>
#Requires -version 4
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
[String]$Target,
[Parameter(ValueFromPipeline)]
[Alias("c")]
[ValidateRange(5,100)]
[int]$PingCycles = 10, #Default to 10 pings per hop; minimum of 5, maximum of 100
[Parameter(ValueFromPipeline)]
[Alias("b")]
[ValidateRange(32,1000)]
[int]$BufLen = 32, #Default to 32 bytes of data in the ICMP packet, maximum of 1000 bytes
[Parameter(ValueFromPipeline)]
[Alias("s")]
[IPAddress]$DNSServer = $Null,
[Parameter(ValueFromPipeline)]
[Alias("f")]
[String]$Filename = "Traceroute_$Target"
)
Function script:Set-Variables {
$PerTraceArr = @()
$script:ASNOwnerArr = @()
$ASNOwnerObj = New-Object PSObject
$ASNOwnerObj | Add-Member NoteProperty "ASN"("AS0")
$ASNOwnerObj | Add-Member NoteProperty "ASN Owner"("EvilCorp")
$ASNOwnerArr += $ASNOwnerObj #Add some values so the array isn't empty when first checked.
$script:i = 0
$script:x = 0
$script:z = 0
$script:WHOIS = ".origin.asn.cymru.com"
$script:ASNWHOIS = ".asn.cymru.com"
} #End Set-Variables
Function script:Set-WindowSize {
$Window = $Host.UI.RawUI
If ($Window.BufferSize.Width -lt 175 -OR $Window.WindowSize.Width -lt 175) {
$NewSize = $Window.BufferSize
$NewSize.Height = 3000
$NewSize.Width = 175
$Window.BufferSize = $NewSize
$NewSize = $Window.WindowSize
$NewSize.Height = 50
$NewSize.Width = 175
$Window.WindowSize = $NewSize
}
} #End Set-WindowSize
Function script:Get-Traceroute {
$script:TraceResults = Test-NetConnection $Target -InformationLevel Detailed -TraceRoute | Select -ExpandProperty TraceRoute
} #End Get-Traceroute
Function script:Resolve-ASN {
$HopASN = $null #Reset to null each time
$HopASNRecord = $null #Reset to null each time
If ($Hop -notlike "TimedOut" -AND $Hop -notmatch "^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*") { #Don't waste a lookup on RFC1918 IPs
$HopSplit = $Hop.Split('.')
$HopRev = $HopSplit[3] + '.' + $HopSplit[2] + '.' + $HopSplit[1] + '.' + $HopSplit[0]
$HopASNRecord = Resolve-DnsName -Server $DNSServer -Type TXT -Name $HopRev$WHOIS -ErrorAction SilentlyContinue | Select Strings
}
Else {
$HopASNRecord = $null
}
If ($HopASNRecord.Strings -AND $HopASNRecord.Strings.GetType().IsArray){ #Check for array;
$HopASN = "AS"+$HopASNRecord.Strings[0].Split('|').Trim()[0]
Write-Verbose "Object found $HopASN"
}
ElseIf ($HopASNRecord.Strings -AND $HopASNRecord.Strings.GetType().FullName -like "System.String"){ #Check for string; normal case.
$HopASN = "AS"+$HopASNRecord.Strings[0].Split('|').Trim()[0]
Write-Verbose "String found $HopASN"
}
Else {
$HopASN = "-"
}
} #End Resolve-ASN
Function script:Resolve-ASNOwner {
If ($HopASN -notlike "-") {
$IndexNo = $ASNOwnerArr.ASN.IndexOf($HopASN)
Write-Verbose "Current object: $ASNOwnerObj"
If (!($ASNOwnerArr.ASN.Contains($HopASN)) -OR ($ASNOwnerArr."ASN Owner"[$IndexNo].Contains('-'))){ #Keep "ASNOwnerArr.ASN" in double quotes so it will be treated as a string and not an object
Write-Verbose "ASN $HopASN not previously resolved; performing lookup" #Check the previous lookups before running this unnecessarily
$HopASNOwner = Resolve-DnsName -Server $DNSServer -Type TXT -Name $HopASN$ASNWHOIS -ErrorAction SilentlyContinue | Select Strings
If ($HopASNOwner.Strings -AND $HopASNOwner.Strings.GetType().IsArray){ #Check for array;
$HopASNOwner = $HopASNOwner.Strings[0].Split('|').Trim()[4].Split('-')[0]
Write-Verbose "Object found $HopASNOwner"
}
ElseIf ($HopASNRecord.Strings -AND $HopASNRecord.Strings.GetType().FullName -like "System.String"){ #Check for string; normal case.
$HopASNOwner = $HopASNOwner.Strings[0].Split('|').Trim()[4].Split('-')[0]
Write-Verbose "String found $HopASNOwner"
}
Else {
$HopASNOwner = "-"
}
$ASNOwnerObj | Add-Member NoteProperty "ASN"($HopASN) -Force
$ASNOwnerObj | Add-Member NoteProperty "ASN Owner"($HopASNOwner) -Force
$ASNOwnerArr += $ASNOwnerObj #Add our new value to the cache
}
Else { #We get to use a cached entry and save Team Cymru some lookups
Write-Verbose "ASN Owner found in cache"
$HopASNOwner = $ASNOwnerArr[$IndexNo]."ASN Owner"
}
}
Else {
$HopASNOwner = "-"
Write-Verbose "ASN Owner lookup not performed - RFC1918 IP found or hop TimedOut"
}
} #End Resolve-ASNOwner
Function script:Resolve-DNS {
$HopNameArr = $null
$script:HopName = New-Object psobject
If ($Hop -notlike "TimedOut" -and $Hop -notlike "0.0.0.0") {
$z++ #Increment the count for the progress bar
$script:HopNameArr = Resolve-DnsName -Server $DNSServer -Type PTR $Hop -ErrorAction SilentlyContinue | Select NameHost
Write-Verbose "Hop = $Hop"
If ($HopNameArr.NameHost -AND $HopNameArr.NameHost.GetType().IsArray) { #Check for array first; sometimes resolvers are stupid and return NS records with the PTR in an array.
$script:HopName | Add-Member -MemberType NoteProperty -Name NameHost -Value $HopNameArr.NameHost[0] #If Resolve-DNS brings back an array containing NS records, select just the PTR
Write-Verbose "Object found $HopName"
}
ElseIf ($HopNameArr.NameHost -AND $HopNameArr.NameHost.GetType().FullName -like "System.String") { #Normal case. One PTR record. Will break up an array of multiple PTRs separated with a comma.
$script:HopName | Add-Member -MemberType NoteProperty -Name NameHost -Value $HopNameArr.NameHost.Split(',')[0].Trim() #In the case of multiple PTRs select the first one
Write-Verbose "String found $HopName"
}
ElseIf ($HopNameArr.NameHost -like $null) { #Check for null last because when an array is returned with PTR and NS records, it contains null values.
$script:HopName | Add-Member -MemberType NoteProperty -Name NameHost -Value $Hop #If there's no PTR record, set name equal to IP
Write-Verbose "HopNameArr apparently empty for $HopName"
}
Write-Progress -Activity "Resolving PTR Record" -Status "Looking up $Hop, Hop #$z of $($TraceResults.length)" -PercentComplete ($z / $($TraceResults.length)*100)
}
Else {
$z++
$script:HopName | Add-Member -MemberType NoteProperty -Name NameHost -Value $Hop #If the hop times out, set name equal to TimedOut
Write-Verbose "Hop = $Hop"
}
} #End Resolve-DNS
Function script:Get-PerHopRTT {
$PerHopRTTArr = @() #Store all RTT values per hop
$SAPSObj = $null #Clear the array each cycle
$SendICMP = New-Object System.Net.NetworkInformation.Ping
$i++ #Advance the count
$x = 0 #Reset x for the next hop count. X tracks packet loss percentage.
$BufferData = "a" * $BufLen #Send the UTF-8 letter "a"
$ByteArr = [Text.Encoding]::UTF8.GetBytes($BufferData)
If ($Hop -notlike "TimedOut" -and $Hop -notlike "0.0.0.0") { #Normal case, attempt to ping hop
For ($y = 1; $y -le $PingCycles; $y++){
$HopResults = $SendICMP.Send($Hop,1000,$ByteArr) #Send the packet with a 1 second timeout
$HopRTT = $HopResults.RoundtripTime
$PerHopRTTArr += $HopRTT #Add RTT to HopRTT array
If ($HopRTT -eq 0) {
$x = $x + 1
}
Write-Progress -Activity "Testing Packet Loss to Hop #$z of $($TraceResults.length)" -Status "Sending ICMP Packet $y of $PingCycles to $Hop - Result: $HopRTT ms" -PercentComplete ($y / $PingCycles*100)
} #End for loop
$PerHopRTTArr = $PerHopRTTArr | Where-Object {$_ -gt 0} #Remove zeros from the array
$HopRTTMin = "{0:N0}" -f ($PerHopRTTArr | Measure-Object -Minimum).Minimum
$HopRTTMax = "{0:N0}" -f ($PerHopRTTArr | Measure-Object -Maximum).Maximum
$HopRTTAvg = "{0:N0}" -f ($PerHopRTTArr | Measure-Object -Average).Average
$HopLoss = "{0:N1}" -f (($x / $PingCycles) * 100) + "`%"
$HopText = [string]$HopRTT + "ms"
If ($HopLoss -like "*100*") { #100% loss, but name resolves
$HopResults = $null
$HopRTT = $null
$HopText = $null
$HopRTTAvg = "-"
$HopRTTMin = "-"
$HopRTTMax = "-"
}
} #End main ping loop
Else { #Hop TimedOut - no ping attempted
$HopResults = $null
$HopRTT = $null
$HopText = $null
$HopLoss = "100.0%"
$HopRTTAvg = "-"
$HopRTTMin = "-"
$HopRTTMax = "-"
} #End TimedOut condition
$script:SAPSObj = [PSCustomObject]@{
"Hop" = $i
"Hop Name" = $HopName.NameHost
"ASN" = $HopASN
"ASN Owner" = $HopASNOwner
"`% Loss" = $HopLoss
"Hop IP" = $Hop
"Avg RTT" = $HopRTTAvg
"Min RTT" = $HopRTTMin
"Max RTT" = $HopRTTMax
}
$PerTraceArr += $SAPSObj #Add the object to the array
} #End Get-PerHopRTT
. Set-Variables
. Set-WindowSize
. Get-Traceroute
ForEach ($Hop in $TraceResults) {
. Resolve-ASN
. Resolve-ASNOwner
. Resolve-DNS
. Get-PerHopRTT
}
$PerTraceArr | Format-Table -Autosize
$PerTraceArr | Format-Table -Autosize | Out-File -Append $env:UserProfile\Desktop\$Filename.txt -encoding UTF8
Format-FileSize
function Format-FileSize([int64] $size) {
if ($size -lt 1024)
{
return "{0:0.0} b" -f $size
}
if ($size -lt 1Mb)
{
return "{0:0.0} Kb" -f ($size/1Kb)
}
if ($size -lt 1Gb)
{
return "{0:0.0} Mb" -f ($size/1Mb)
}
if ($size -lt 1Tb)
{
return "{0:0.0} Gb" -f ($size/1Gb)
}
return "{0:0.0} Tb" -f ($size/1Tb)
}
du (clone)
function du {
param(
[parameter(Mandatory=$false,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True,Position=0)]
[System.String]
$Path=".",
[Alias('h')]
[switch]
$humanreadable,
[Alias('sort')]
[switch]
$SortBySize,
[Alias('s')]
[switch]
$Summary
)
$path = (get-item "$Path").FullName
$groupedList = Get-ChildItem -Recurse -File $Path |
Group-Object directoryName |
select name,@{name='length'; expression={($_.group | Measure-Object -sum length).sum } }
$results = ($groupedList | % {
$dn = $_
if ($summary -and ($path -ne $dn.name)) {
return
}
$size = ($groupedList | where { $_.name -like "$($dn.name)*" } | Measure-Object -Sum length).sum
$fsize = ""
if($humanreadable) { $fsize = Format-FileSize($size); }
else { $fsize = "{0:0.0} b" -f $size }
New-Object psobject -Property @{
Directory=$dn.name;
Size=$fsize;
Bytes=$size`
}
})
if ($SortBySize)
{ $results = $results | sort-object -property Bytes }
return $results
}
Get-MsiProductCode
function getMsiProductCode() {
<#PSScriptInfo
.VERSION
1.0
.GUID
01281c47-25e2-4245-a1c0-b70e27acbe21
.AUTHOR
Thomas J. Malkewitz @dotsp1
#>
<#
.SYNOPSIS
Gets the product code from a Windows Installer Database.
.DESCRIPTION
Opens a Windows Installer Database (.msi) and querys for the product code.
.INPUTS
System.String.
.OUTPUTS
System.Guid.
.EXAMPLE
PS C:\> Get-MsiProductCode -Path C:\my.msi
.LINK
http://dotps1.github.io
#>
#[OutputType(
# [Guid]
#)]
Param (
[Parameter(
Mandatory = $true,
ValueFromPipeLine = $true
)]
[ValidateScript({
if ($_.EndsWith('.msi')) {
$true
} else {
throw "$_ must be an '*.msi' file."
}
})]
[String[]]
$Path
)
$ret = @()
foreach ($item in $Path) {
#$item = $Path
try {
$windowsInstaller = New-Object -com WindowsInstaller.Installer
$database = $windowsInstaller.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $null, $windowsInstaller, @((Get-Item -Path $item).FullName, 0))
$view = $database.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $database, ("SELECT Value FROM Property WHERE Property = 'ProductCode'"))
$view.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $view, $null)
$record = $view.GetType().InvokeMember('Fetch', 'InvokeMethod', $null, $view, $null)
#Write-Output -InputObject $($record.GetType().InvokeMember('StringData', 'GetProperty', $null, $record, 1))
$ret += $($record.GetType().InvokeMember('StringData', 'GetProperty', $null, $record, 1))
$view.GetType().InvokeMember('Close', 'InvokeMethod', $null, $view, $null)
[Void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($windowsInstaller)
} catch {
Write-Error -Message $_.ToString()
break
}
}
[String[]]$ret = $ret | ? { $_ -ne $null }
return $ret
}
Folder diff
This function compares the content of 2 folders.
By default it checks for the existence of files. That means, a file that exists in both folders is considered as equal, regardless of its content. To determine changes in files you may specify -s|-size so, the file size of both files is compared. Or you can use -w|-writetime to compare the last write time of both files.
This function below also uses 3 functions from the ‘Snippets’ section above:
exists(), fileExists() and dirExists()
So, if you want to use this one, also copy the *exists() functions from the ‘Snippets’ section.
function diffFolders() {
param(
[Parameter(ParameterSetName="one", Mandatory = $true, Position = 0)]
[String]$folder1,
[Parameter(ParameterSetName="one", Mandatory = $false, Position = 1)]
[String]$folder2=$pwd,
[Parameter(ParameterSetName="one", Mandatory = $false)]
[Alias('s')]
[Switch]$size,
[Parameter(ParameterSetName="one", Mandatory = $false)]
[Alias('w')]
[Switch]$writetime,
[Parameter(ParameterSetName="two", Mandatory = $false)]
[Alias('h')]
[Switch]$help
)
# RelativePath is always checked!
$property = @("RelativePath")
if($help) {
write-host ""
write-host "Usage: diffFolders [-s|-size] [-w|-writetime] [-h|-help] [-folder1] FOLDER1 [-folder2] FOLDER2"
write-host ""
write-host "`tFOLDER1`t`tFirst folder to be compared (mandatory)"
write-host "`tFOLDER2`t`tOptional second folder. If not given the current working directory (`$pwd) will be used."
write-host "`t-s|-size`tCheck the filesize."
write-host "`t-w|-writetime`tCheck the last WriteTime of file."
write-host "`t-h|-help`tPrint this help and exit."
write-host ""
break;
}
if($size) {
# check for filesize also not only existance of files
$property_add = "Length";
$property += $property_add
}
if($writetime) {
$property_add = "LastWriteTime";
$property += $property_add
}
write-host ""
if(exists $folder1) {
$f1 = gci -File -recurse "$folder1" #-erroraction silentlycontinue
} else {
write-host "Does not exist: $folder1"
break;
}
if(exists $folder2) {
$f2 = gci -File -recurse "$folder2" #-erroraction silentlycontinue
} else {
write-host "Does not exist: $folder2"
break;
}
write-host ""
write-host "Comparing folders $folder1 against $folder2"
write-host "Using relative path for for comparison."
if(!$size -and !$writetime) {
write-warning "Only existence of files is checked! See -help for more options"
}
write-host ""
write-host "Adding RelativePath property."
$f1 | Add-Member -MemberType ScriptProperty -Name "RelativePath" -Value {$this.FullName -replace [Regex]::Escape("$folder1"),""}
$f2 | Add-Member -MemberType ScriptProperty -Name "RelativePath" -Value {$this.FullName -replace [Regex]::Escape("$folder2"),""}
write-host ""
write-host "Trying to compare"
$diff = Compare-Object $f1 $f2 -Property $($property) #-PassThru
write-host ""
write-host "Adding Winner property"
#$script = { if($this.SideIndicator -eq "<=") { echo $folder1 } else { echo $folder2 } }
$diff | ? {$_.SideIndicator -eq "<="} | Add-Member -MemberType NoteProperty -name "Winner" -value "$folder1"
$diff | ? {$_.SideIndicator -eq "=>"} | Add-Member -MemberType NoteProperty -name "Winner" -value "$folder2"
return $diff
}
Get Reboot Reason
As this shit does not come outa my ass and I don’t need to do this remotely I commented out the Network Credential stuff. So this might not work if you specify something different than ‘localhost’.
function Get-RestartInfo
{
<#
.Synopsis
Returns reboot / restart event log info for specified computer
.DESCRIPTION
Queries the system event log and returns all log entries related to reboot & shutdown events (event ID 1074)
.Parameter ComputerName
Specifies a computer to add the users to. Multiple computers can be specified with commas and single quotes
(-Computer 'Server01','Server02')
.PARAMETER Credential
Specifies the user you would like to run this function as
.EXAMPLE
Get-RestartInfo
This command will return all the shutdown/restart eventlog info for the local computer.
PS C:\Scripts\> Get-RestartInfo
Computer : localhost
Date : 1/7/2019 5:16:50 PM
Action : shutdown
Reason : No title for this reason could be found
User : NWTRADERS.MSFT\Tom_Brady
Process : C:\WINDOWS\system32\shutdown.exe (CRDNAB-PC06LY52)
Comment :
Computer : localhost
Date : 1/4/2019 5:36:58 PM
Action : shutdown
Reason : No title for this reason could be found
User : NWTRADERS.MSFT\Tom_Brady
Process : C:\WINDOWS\system32\shutdown.exe (CRDNAB-PC06LY52)
Comment :
Computer : localhost
Date : 1/4/2019 9:10:11 AM
Action : restart
Reason : Operating System: Upgrade (Planned)
User : NT AUTHORITY\SYSTEM
Process : C:\WINDOWS\servicing\TrustedInstaller.exe (CRDNAB-PC06LY52)
Comment :
.EXAMPLE
Get-RestartInfo SERVER01 | select-object Computer, Date, Action, Reason, User
This command will return all the shutdown/restart eventlog info for server named SERVER01
PS C:\Scripts\> Get-RestartInfo SERVER01 | Format-Table -AutoSize
Computer Date Action Reason User
-------- ---- ------ ------ ----
SERVER01 12/15/2018 6:21:45 AM restart No title for this reason could be found NT AUTHORITY\SYSTEM
SERVER01 11/17/2018 6:57:53 AM restart No title for this reason could be found NT AUTHORITY\SYSTEM
SERVER01 9/29/2018 6:47:50 AM restart No title for this reason could be found NT AUTHORITY\SYSTEM
.NOTES
NAME: Get-RestartInfo
AUTHOR: Mike Kanakos
CREATED: 2016-09-27
LASTEDIT: 2019-12-17
MISC: Function based on script found at:
https://social.technet.microsoft.com/wiki/contents/articles/17889.powershell-script-for-shutdownreboot-events-tracker.aspx
CREDIT: Biswajit Biswas
.Link
https://github.com/compwiz32/PowerShell
#>
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]
[alias("Name","MachineName","Computer")]
[string[]]
$ComputerName = 'localhost'
<#
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
#$Credential = [System.Management.Automation.PSCredential]::Empty
#>
)
Begin { }
Process {
Foreach($Computer in $ComputerName){
$Connection = Test-Connection $Computer -Quiet -Count 2
If(!$Connection) {
Write-Warning "Computer: $Computer appears to be offline!"
} #end If
Else {
Get-WinEvent -ComputerName $computer -FilterHashtable @{logname = 'System'; id = 1074,6005,6006,6008} |
ForEach-Object {
$EventData = New-Object PSObject | Select-Object Date, EventID, User, Action, Reason, ReasonCode, Comment, Computer, Message, Process
$EventData.Date = $_.TimeCreated
$EventData.User = $_.Properties[6].Value
$EventData.Process = $_.Properties[0].Value
$EventData.Action = $_.Properties[4].Value
$EventData.Reason = $_.Properties[2].Value
$EventData.ReasonCode = $_.Properties[3].Value
$EventData.Comment = $_.Properties[5].Value
$EventData.Computer = $Computer
$EventData.EventID = $_.id
$EventData.Message = $_.Message
$EventData | Select-Object Date, Computer, EventID, Action, User, Reason, Message
}
} #end Else
} #end Foreach Computer Loop
} #end Process block
} #end of Function
if(!(get-alias getRebootReason) 2>&1 | out-null) {
new-alias getRebootReason Get-RestartInfo
}
Get Pending Reboot
function getPendingReboot() {
###############################################################################
# Check-PendingReboot.ps1
# Andres Bohren / www.icewolf.ch / blog.icewolf.ch / a.bohren@icewolf.ch
# Version 1.0 / 03.06.202020 - Initial Version
###############################################################################
<#
.SYNOPSIS
This Script checks diffrent Registry Keys and Values do determine if a Reboot is pending.
.DESCRIPTION
I found this Table on the Internet and decided to Write a Powershell Script to check if a Reboot is pending.
Not all Keys are checked. But feel free to extend the Script.
https://adamtheautomator.com/pending-reboot-registry-windows/
KEY VALUE CONDITION
HKLM:\SOFTWARE\Microsoft\Updates UpdateExeVolatile Value is anything other than 0
HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager PendingFileRenameOperations value exists
HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager PendingFileRenameOperations2 value exists
HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired NA key exists
HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Services\Pending NA Any GUID subkeys exist
HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\PostRebootReporting NA key exists
HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce DVDRebootSignal value exists
HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending NA key exists
HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress NA key exists
HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending NA key exists
HKLM:\SOFTWARE\Microsoft\ServerManager\CurrentRebootAttempts NA key exists
HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon JoinDomain value exists
HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon AvoidSpnSet value exists
HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName ComputerName Value ComputerName in HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName is different
.EXAMPLE
./Check-PendingReboot.ps1
#>
function Test-RegistryValue {
param (
[parameter(Mandatory=$true)][ValidateNotNullOrEmpty()]$Path,
[parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()]$Value
)
try {
Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null
return $true
}
catch {
return $false
}
}
[bool]$PendingReboot = $false
#Check for Keys
If ((Test-Path -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") -eq $true)
{
$PendingReboot = $true
}
If ((Test-Path -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\PostRebootReporting") -eq $true)
{
$PendingReboot = $true
}
If ((Test-Path -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") -eq $true)
{
$PendingReboot = $true
}
If ((Test-Path -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") -eq $true)
{
$PendingReboot = $true
}
If ((Test-Path -Path "HKLM:\SOFTWARE\Microsoft\ServerManager\CurrentRebootAttempts") -eq $true)
{
$PendingReboot = $true
}
#Check for Values
If ((Test-RegistryValue -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing" -Value "RebootInProgress") -eq $true)
{
$PendingReboot = $true
}
If ((Test-RegistryValue -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing" -Value "PackagesPending") -eq $true)
{
$PendingReboot = $true
}
If ((Test-RegistryValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Value "PendingFileRenameOperations") -eq $true)
{
$PendingReboot = $true
}
If ((Test-RegistryValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Value "PendingFileRenameOperations2") -eq $true)
{
$PendingReboot = $true
}
If ((Test-RegistryValue -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" -Value "DVDRebootSignal") -eq $true)
{
$PendingReboot = $true
}
If ((Test-RegistryValue -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon" -Value "JoinDomain") -eq $true)
{
$PendingReboot = $true
}
If ((Test-RegistryValue -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon" -Value "AvoidSpnSet") -eq $true)
{
$PendingReboot = $true
}
Write-Host "Reboot pending: $PendingReboot"
}