Skip to main content

PowerShell Cheatsheet

Windows Devices

Forcing a Device Sync\Check-In with Intune

Run these as a user:

Both of the below are the same as opening the Company Portal and clicking either Sync in Settings or Check Now under Devices.

  • Sync Application and Policy: intunemanagementextension://syncapp
  • Sync Compliance Settings: intunemanagementextension://synccompliance

Run these as an Administrator:

This will trigger a device Check-In using the scheduled task that is created during Enrollment. It does seem to Sync all settings (Apps, Config Policies and Compliance Policies).

Get-ScheduledTask -TaskName "Schedule #3 created by enrollment client" | Start-ScheduledTask

Find Strings in the IME Logs

warning

Cannot handle carraige returns

gc C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\intuneManagement*.log | `
Select-String -Pattern "retryCount:" | % {
if ($_ -match '<!\[LOG\[(?<Message>.*?)\]LOG\]!><time="(?<Time>[\d:.]+)" date="(?<Date>\d{1,2}-\d{1,2}-\d{4})"(?<Misc>.*?)>') {
[PSCustomObject]@{
Date = $matches.Date
Time = $matches.Time
Message = $matches.Message.Trim()
Misc = $matches.Misc.Trim()
}
}
else {
[PSCustomObject]@{ RawLog = $_ }
}
}

Create Scheduled Task

$scheduledTaskName = "Task Name"
$scheduledTaskFolder = "Folder Name"
$action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument '-WindowStyle hidden -command "& C:\temp\script.ps1"'
$trigger = New-ScheduledTaskTrigger -AtLogon
$principal = New-ScheduledTaskPrincipal -GroupId "Users"
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit (New-TimeSpan -Minutes 5) -Hidden
$task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger -Settings $settings

try {
Register-ScheduledTask -TaskName $scheduledTaskName -InputObject $task -TaskPath $scheduledTaskFolder
}
catch {
WriteToLogFile "Unable to register task."
}

Find Expiring Certificates

# Find all Certificates on a device
Get-ChildItem -Path Cert: -Recurse -ExpiringInDays 10 | select thumbprint, notafter | sort notafter

# Find a Cert via Thumbprint
gci -Path Cert: -Recurse | ? thumbprint -match thumbprint | fl

Detect logged in user Account

(Get-Childitem -path "C:\Users\$((Get-Process -IncludeUserName -Name explorer | Select-Object UserName -Unique).username.split('\')[1])" | where-object Name -Match 'OneDrive -').FullName

Enable TLS 1.2 for session

Required on older servers when trying to install from nuget.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Check Process Resource Usage

# Array of strings into the search for the process
"Firefox","msi" | % {
$string = $_
gcim win32_Process | ? { $_.name -match $string -or $_.commandline -match $string } | `
Select name, creationdate, commandline
}

