<< A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Active Directory Users and Computers (ADUC) - see RSAT

assoc command – associate a file extension with a command– see also ftype command

the assoc command doesn't work directly from within PowerShell. Instead, prefix with cmd. So, for example with PHP:

cmd /c assoc .php=phpfile

followed with

cmd /c ftype phpfile="C:\php8_2\php.exe" -f "%1" -- %~2

you can also put in the following to your profile

function assoc {cmd /c assoc $args}
function ftype {cmd /c ftype $args}

audio devices

Install-Module -Name AudioDeviceCmdlets

show defaults

Get-AudioDevice -List | ? {$_.DefaultCommunication -eq $true} | select ID, Type, Name



background color, get

(Get-Host ).UI.RawUI.BackgroundColor

background color, set

$a = (Get-Host).UI.RawUI

$a.BackgroundColor = "DarkGreen"

There aren’t too many choices


only lists 16 color choices


c drive on remote computer – see directory, on remote computer

certs, list

Get-ChildItem -Recurse Cert: | ft

command, run remotely - see remote command

compress a file - see zip a file

computer name see also environment variables


with fully qualified domain name


remote computer directory – see directory, on remote computer

computer remote session, - see remote session, initiate

computer serial number - see PC, get serial number

copy files from one directory to another

$destination = "D:\xml\"
$location = "D:\Client Portal\"
function processCopy
  $files = Get-ChildItem -Path:$location
  foreach($file in $files)
   $path = $file.FullName
  if($file.Name -ne "copy.ps1"){
   Copy-Item -Path:$path -Destination:$destination -Force -Confirm:$false
   Write-Host "Item" $file.Name " has been sucessfully copied to" $destination
   if($file.Attributes -eq "Directory")
    copyFile $file $destination

function copyFile($directory, $target)
  $target += $directory.Name
  $files = Get-ChildItem -Path:$directory.FullName
  foreach($file in $files)
  $path = $file.FullName
  if($file.Name -ne "copy.ps1"){
  Copy-Item -Path:$path -Destination:$target -Force -Confirm:$false
  Write-Host "Item" $file.Name " has been sucessfully copied to" $target

  if($file.Attributes -eq "Directory")

  copyFile $file $target

function Pause ($Message="Press any key to continue...")
  Write-Host -NoNewLine $Message
  $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
  Write-Host ""

Count how many files in a directory, excluding "bin" and "obj" files & directories

(gci "D:\VisualStudio\GID_CRM" -exclude bin, obj -Recurse).Count

CPU Utilization

top 20 threads (filtering out totals) shows

gwmi Win32_PerfFormattedData_PerfProc_Thread |
    ?{$_.Name -notmatch '_Total'} |
    sort PercentProcessorTime -desc |
    select -first 20 |
    ft -auto Name,IDProcess,IDThread,PercentProcessorTime


date of files, determine

ls d:\filemaker -rec | foreach {$_.creationtime -lt "02/25/2013"}

date of most recent file in a directory

$latest = Get-ChildItem -Path $backedUpDirectoryPath | Sort-Object LastWriteTime -Descending | Select-Object -First 1

directory, on remote computer

C drive on remote computer

dir \\remote-server\C$

directory, loop through

$sourceDirectory= "D:\somedirectory"
ls $sourceDirectory -rec | foreach {
  $filename = $_.Name
  $length = $_.length
  $creationtime = $_.creationtime
  $DirectoryName = $_.Directory.Name
  Write-Host $i $filename ", " $DirectoryName ", " $length ", " $creationtime

delete file

Remove-Item $a[$i] -recurse -force

directory, delete certain subdirectories and everything underneath them

gci $workingDirectory -include bin, obj, Upload -Recurse -Force | Remove-Item -Recurse -Force

In Powershell 3.0, it is simpler:

dir -Directory #List only directories
dir -File #List only files

Or to limit to just 2 directories deep:

dir -Directory .\*\*

In PowerShell 2, to just get directories (with grouping):

Get-ChildItem -Recurse | ?{ $_.PSIsContainer }

Or to limit to just 2 directories deep:

Get-ChildItem .\*\* | ?{ $_.PSIsContainer }

To get a raw list of directories, without the grouping:

Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | Select-Object FullName

directory size

(gci -Force "C:\Users\gollum\myPrecious\odes" -Recurse -ErrorAction SilentlyContinue | measure Length -s).sum

or in Gb

(gci -Force "C:\Users\gollum\myPrecious\odes" -Recurse -ErrorAction SilentlyContinue | measure Length -s).sum 1Gb

disk space, free

get-psdrive c | % {$_.free/($_.used + $_.free)} | % tostring p

disk space consumed by a bunch of similarly-named files, percentage of disk space

How much space are our SQL server error logs consuming on the F drive?

$errorFileLogLocation = "F:\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Log"
"{0:P}" -f ((gci $errorFileLogLocation Errorlog* | measure Length -s).sum / (Get-PSDrive F | % {($_.used + $_.free)}))

disk drives, status of all – including free disk space

$props = @(
    @{Name = 'SizeRemaining'
      Expression = {"{0:N3} Gb" -f ($_.SizeRemaining/ 1Gb)}}
    @{Name = 'Size'
      Expression = {"{0:N3} Gb" -f ($_.Size / 1Gb)}}
    @{Name = '% Free'
      Expression = {"{0:P}" -f ($_.SizeRemaining / $_.Size)}}
Get-Volume -DriveLetter C | Select-Object $props | ogv

disk UID



DISKPART> list disk


  Disk      Status         Size     Free     Dyn  Gpt
  --------  -------------  -------  -------  ---  ---
  Disk 0    Online          150 GB      0 B        *


DISKPART> select disk 0
Disk 0 is now the selected disk.
DISKPART> uniqueid disk
Disk ID: {14BA81F5-ED65-4C2D-8550-309D21D9712E}



$smtpFrom = "fromEmail@yourDomain"

$smtpTo ="toEmail@yourDomain"

$message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpTo

$message.Subject = $messageSubject

$message.IsBodyHTML = $true

$message.Body = $body

$smtpServer = "yourTenant-com01ec.mail.protection.outlook.com"

$smtp = new-object Net.Mail.SmtpClient($smtpServer)

$ credentials =new-object system.net.networkcredential("whosSending@yourDomain","TopSecret")



This does not work all the time

send-mailmessage -to "user@mydomain.com" `
  -from "user@mydomain.com" `
  -subject "sample subject line" `
  -smtpServer mymailserver.mydomain.com `
  -body 'test body'

not only does it not work, putting in a "try-catch" block doesn't give you an error; it errors out right away when you first try to run.

event log -

Get-WinEvent -FilterHashtable @{logname = "Application"; starttime = "11/14/23 07:40 am"; endtime = "11/14/23 07:55 am"} | ? {$_.LevelDisplayName -eq "Error" -or $_.LevelDisplayName -eq "Warning"}

or (deprecated, may fail because not recognized)

Get-EventLog -LogName "Application" | Select TimeWritten, Message, EventID | Where-Object -FilterScript {$_.TimeWritten -ge "11/14/23 07:40 am" -and $_.TimeWritten -le "11/14/23 07:55 am"}

event ID

this retrieves security event logs with event IDs 2886,2887,2888,2889,3039 and 3040 that occurred within the last day from a single server

Get-EventLog -LogName "Directory Service" 2886,2887,2888,2889,3039,3040 -After ((Get-Date).AddDays(-1))

If you get

Get-EventLog: The term 'Get-EventLog' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

This likely means that Get-Eventlog is deprecated. Try this instead (this gets recent schannel event IDs):

$StartTime = (Get-Date).AddMinutes(-5)
$EndTime = Get-Date
$Filter = @{
    LogName = "Directory Service"
    ID = @(36870, 36871, 36872, 36874, 36888)
    StartTime = $StartTime
    EndTime = $EndTime
try {
    Get-WinEvent -FilterHashtable $Filter -ErrorAction Stop
} catch {
    Write-Host "Error: $_"

By IP:

Get-WinEvent -FilterHashtable @{LogName="Directory Service"; ProviderName="Microsoft-Windows-ActiveDirectory_DomainService"; Data=""}

event ID from several servers

runs same query on many servers (domain controllers in this case) to return an object containing rows from many domain controllers with several fields

function Get2889OneDC ($startTime, $endTime) {
    $Filter = @{
        LogName = "Directory Service"
        ID = @(2889)
        StartTime = $startTime
        EndTime = $endTime
    $XML2889 = Get-WinEvent -FilterHashtable $Filter -ErrorAction Stop | % {$_.ToXml()}
    $LDAP2889 = @()
    foreach ($xml in $XML2889) {
        $xml = [xml]$xml
        # user
        $SID = $xml.Event.System.Security.UserID
        $objSID = New-Object System.Security.Principal.SecurityIdentifier $SID
        $objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
        $user = $objUser.Value
        # time
        $systemTime = $xml.Event.System.TimeCreated.SystemTime
        $time = (Get-Date $systemTime).ToString("yyyy-MM-dd h:mm:ss tt")
        $LDAP2889 += New-Object PSObject -property @{
            # dc = $xml.Event.System.Computer
            user = $user
            IP = $xml.Event.EventData.Data[0]
            computer = $xml.Event.EventData.Data[1]
            TimeCreated = $time}
    $LDAP2889 = $LDAP2889 | select computer, IP, user, TimeCreated #, dc, EventID
    return $LDAP2889

$DCs = @("DC1", "DC2")
$now = Get-Date
$endTime = $now.AddMinutes(-($now.Minute % 15)).AddSeconds(-$now.Second)
$startTime = $endTime.AddMinutes(-15)
$s = New-PSSession -ComputerName $DCs -ErrorAction Stop
$LDAP2889 = Invoke-Command -session $s -ScriptBlock ${function:Get2889OneDC} -ArgumentList $startTime, $endTime -ErrorAction Stop
Get-PSSession | Remove-PSSession
if ($LDAP2889) { # When any DC has no records that match, PowerShell helpfully puts in 5 empty, worthless rows, which we exclude by test whether IP field.
    # It also adds on a couple useless fields: RunspaceId, PSShowComputerName and one useful field - PSComputerName.
    # keep PSComputerName but do not select the extra RunspaceId, PSShowComputerName fields
    $LDAP2889 | ? {$_.IP } | select computer,IP,user,TimeCreated,@{n="DC";e={$_.PSComputerName}} | Export-CSV -Path "C:\reports\Event2889.csv" -NoTypeInformation -Encoding UTF8 -Append


folder on remote computer – see directory, on remote computer

fonts, install

$path = "directoryContainingFontFiles"
$shell = New-Object -ComObject Shell.Application

Or, if you want to check to see if the target PC already has it:

$sourcPath = "\\genetic-id.com\share\Dept_Shares\IT\Museo Sans Rounded\OpenType CFF Std"
$destinationPath = "c:\windows\fonts\"
$fontFileSource = Get-ChildItem $sourcPath | Select Name
# Check for presence of each file.  If any ONE of the 6 files are missing, install ALL of them.
foreach ($file in $fontFileSource)
    If (Test-Path "$($destinationPath)$($File.name)")
        #"font $($File.name) found, no action necessary"
        #"font $($File.name) not found, need to add"
        $shell = New-Object -ComObject Shell.Application

If you want to deploy these fonts across your organization, then invoke this from Group Policy.

ftype command – associate a file extension with a command – see also assoc command

the assoc command doesn't work directly from within PowerShell. Instead, prefix with cmd. So, for example with PHP:

cmd /c ftype phpfile="C:\php8_2\php.exe" -f "%1" -- %~2


Get-WMIObject not recognized – if


Get-WMIObject Win32_DiskDrive


Get-WMIObject: The term 'Get-WMIObject' is not recognized as a name of a cmdlet, function, script file, or executable program.

It might be because that command is deprecated in newer versions of PowerShell. try

Get-CimInstance -ClassName Win32_DiskDrive




installed programs

The only reason I include the PSPath - which is quite lengthy & often useless - is because for some entries just about all the other fields are empty. I think these are mainly OS update entries.

Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |  Select-Object DisplayName,InstallLocation,DisplayVersion,PSPath,Publisher,InstallDate | ogv





for the machine you're on


What languages are available on the machine?

Get-WinUserLanguageList | ft

local users and groups



MAC addresses for a PC


MPIO – Multipath IO

Install-WindowsFeature -Name Multipath-IO

My Documents location

$mydocs = [ environment]::getfolderpath("mydocuments")

change directory to my documents

$dir = [environment]::getfolderpath("mydocuments")

cd $dir

or if you don't want to mess with a variable and want to embed date/time in a file name

Get-AdUser | Export-Csv -Path "$([environment]::getfolderpath("mydocuments"))\fileBaseName$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv" -NoTypeInformation -Encoding UTF8


name of the PC/server you're on right now



$Get-WmiObject Win32_Computersystem).name


open files

all the open files in a certain directory

Get-SmbOpenFile | Where-Object -Property Path -Like "*somePath*" | ft ClientUserName,Path


Get-SmbOpenFile | Where-Object -Property ShareRelativePath -Match "someString" | select ShareRelativePath | fl

supposedly, this will find open files on another server

Get-SmbOpenFile -ScopeName "someServer"

but this always fails for me

Get-SmbOpenFile : No MSFT_SMBOpenFile objects found with property 'ScopeName' equal to 'someServer'. Verify the value of the property and retry.

operating system – see Windows version

OS – see Windows version


PC serial number

gwmi win32_bios


$sessionOption = New-CimSessionOption -Protocol Dcom
$cimSession = new-cimsession -sessionOption $sessionOption -computername somePCName
Get-CimInstance Win32_BIOS -CimSession $cimSession

pc name - see name of the PC/server you're on right now

processes, how many are going on


process, is one particular process active?

process, kill one particular process

profile location - $profile

To create a whole new profile (it checks first to make sure we don't already have one):

if (!(test-path $profile)) {new-item -type file -path $profile -force}

Prompt, change - helpful to include this in scripts that connect to other servers

function global:prompt{

    $promptString = "US $($executionContext.SessionState.Path.CurrentLocation) $([datetime]::Now.ToLongTimeString())>"
    write-host -NoNewLine -ForegroundColor Cyan $promptString
    return " "
#change prompt

That global: up top is pretty important



registry, can we view remote

Get-Service RemoteRegistry


Set-Service –Name RemoteRegistry –Computer someComputer -StartupType Automatic

Get-Service RemoteRegistry -ComputerName someComputer | Start-Service

registry values for a key, read and display

$Srv = "PC_Name"
$key = "SOFTWARE\Microsoft\Windows\CurrentVersion"
$type = [Microsoft.Win32.RegistryHive]::LocalMachine
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type , $Srv)
$regKey = $regKey.OpenSubKey($key)
Write-Host "Values"
Write-Host "------"
Foreach($val in $regKey.GetValueNames()){
   Write-Host $val.PadRight(30) -nonewline
   Write-Host $regKey.GetValue("$val")

Note that the way you specify which of the topmost hives (HKEY_LOCAL_MACHINE in this case) is by the $type = [Microsoft.Win32.RegistryHive]::LocalMachine

remote command

on several different computers at once:

$Cred = Get-Credential
Invoke-Command -ComputerName Mordor, TheShire {Get-Service -Name W32time} -Credential $Cred

runs on the remote computer and the results are returned to your local computer as deserialized objects. That doesn't mean you can't start or stop a service using a method with Invoke-Command though. It just means that the method has to be called in the remote session.

Invoke-Command -ComputerName Mordor, TheShire {(Get-Service -Name W32time).Stop()} - Credential $Cred

Sometimes a simple command…

Invoke-Command -ComputerName{$env:COMPUTERNAME} -Credential $Cred

…fails with:

[] Connecting to remote server failed with the following error message : The WinRM client cannot process the request. Default authentication may be used with an IP address under the following conditions: the transport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials are provided. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. For more information on how to set TrustedHosts run the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic.
    + CategoryInfo          : OpenError: ( [], PSRemotingTransportException
    + FullyQualifiedErrorId : CannotUseIPAddress,PSSessionStateBroken

Trying to fix with…

Set-Item WSMan:\localhost\Client\TrustedHosts -Value -Force

…fails with:

Set-Item : Access is denied. At line:1 char:1
+ Set-Item WSMan:\localhost\Client\TrustedHosts -Value ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Set-Item], InvalidOperation Exception
    + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.SetItemCommand

remote session, initiate

$Cred = Get-Credential
Enter-PSSession -ComputerName MagicKindom -Credential $Cred

to end:


RSAT (e.g., ADUC)

What available modules are installed?

Get-WindowsCapability -online | ? Name -like Rsat* | ft

Install RSAT for Windows 10 1809 and 1903 automated

RSAT, components included

RSAT, install

reg add "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Servicing" /v RepairContentServerSource /d 2 /t REG_DWORD /f

Add-WindowsCapability -online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~
Add-WindowsCapability -online -Name Rsat.Dns.Tools~~~~
Add-WindowsCapability -Online -Name Rsat.FileServices.Tools~~~~
Add-WindowsCapability -Online -Name Rsat.GroupPolicy.Management.Tools~~~~
Add-WindowsCapability -Online -Name Rsat.DHCP.Tools~~~~
Add-WindowsCapability -Online -Name Rsat.FailoverCluster.Management.Tools~~~~
Add-WindowsCapability -Online -Name Rsat.WSUS.Tools~~~~


schannel event IDs, find

$StartTime = (Get-Date).AddMinutes(-5)
$EndTime = Get-Date
$Filter = @{
    LogName = Security
    ID = @(36870, 36871, 36872, 36874, 36888)
    StartTime = $StartTime
    EndTime = $EndTime
try {
    Get-WinEvent -FilterHashtable $Filter -ErrorAction Stop
} catch {
    Write-Host "Error: $_"

Schedule PowerShell Scripts (in Server 2008)

In the "Action" tab, for the "Start a program", need to have "powershell" for the "Program/script" and the file location for the "Add arguments (optional)". If you're attempting to run some commands - like New-Object IO.FileSystemWatcher then you must precede the file name with "-NoExit . " (including the dot).

scheduled tasks, list – see also task scheduler, run a PowerShell script in

Finds tasks in the root directory and omits tasks whose names start with either "Optimize Start Menu Cache Files" or "MicrosoftEdgeUpdateTask"

$taskDetails = @()
$tasks = Get-ScheduledTask | ? {$_.TaskPath.Trim("\\") -eq "" -and $_.TaskName -notlike "Optimize Start Menu Cache Files*" -and $_.TaskName -notlike "MicrosoftEdgeUpdateTask*"}
foreach ($task in $tasks) {
    if ($task.Triggers.Count -eq 1) {
        foreach ($trigger in $task.Triggers) {
            switch ($trigger) {
                "MSFT_TaskDailyTrigger" {$triggerType = "daily"}
                "MSFT_TaskWeeklyTrigger" {$triggerType = "weekly"}
                "MSFT_TaskTrigger" {$triggerType = "monthly"}
                default {$triggerType = "unknown"}
            $startTime = $trigger.StartBoundary
            $inputDateTime= [DateTime]::Parse($startTime)
            $startTime = Get-Date $inputDateTime -Format "h:mm:ss tt"
    else {$triggerType = "multiple"}
    $taskDetails += New-Object -TypeName PSObject -Property @{
        TaskName = $task.TaskName
        type = $triggerType
        StartTime = $StartTime
        state = $task.state
        Execute = $task.Actions.Execute
        Arguments = $task.Actions.Arguments
$taskDetails | select TaskName, type, StartTime, Execute, state, Arguments | ogv

serial number for a PC - see PC, get serial number

server shares – see shares for a server, list


Find if you don't know the exact name but have some idea of the name. For example: you know the service has something to do with the word, profile:

get-service | Where-Object {$_.DisplayName -like "*profile*"} | ft

session, kill existing

Get-PSSession | Remove-PSSession

session, remote initiate - see remote session, initiate

shares for a server, list – aka: shared directories for a server, list

get-WmiObject -class Win32_Share -computer someServer




net share

these will likely at least show these 3:

Name   ScopeName Path       Description
----   --------- ----       -----------
ADMIN$ *         C:\WINDOWS Remote Admin
C$     *         C:\        Default share
IPC$   *                    Remote IPC

these are default and not recommended to remove. If you try anyway:

Get-SmbShare | ForEach-Object {Remove-SmbShare -Name $_.Name -Force}

Even if you run shell with admin priveleges to try to delete these 3 default shares, you might get something like this:

Remove-SmbShare : The request is not supported.
At line:1 char:32
+ Get-SmbShare | ForEach-Object {Remove-SmbShare -Name $_.Name -Force}
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   + CategoryInfo          : InvalidOperation: (MSFT_SmbShare (...copeName = "*"):ROOT/Microsoft/Windows/SMB/MSFT_SMBShare) [Remove-SmbShare], C
   + FullyQualifiedErrorId : Windows System Error 50,Remove-SmbShare


task scheduler, list tasks in – see scheduled tasks, list

task scheduler, run a PowerShell script in

in the "Actions" tab, in the "Start a program" area, put in "powershell"

In the "Add arguments" area, put in "-ExecutionPolicy Bypass D:\path\YourPowerShellScript.ps1"

If you see, "This task requires that the user account specified has Log on as batch job rights" the user must be able to do the following

  1. Start -> Run
  2. Type in secpol.msc /s
  3. Select "Local Policies" in MSC snap in
  4. Select "User Rights Assignment"
  5. Right click on "Log on as batch job" and select Properties
  6. Click "Add User or Group", and include the relevant user.

tenant, which one am I on?


The command above returns a list of SKUs, each of which includes an AccountSkuID field. The first part of this each of the AccountSkuID field on every row in this list of SKUs has the tenant name. If you just want the tenant name all by itself, use this instead:


which looks at the AccountSkuID field of the first SKU in the array and then uses the portion before the colon.


UNC directory, change to

Set-Location \\yourDomain.com\share

updates, windows - see windows updates

user profile


user profiles on remote PCs

Get-WmiObject -Class Win32_UserProfile -ComputerName 'SomePC'| ft LocalPath



Windows Services - see Services

Windows updates

Here's the shortest answer:


But that seems to leave out a lot of updates. This shows more:

$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$HistoryCount = $Searcher.GetTotalHistoryCount()
$Searcher.QueryHistory(0,$HistoryCount) | ForEach-Object {$_}

which I usually follow with an | Out-GridView so I don't just get a big screen dump.

Although this shows more records tha what Get-Hotfix does above, I can't tell for sure if there's any overlap because Get-Hotfix shows KB numbers whereas the 4 commands immediately above don't return any KB numbers.

or if you're not using PS 7 where none of these commands below work anymore, try

gwmi -cl win32_reliabilityRecords | select ProductName, SourceName, TimeGenerated, EventIdentifier, RecordNumber, __CLASS | ft


gwmi win32_quickfixengineering |sort installedon -desc | ft

Windows version - the single-line commands below will return various aspects

newer works with PS 7

[environment]::OSVersion.Version # same info as above but in table form
Get-CimInstance Win32_OperatingSystem # table with more entries including serial number and system directory
Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName someServer | select Caption # plain English version e.g., Microsoft Windows 2022

older commands do not work with PS 7

(Get-WmiObject Win32_OperatingSystem).Version # short number e.g., 10.0.18363
Get-WindowsEdition -Online # edition e.g., Core
gwmi win32_operatingsystem | % caption # plain English version e.g., Microsoft Windows 10 Home
(gwmi win32_operatingsystem).caption # plain English version e.g., Microsoft Windows 10 Home




zip a file

$src_folder = "D:\project"
$destfile = "D:\project.zip"
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
$includeBaseDir = $false
[System.IO.Compression.ZipFile]::CreateFromDirectory($src_folder, $destfile, $compressionLevel, $includeBaseDir)