Snippets - PowerShell

Basic Where

Get-WindowsOptionalFeature -Online | ?{ $_.State -Like 'Enabled'} | Select FeatureName

Admin check

Run Test-IsAdmin to call the function and output true or false. I use this for logging. If you want a hard fail for lack of admin use #Requires -RunAsAdministrator

function Test-IsAdmin {
    try {
        $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
        $principal = New-Object Security.Principal.WindowsPrincipal -ArgumentList $identity
        return $principal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator )
    } catch {
        Throw "Failed to determine if the current user has elevated privileges. The error was: '{0}'." -f $_
    }
}

Start service on remote machine

Get-Service -ComputerName <machine> -Name <service> | Set-Service -Status Running

Grep

<stdout> | findstr -i <term>
Select-String -Path * -Pattern ".*STRING.*" -ErrorAction SilentlyContinue

Connect to Sharepoint online

# the name appearing in the URL of your sharepoint site before sharepoint.com
$orgName=""
# connect without using get-credential so that the modern prompt is generated allowing 2FA
Connect-SPOService -Url https://$orgName-admin.sharepoint.com

Dates

$Date = Get-Date -Format yyyy-MM-dd
$Year = Get-Date -Format yyyy
$Month = Get-Date -Format MM
$Day = Get-Date -Format dd
$Hour = Get-Date -Format HH
$Minute = Get-Date -Format mm
$Second = Get-Date -Format ss
$Time = Get-Date -Format HH-mm-ss
$TimeStamp = Get-Date -Format s | foreach {$_ -replace ":", "-"}

Remove specific index from array

$array = 1,2,3
$newArray = $array | ? { $_ -ne $array[0] }

Remove empty objects from array

$array | Where-Object {$_}

Get Fonts

[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

(New-Object System.Drawing.Text.InstalledFontCollection).Families

Check object for property

If (Get-Member -inputobject $OBJECT -name "PROPERTY" -Membertype Properties) { Write-Host 'yes' }

Counting

$i | measure -Line -Character -Word

Date manipulation

Get the date 6 months ago

$date = Get-Date
$date.AddMonths(-6)

Parameters

param (
    [Parameter(Mandatory=$True)]
    [Object]$smptTo,
    [Parameter(Mandatory=$True)]
    [Object]$messageSubject,
    [Parameter(Mandatory=$True)]
    [Object]$messageBody,
    [Parameter(Mandatory=$False)]
    [Object]$messageAttachment,
)

Replace

This uses regex

$a -replace "boring!$", "exciting!"

Replace in files

ForEach ($file in $(Get-ChildItem -Path "./*" -Recurse -Attributes !Directory)) {
    $dirty = Get-Content $file 
    $dirty -Replace 'this', 'that' | Set-Content $file
}

Splitting

$string = "a powershell $([char]0x007B) string $([char]0x007D) contains stuff"
$string.Split("{,}")

With a pipe

$rawData0 -Split "-- S.M.A.R.T"

Timers

#Create a Stopwatch
$stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch

#You can use the $stopWatch variable to see it
$stopWatch

#Go ahead and check out the methods and properties it has
$stopWatch | Get-Member
$stopwatch.Start()
$stopwatch.Elapsed
$stopwatch.Stop()
$stopwatch.Reset()

Try-Catch

try { 
    This is not allowed "This is Allowed" 
} catch { 
    Write-Host "Error occured" -BackgroundColor DarkRed 
}

Printing the error that caused the catch

Use Write-Host $_

Get word count from text files recursively

Get-ChildItem -Recurse | Select Name,@{Name='Count'; Expression={(Get-Content $_ | Measure-Object -Word).Words}}

Remove all lines after X from selection/text file

$txt = Get-Content file.txt
$to = '## Home'
$i = 0
Do { $txt[$i++] } Until ($txt[$i] -eq $to)

Simpler

$(Get-Content .\2021-09-27.md -Raw ) -replace '## Home[\s\S]+'
ForEach ($file in (Get-ChildItem -Recurse -Filter '20*.md')) { 
    $(Get-Content $file -Raw) -replace '## Home[\s\S]+' | Set-Content $file 
}

Remove all work lines form daily notes

$(Get-Content .\2022-01-06.md -Raw) -replace '# Daily[\s\S]+## Home','# Daily'
ForEach ($file in (Get-ChildItem -Recurse -Filter '*.md')) {
    $(Get-Content $file -Raw) -replace '# Daily[\s\S]+## Home','# Daily' | Set-Content $file
}

or

ForEach ($file in (Get-ChildItem -Recurse -Filter '20*.md')) { 
    $(Get-Content $file -Raw) -replace '## Home[\s\S]+' | Set-Content $file 
}

Get Directory Size

(Get-ChildItem C:\Temp\ -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB
(Get-ChildItem C:\Temp\ -Recurse | Measure-Object -Property Length -Sum).Sum / 1GB

Get directory size for every child directory

ForEach ($dir in $(Get-ChildItem -Directory)) {
    Write-Host $dir.name -ForegroundColor green
    (Get-Childitem $dir -Recurse | Measure-Object -Property Length -Sum).Sum / 1GB
}

Search for file names

Get-Childitem –Path C:\ -Include *Term* -File -Recurse -ErrorAction SilentlyContinue

Get-Childitem –Path C:\ -Include "*Term*" -Exclude "*.png","*.jpg" -File -Recurse -ErrorAction SilentlyContinue

File extensions function

[System.IO.Path]::ChangeExtension("Untitled.md",".new")

File exists

If (Test-Path $vsLayout) {
    Write-Host "Layout exists" -ForegroundColor Green
}

Wait for file to exist

While (!(Test-Path $vsLayout)){
        Write-Host "Waiting for layout creation..." -ForegroundColor Yellow
        Start-Sleep -Seconds 3
}

Prepend string to items in array

$test = $jsonConfig.components.ForEach({"--add " + $_})

Get object type

$test.GetType()

Random String

add-type -AssemblyName System.Web
[System.Web.Security.Membership]::GeneratePassword(15,2)

Compare 2 directories

Quick way to get just names

$Folder1 = Get-childitem "C:\Folder1"
$Folder2 = Get-childitem  "C:\Folder2"

$Compare-Object $Folder1 $Folder2 -Property Name

If you need to retain properties

$Folder1 = Get-childitem "C:\Folder1"
$Folder2 = Get-childitem  "C:\Folder2"

$Difference = $Folder1 | Where {$Folder2.Name -notcontains $_.Name}

Pull differences into a new directory

Copy-Item $Difference.FullName -Destination .\Difference_Directory

If file exists

If (Test-Path C:\filename) {
    Write-Warning "File exists"
}