# Kill the process like so
gcim win32_process | ? name -match "msi" | ForEach-Object { Stop-Process -Id $_.ProcessId }
# This gets a single service\process
(gcim Win32_Service -Filter "Name='Zoho Assist-Unattended Support'").ProcessId | % {
Get-Process -Id $_ | `
select id, name, StartTime, `
@{n="CPU(Seconds)";e={$_.CPU}},
@{n="RAM(MB)";e={($_.WorkingSet64 / 1MB)}}, `
@{n="PageFile(MB)";e={($_.PagedMemorySize64 / 1MB)}}, `
@{n="Handles";e={$_.HandleCount}}, `
@{n="Threads";e={$_.Threads.Count}}, `
@{n="VM Size (MB)";e={($_.VirtualMemorySize64 / 1MB)}}, `
@{n="Nonpaged Pool (MB)";e={($_.NonpagedSystemMemorySize64 / 1MB)}}, `
@{n="Paged Pool (MB)";e={($_.PagedSystemMemorySize64 / 1MB)}}, `
ExitCode, ExitTime
} | ft -a

Get Win Event Logs

$logNames = @(
'Application',
'System',
'Microsoft-Windows-Windows Defender/Operational'
)
$properties = @(
'LogName',
'timeCreated',
'id',
'leveldisplayname',
'message'
)
Get-WinEvent -LogName $logNames -MaxEvents 10 | Select-Object $properties | Where-Object Message -like "*Defender*" | Format-List

<# Another example which runs a bit quicker #>

Get-WinEvent -FilterHashTable @{ LogName = 'System' ; id = 107 ; StartTime = (get-date).AddDays(-1) }

<# Useful Event IDs
12 The operating system started at system time
13 The operating system is shutting down at system time.
20 The last shutdown's success status was true. The last boot's success status was true.
42 The sytem is entering sleep.
107 The system has returned from sleep.
109 The kernel power manager has initiated a shutdown transition.
1074 The process Explorer.EXE has initiated the shutdown of computer on behalf of user for the following reason
6005 The Event log service was started.
6006 The Event log service was stopped.
6013 The system uptime is 10 seconds.
#>

Find Uninstall String from Registry

tip

Pipe the below into Format-Table -Autosize

"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*","HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" | % {
Get-ItemProperty $_ | % {
$app = $_
[PSCustomObject]@{
Name = $app.displayname
Version = $app.DisplayVersion
InstallDate = if($app.InstallDate){[datetime]::ParseExact($app.InstallDate, "yyyyMMdd", $null)} else {$app.InstallDate}
UninstallString = $app.UninstallString
MSIExecCommand = if($app.UninstallString -match "MsiExec.exe") {"MSIExec.exe " + ($app.UninstallString -replace '/I|/X', '/x ' -replace "MsiExec.exe","") + " /NORESTART"} else {"N\A"}
Path = $app.PSPath -replace "Microsoft.PowerShell.Core\\Registry::",""
}
}
}

Setting Windows Desktop background

# Detection script for the Background
if (Test-Path "Path\to\local\file"){
Write-Output "File already exists"
Exit 0
} else {
write-output "File does not exist"
Exit 1
}

# Remediation script for the Background
$Data = @{
url = "Blob Storage URL\to\File.png" # Change to your fitting
DownloadDirectory = "C:\Path\to\output\directory"
RegKeyPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP' # Assigns the wallpaper
StatusValue = "1"
}

# Creates the destination folder on the target computer
New-Item -ItemType Directory -Path $Data.DownloadDirectory -ErrorAction SilentlyContinue

# Downloads the image file from the source location
Invoke-WebRequest -Uri $Data.url -OutFile $Data.DownloadDirectory\$data.DownloadDirectory\$(($data.url -split "/")[-1]

# Creates the registry key and sets the values
New-Item -Path $Data.RegKeyPath -Force
New-ItemProperty -Path $Data.RegKeyPath -Name 'DesktopImageStatus' -Value $Data.Statusvalue -PropertyType DWORD -Force
New-ItemProperty -Path $Data.RegKeyPath -Name 'LockScreenImageStatus' -Value $Data.Statusvalue -PropertyType DWORD -Force
New-ItemProperty -Path $Data.RegKeyPath -Name 'DesktopImagePath' -Value "$($data.DownloadDirectory)\$(($data.url -split "/")[-1])" -PropertyType STRING -Force
New-ItemProperty -Path $Data.RegKeyPath -Name 'DesktopImageUrl' -Value "$($data.DownloadDirectory)\$(($data.url -split "/")[-1])" -PropertyType STRING -Force

Windows Server

Get Kerberos Events

# Get the event logs with relevant IDs
$events = Get-WinEvent -FilterHashTable @{ LogName = 'security' ; id = 4768,4769,4770,4771,4772,4773 ; StartTime = (get-date).Addhours(-8) }
# Filtering options
$events | ? message -Match 'Filter'| ft -AutoSize -wrap # -wrap stops truncating output.
# Get events matching a userID with the matching error code\event "success".
$events | ? {( $_.message -Match 'userID') -and ( $_.message -Match '0x0') -and ($_.Id -Match '4768' ) } | ft -AutoSize -Wrap
# Search for messages with a userID in it.
$events | ? message -Match 'userID'| ft -AutoSize -wrap

# Search multiple machines.
$listOfDevices = 'server1','server2'
$kerberosEvents = foreach ($device in $listOfDevices) {

Write-Host "Getting logs from $($device)." -ForegroundColor Yellow
Get-WinEvent -ComputerName $device -FilterHashTable @{ LogName = 'security' ; id = 4768,4769,4770,4771,4772,4773 ; StartTime = (get-date).AddMinutes(-30) }
Write-Host "Log collection from $($device) successfull logs." -ForegroundColor Green

}

Get FISMO Roles

Get-ADForest | `
Select SchemaMaster,DomainNamingMaster,`
@{ n='pdcemulator';e={ Get-ADDomain | Select -ExpandProperty pdcemulator} }, `
@{ n='ridmaster';e={ Get-ADDomain | Select -ExpandProperty ridmaster} }, `
@{ n='infrastructuremaster';e={ Get-ADDomain | Select -ExpandProperty infrastructuremaster} } | `
Format-List

Get SMB Session Data

# Get the open file sessions.
$var_filesessions = Get-SmbOpenFile
$var_getDate = Get-Date

# Get the relevant info from the SMB command and insert the date\time of when it ran.
$var_opensmbsessions = $var_filesessions | Select @{ l='DateTime';e={ $var_getDate }}, ClientComputerName, clientusername, path

Cloud User Management

Check for and set Locale and Region Information

# Takes ages to run for some reason.
# Maybe faster putting mailboxes into a variable first.
Get-Maibox | % {
$mailbox = $_
Write-Host "Working on $mailbox.userprincipalname" -ForegroundColor Yellow
$mailboxConfig = Get-MailboxRegionalConfiguration -Identity $mailbox.UserPrincipalName
[PSCustomObject]@{
UserPrincipalName = if ($null -eq $mailbox.UserPrincipalName) { "Null" } else { $mailbox.UserPrincipalName }
DateFormat = if ($null -eq $mailboxConfig.DateFormat) { "Null" } else { $mailboxConfig.DateFormat }
Language = if ($null -eq $mailboxConfig.Language) { "Null" } else { $mailboxConfig.Language }
TimeFormat = if ($null -eq $mailboxConfig.TimeFormat) { "Null" } else { $mailboxConfig.TimeFormat }
TimeZone = if ($null -eq $mailboxConfig.TimeZone) { "Null" } else { $mailboxConfig.TimeZone }
}
} | ft -a
# Connect to MG-Graph and Exchange Online First
'UPN' | % {
Write-Host "Working on, $_..."
Update-MgUser -userId $_ -PreferredLanguage en-GB
Update-MgUser -userId $_ -UsageLocation GB
Set-MailboxRegionalConfiguration -UserId $_ -Language en-GB -DateFormat "dd/MM/yyyy" -TimeFormat "HH:mm" -TimeZone "GMT Standard Time"
Set-MailboxCalendarConfiguration -Identity $_ -WorkingHoursTimeZone "GMT Standard Time"
}

Misc

Convert Unix Time Function

Function Convert-FromUnixDate ($UnixDate) {
[timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($UnixDate))
}

Searching between two Strings

[CmdletBinding()]
param (
[Parameter()]
[array]
$logData = $proxylogs
)

# Initialize an array to store the extracted logs
$extractedLogs = @()

# Define start and end patterns
$startPattern = "Activating Job:" # Starting pattern
$endPattern = "Job Completed:" # Ending pattern

# Initialize capturing flag
$capturing = $false

# Loop through each line in the log data array
foreach ($line in $logData) {
# Start capturing after finding the "Activating Job:" pattern
if ($line -match $startPattern) {
$capturing = $true
}

# If capturing is true, add the current line to the extracted logs
if ($capturing) {
$extractedLogs += $line
}

# Stop capturing after finding the "Job Completed:" pattern
if ($line -match $endPattern -and $capturing) {
$capturing = $false
}
}

# Output the extracted logs
$extractedLogs

Removing strings from text files

$LinesToremove = @(
"String 1",
"String 2"
)

foreach ($string in $LinesToremove){
(select-string -Path $hostsFilePath -Pattern $string -NotMatch ).line | Set-Content $hostsFilePath
Start-Sleep -Milliseconds 100
}

Progress Bar Snippet

$count = 0
ForEach ($item in $output) {
Write-Progress -PercentComplete ($count/$output.Count*100) -Status "Processing Items" -Activity "Checking $count of $($output.Count) for Registered User."
# Your actual script logic here
Start-Sleep -Milliseconds 50
$count++
}

Write-Progress -Activity "Checking count of $(output.Count) for Registered User." -Completed

## Inline version
$count = 0
ForEach ($item in $output) {
$count++
Write-Host "`rWorking on user $count of $($allM365Users.Count) in total" -NoNewline -ForegroundColor Cyan
# Your actual script logic here
}

Download Timer


$stopwatch = [System.Diagnostics.Stopwatch]::new()

$stopwatch.Start()
$startBitsTransferSplat = @{
Source = 'https://www.contoso.com/Files/BitsDefinition.txt'
Destination = 'C:\BitsDefinition.txt'

Start-BitsTransfer @startBitsTransferSplat
$stopwatch.Stop()

Write-Output $stopwatch.Elapsed

Enable Remote Mailbox from Exchange

# Create account in On-prem AD or Exchange first as normal mailbox.
# Run the command below.
Enable-RemoteMailbox "Friendly Name" -RemoteRoutingAddress SMTPAddress@domain.mail.onmicrosoft.com
# Run an AAD Sync to push the settings.

Encrypt Credentials using Credential Manager

#     Add password to Credential Manager.     #
# String to be secured in Credential Manager
$unsecureString = 'Password123'
# Install the module.
Install-Module -Name CredentialManager
# Create the new Credential in Credentials Manager.
New-StoredCredential -Target 'Target Name' -UserName 'Username' -Password $unsecureString -Type Generic -Persist LocalMachine

# Retrieve password from Credential Manager. #
# Get the password secure string.
$cred = (Get-StoredCredential -Target 'Target Name' -Type Generic).Password
# Marshall is a .NET class: Allocates an unmanaged binary string (BSTR) and copies the contents of a managed SecureString object into it.
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($cred)
# Allocates a managed String and copies all characters up to the first null character from a string stored in unmanaged memory into it.
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

Reinstate Partner Access to Azure Sub

Install-Module -Name Az.Resources -Force -Verbose
Import-Module -Name Az.Resources -Verbose -MinimumVersion 4.1.1
Connect-AzAccount -Tenant <customer tenant>
Set-AzContext -SubscriptionId <customer subscriptions>
New-AzRoleAssignment -ObjectId <principal ID> -RoleDefinitionName "Owner" -Scope "/subscriptions/<customer subscription>" -ObjectType "ForeignGroup"

File Report

########################## Basic File report for the directory you're currently in. ##########################
Get-ChildItem | Select FullName,@{l='Size(GB)';e={ [math]::round($_.length/1024,2) } }, CreationTime, LastAccessTime, LastWriteTime

########################## Folder size. ##########################
# /1MB - Convert to MB.
# /1GB - Convert to GB
(gci -path "Folder Path" -Recurse | measure -Property Length -Sum).sum /1MB

# Round to 2 decimal places.
[Math]::round((gci .\Networking\ -Recurse | measure -Property Length -Sum).sum /1MB,2)
$startFolder = "S:\Citrix_Profiles"
$colItems = Get-ChildItem $startFolder | Where-Object {$_.PSIsContainer -eq $true} | Sort-Object
$Output = foreach ($i in $colItems) {

$subFolderItems = Get-ChildItem $i.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum

New-Object psobject -property @{
"Size(GB)" = “{0:N2}-f ($subFolderItems.sum /1GB)
"Location" = $i.FullName
}

}
$Output | Export-csv -Path 'C:\Temp\FolderReport-$startFolder.csv' -NoTypeInformation

Check AAD Connect Sync

# Get the status of the last 10 syncs.
Get-ADSyncRunStepResult | Select -First 10 StepNumber,StepResult, StartDate, EndDate | ft -a
# Get Scheduler status.
Get-ADSyncScheduler