PowerShellTips.json

[
  {
    "CreatedDate": "2023-07-16T00:00:00",
    "Title": "PowerShell is open source",
    "TipText": "Did you know that PowerShell is open source? You can contribute to the project on GitHub.",
    "Example": "",
    "Urls": [
      "https://github.com/PowerShell/PowerShell"
    ],
    "Category": 0
  },
  {
    "CreatedDate": "2023-07-17T00:00:00",
    "Title": "Set Strict Mode on your scripts",
    "TipText": "Enforce coding rules and raise errors for common coding mistakes by declaring strict mode at the top of your scripts.",
    "Example": "Set-StrictMode -Version Latest",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-08-28T00:00:00",
    "Title": "View your command line history",
    "TipText": "PowerShell lets you view your session history with `Get-History` and it's alias `h`.\r\n`Get-PSReadLineOption` used with `Get-Content` takes history reading further by allowing you to read your current users lifetime history.",
    "Example": "Get-Content (Get-PSReadLineOption).HistorySavePath",
    "Urls": [
      "https://learn.microsoft.com/powershell/module/psreadline/about/about_psreadline",
      "https://learn.microsoft.com/powershell/module/microsoft.powershell.core/get-history"
    ],
    "Category": 6
  },
  {
    "CreatedDate": "2023-09-05T00:00:00",
    "Title": "When checking for $null, put $null on the left",
    "TipText": "When checking if a variable or expression is null, put the $null on the left side of the comparison.\r\n\r\nIf the variable you are checking is an array that contains a null value, the comparison may not return the expected result if you put the $null on the right side of the comparison.\r\n\r\nDo this: if ($null -eq $variable)\r\nNot this: if ($variable -eq $null)",
    "Example": "if ($null -eq $variable) { \"The variable really is null.\" }",
    "Urls": [
      "https://powershellexplained.com/2018-12-23-Powershell-null-everything-you-wanted-to-know/",
      "https://stackoverflow.com/a/60996703/602585"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-06T00:00:00",
    "Title": "Use Ctrl+R to search your terminal history",
    "TipText": "When in your command prompt, press Ctrl+R to reverse search your terminal history. As you type, it will show the most recent matching command. This is a great way to find a command you ran previously, but can't remember the exact command or parameters.\r\n\r\nIf you press Ctrl+R again, it will show the next most recent matching command. You can keep pressing Ctrl+R to cycle through all matching commands. If you go past the command you wanted, press Ctrl+S and it will cycle through the matching commands in the opposite direction.\r\n\r\nNote: Requires the `PSReadLine` module, which is included in PowerShell 5.1 and newer.",
    "Example": "",
    "Urls": [
      "https://woshub.com/powershell-commands-history/"
    ],
    "Category": 6
  },
  {
    "CreatedDate": "2023-09-06T00:00:00",
    "Title": "Use Ctrl+Space to list all parameters, properties, and possibilities",
    "TipText": "In the terminal, when you are typing a command, parameter, or property, press Ctrl+Space to see a list of all the possible options. If there is only a single option, it will auto-complete the field for you. If there are many options, it will list them all for you to choose from and you can use the arrow keys to navigate the list and select one.\r\n\r\nCtrl+Space is similar to tab completion, except it will show you all of the options instead of just one option at a time and having to tab cycle through them.\r\n\r\nNote: Requires the `PSReadLine` module, which is included in PowerShell 5.1 and newer.",
    "Example": "- Type `Get-Process -` and press Ctrl+Space to list all the possible parameters you can use with the `Get-Process` command.\r\n- Type `$variableName.` and press Ctrl+Space to list all the properties and methods for the variable.\r\n- Type `Get-Pro` and press Ctrl+Space to list all the commands that start with `Get-Pro`, including their parameter sets.\r\n- Type part of a variable name (e.g. $var) and press Ctrl+Space to list all the variables that start with `$var`, including their type if available (e.g. [string], [int]).",
    "Urls": [
      "https://blog.danskingdom.com/PowerShell-intellisense-on-the-command-line/"
    ],
    "Category": 6
  },
  {
    "CreatedDate": "2023-09-11T00:00:00",
    "Title": "Ensure prerequisites are met by using #Requires",
    "TipText": "Use the #Requires statement to ensure that the environment meets the prerequisites for your script to run. You can use #Requires to check that:\r\n- A minimum PowerShell version is being used\r\n- PowerShell Desktop or PowerShell Core is being used\r\n- Specific modules or snap-ins are installed\r\n- The script is running as Administrator\r\n\r\nIf one of the required prerequisites are not met, PowerShell will throw an error and the script will not run.",
    "Example": "#Requires -Version 7.2\r\n#Requires -PSEdition Core\r\n#Requires -Modules @{ ModuleName=\"Az.KeyVault\"; ModuleVersion=\"4.0.0\" }\r\n#Requires -RunAsAdministrator",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_requires"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-11T00:00:00",
    "Title": "Join the monthly PowerShell community call!",
    "TipText": "The PowerShell Community Call is held on the 3rd Thursday of every month at 9:30 AM US Pacific Time. Topics include PowerShell 7, Windows OpenSSH, PSEditorServices/VSCode-PowerShell, PSScriptAnalyzer, PowerShell Gallery, and any other projects owned by the PowerShell Team.\r\n\r\nYou can join the Teams live event at https://aka.ms/JoinPSCall. The call is recorded and posted on YouTube.",
    "Example": "",
    "Urls": [
      "https://github.com/PowerShell/PowerShell-RFC/blob/master/CommunityCall/README.md",
      "https://powershell.org/series/powershell-community-call/",
      "https://www.youtube.com/@powershellanddscteamchanne5739"
    ],
    "Category": 0
  },
  {
    "CreatedDate": "2023-09-11T00:00:00",
    "Title": "Read and write Excel spreadsheets with ImportExcel",
    "TipText": "Need to share large data sets with colleagues or your boss? Excel is still a popular way to do that. ImportExcel is a PowerShell module that makes it easy to read and write Excel spreadsheets. Use it to export your data to Excel, and even add charts and pivot tables. It's fast and doesn't require Excel to be installed on your computer. It's also cross-platform, so you can use it on Windows, macOS, and Linux.",
    "Example": "[PSCustomObject[]] $data = @(\r\n\t[PSCustomObject] @{\r\n\t\tFirstName = 'John'\r\n\t\tLastName = 'Doe'\r\n\t\tAge = 42\r\n\t}\r\n\t[PSCustomObject] @{\r\n\t\tFirstName = 'Jane'\r\n\t\tLastName = 'Doe'\r\n\t\tAge = 39\r\n\t}\r\n)\r\n$data | Export-Excel -Path 'C:\\Temp\\Results.xlsx' -WorksheetName 'People' -FreezeTopRow -AutoFilter -AutoSize",
    "Urls": [
      "https://www.powershellgallery.com/packages/ImportExcel",
      "https://github.com/dfinke/ImportExcel"
    ],
    "Category": 2
  },
  {
    "CreatedDate": "2023-09-12T00:00:00",
    "Title": "Get text file updates in realtime with Get-Content",
    "TipText": "Get-Content provides a `-Wait` switch that can be used to get updates to a text file in realtime. This is useful for monitoring log files from the terminal, or any other text file that is updated over time.\r\n\r\nIn addition, if you want to get the last N lines of a file, you can use the `-Tail` parameter. This is useful for getting only the last few lines of a very large text file.\r\n\r\nOnce you are done monitoring the file, you can press `Ctrl+C` to stop the command.",
    "Example": "Get-Content -Path $filePath -Wait -Tail 10",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content",
      "https://4sysops.com/archives/parse-log-files-with-powershell/"
    ],
    "Category": 3
  },
  {
    "CreatedDate": "2023-09-16T00:00:00",
    "Title": "Use Out-GridView to view and select tabular data",
    "TipText": "Instead of piping data to Out-Table, use Out-GridView. This opens a window with the data in a grid view, allowing you to interactively sort and filter the data. If you provide the -PassThru parameter, you can select one or more rows and the selected data will be returned to the pipeline, allowing you to save it to a variable or pipe it to other commands.\r\n\r\nNOTE: Out-GridView is only available on Windows.",
    "Example": "Get-Process | Out-GridView -PassThru -Title \"Select processes to return\" | Select-Object -Property ProcessName,Id",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-gridview",
      "https://woshub.com/using-out-gridview-table-powershell/"
    ],
    "Category": 3
  },
  {
    "CreatedDate": "2023-09-17T00:00:00",
    "Title": "Use F2 to toggle PSReadLine predictions to list view",
    "TipText": "PSReadLine v2.1.0 introduced history-based predictions. As you type, PSReadLine will show you a command that you previously typed, thinking that you may want to run the same command again. You can use the right-arrow to accept the suggestion.\r\n\r\nIf you want to see more predictions, you can press the F2 key to swap from Inline View (which only shows a single suggestion), to List View, which shows many. You can then use the up and down arrow keys to select a command from the list.\r\n\r\nUse 'Update-Module -Name PSReadLine' to update to the latest version of PSReadLine and use these features.",
    "Example": "Type \"Get-\" and then press F2 to see a list of commands that you have previously typed that start with \"Get-\"",
    "Urls": [
      "https://devblogs.microsoft.com/powershell/announcing-psreadline-2-1-with-predictive-intellisense/",
      "https://learn.microsoft.com/en-us/powershell/module/psreadline/"
    ],
    "Category": 6
  },
  {
    "CreatedDate": "2023-09-18T00:00:00",
    "Title": "Split long lines of code into multiple lines",
    "TipText": "Long lines of code can be difficult to read, especially when doing code reviews in a web browser and for users not using word-wrap in their editors. It is good practice to try and avoid long lines of code.\r\n\r\nPowerShell lines can naturally be split into multiple lines at many operators, such as =, +, -, |, {, -eq, etc.\r\n\r\nIf you need to split a line at an unnatural location, you can use the backtick character (`) at the end of each line. This is generally discouraged though as the backtick can be hard to see, easy to forget, and a space after the backtick breaks the line continuation. However, there are times when it may still be useful.",
    "Example": "# Split into multiple lines using natural operators.\r\n[bool] $arrayIsNullOrEmpty =\r\n $null -eq $myIntegerArray -or\r\n $myIntegerArray.Length -eq 0\r\n\r\n[int[]] $valuesGreaterThan10AndSorted =\r\n $myIntegerArray |\r\n Where-Object {\r\n $_ -gt 10\r\n } |\r\n Sort-Object\r\n\r\n[string] $myString =\r\n 'This is a very long string that is split into multiple lines ' +\r\n 'using the + operator.'\r\n\r\n# Split into multiple lines at an unnatural locations using the backtick.\r\nGet-ChildItem `\r\n -Path 'C:\\' `\r\n -Recurse `\r\n -File `\r\n -Filter '*.txt'",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parsing?view=powershell-7.3#line-continuation"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-19T00:00:00",
    "Title": "Use Splatting for nicer code and dynamic parameters",
    "TipText": "Splatting allows you to pass parameters to a function as a hashtable. This can make your code more readable when you have a lot of parameters to pass to a function. It also allows you to build the parameters dynamically.\r\n\r\nTo use splatting, create a hashtable with the parameter names as the keys and the parameter values as the values. Then, pass the hashtable to the function using the `@` operator.\r\n\r\nYou can also use splatting with arrays, where the array values are passed to the function as positional parameters.\r\n\r\nIn a function, you can use the $PSBoundParameters automatic variable to access the parameters that were passed to the function. This allows you to modify and extend the given parameters before passing them to another function.",
    "Example": "$hashtableParameters = @{\r\n Path = \"test.txt\"\r\n Destination = \"test2.txt\"\r\n WhatIf = $true\r\n}\r\nCopy-Item @hashtableParameters\r\n\r\n$arrayParameters = \"test.txt\", \"test2.txt\"\r\nCopy-Item @arrayParameters -WhatIf",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_splatting",
      "https://adamtheautomator.com/powershell-splatting/",
      "https://4sysops.com/archives/use-splatting-and-psboundparameters-to-pass-parameters-in-powershell/"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-21T00:00:00",
    "Title": "Use Here-strings for hardcoded multiline strings",
    "TipText": "When you are defining multiline strings in code, you could create a string and use `r`n or [Environment]::NewLine to create new lines in it. If it is a long string, you may even choose to break it into multiple lines in code and concatenate them using the + operator. However, this can be cumbersome to both write and read. Instead, you can use a here-string to define a multiline string.\r\n\r\nA here-string is a string that is defined between two `@ symbols. The here-string can be defined with single or double quotes. If you use single quotes, the string will be a literal string and no variable expansion will occur. If you use double quotes, variable expansion will occur.\r\n\r\nHere-strings allow you to define and see a multiline string in your code exactly as it will appear when it is output.",
    "Example": "[string] $multilineString = @'\r\nThis is the first line of the string.\r\nThis is the second line of the string.\r\n\r\n There is a blank line above this line, and 2 spaces at the start of this line.\r\nThis $variable will not be expanded because we used single quotes.\r\n`'@\r\n\r\n[int] $johnDoeAge = 42\r\n[string] $jsonString = @\"\r\n{\r\n \"Name\": \"John Doe\",\r\n \"Age\": $johnDoeAge\r\n}",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules#here-strings",
      "https://devblogs.microsoft.com/scripting/maximizing-the-power-of-here-string-in-powershell-for-configuration-data"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-21T00:00:00",
    "Title": "Use PSBoundParameters to check if a parameter was provided",
    "TipText": "When writing a function you may want to check if a parameter was provided by the caller. With reference types (e.g. [string]) you can simply check if the parameter is null, but what is $null is a valid value for the parameter and you need to take different action if the parameter was not provided? Similarly, what if the parameter is a value type (e.g. [int]) and you need to take action if the caller provided the default value (e.g. zero), but not if they didn't provide the parameter?\r\n\r\nYou can check if a parameter was passed to a script/function by using the $PSBoundParameters automatic variable. This variable contains a hashtable of all parameters that were passed to the function, and you can use the ContainsKey function to check if a specific parameter was passed.",
    "Example": "function Test-ParameterWasPassed([string] $OptionalParameter = $null)\r\n{\r\n\tif ($PSBoundParameters.ContainsKey('OptionalParameter'))\r\n\t{\r\n\t\tWrite-Output 'OptionalParameter was passed.'\r\n\t}\r\n\telse\r\n\t{\r\n\t\tWrite-Output 'OptionalParameter was not passed.'\r\n\t}\r\n}",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables#psboundparameters",
      "https://devblogs.microsoft.com/powershell/checking-for-bound-parameters/",
      "https://www.reza-aghaei.com/how-to-determine-if-a-parameter-is-passed-to-a-powershell-cmdlet/"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-22T00:00:00",
    "Title": "Avoid Array addition",
    "TipText": "Array addition is an expensive and inefficient operation and can usually be replaced by PowerShell explicit loop assignment.\r\n\r\nUse a `List<T>` instead in those cases when adding to a collection while looping is required.",
    "Example": "# Array addition:\r\n$items = @()\r\nforeach ($i in 0..10) {\r\n $items += $i\r\n}\r\n\r\n# Can be easily replaced with explicit assignment:\r\n$items = foreach ($i in 0..10) {\r\n $i\r\n}\r\n\r\n# And, when not possible, a List<T> is recommended:\r\n$items = [System.Collections.Generic.List[int]]::new()\r\nforeach ($i in 0..10) {\r\n $items.Add($i)\r\n}",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/performance/script-authoring-considerations?view=powershell-7.3#array-addition"
    ],
    "Category": 4
  },
  {
    "CreatedDate": "2023-09-23T00:00:00",
    "Title": "Define hardcoded array items on new lines without commas",
    "TipText": "When defining hardcoded arrays with many values in PowerShell, you can define each item on a new line without commas; the commas are optional. This makes it easier to read and maintain the array items, and you don't have to worry about commas when adding or rearranging items.\r\n\r\nIf you choose to define multiple array values on a single line, then you will need a comma between each item on the line.",
    "Example": "[string[]] $stringArray = @(\r\n 'Notice that each item is on a new line without commas.'\r\n 'This is much easier to read and maintain.'\r\n 'And you can add comments to explain each item if needed.' # Like this.\r\n)\r\n\r\n[int[]] $intArray = @(1, 2, 3)",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-arrays?view=powershell-7.3#create-an-array"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-23T00:00:00",
    "Title": "Use $PSVersionTable to get PowerShell session info",
    "TipText": "The $PSVersionTable automatic variable contains information about the current PowerShell session, including the PowerShell version, operating system, and more.",
    "Example": "Write-Output \"The PowerShell version being used is $($PSVersionTable.PSVersion)\"\r\n\r\nWrite-Output \"Below is the full contents of the `$PSVersionTable variable:\"\r\n$PSVersionTable",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables#psversiontable"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-23T00:00:00",
    "Title": "Use Flags to allow multiple enum values",
    "TipText": "You can use the [Flags()] attribute to allow multiple enum values to be used at once. In addition to the attribute, you need to set the enum values to powers of 2 (1, 2, 4, 8, 16, etc.). This allows you to use the bitwise operators to combine enum values.\r\n\r\nWhen using a flags enum you must be careful to not use the -eq operator to check if a variable contains a specific enum value. This will only return true if the variable contains only that enum value. Instead, use the -band operator or the .HasFlag() method to check if the variable contains a specific enum value.",
    "Example": "[Flags()]\r\nenum FileAttributes {\r\n Archive = 1\r\n Compressed = 2\r\n Device = 4\r\n Directory = 8\r\n Encrypted = 16\r\n Hidden = 32\r\n}\r\n\r\n# Set a variable to multiple enum values.\r\n$attributes = [FileAttributes]::Archive + [FileAttributes]::Hidden\r\n$attributes += [FileAttributes]::Compressed\r\n\r\n# Check if the variable contains a specific enum value.\r\n$attributes -eq [FileAttributes]::Archive # False\r\n$attributes -band [FileAttributes]::Archive # True\r\n$attributes.HasFlag([FileAttributes]::Archive) # True",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_enum#enumerations-as-flags",
      "https://arcanecode.com/2021/12/06/fun-with-powershell-enum-flags/"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-09-29T00:00:00",
    "Title": "Use dynamic values in ValidateSet while maintaining tab completion",
    "TipText": "The ValidateSet attribute is a great way to limit the values that can be passed to a parameter, and it provides tab autocompletion for the parameter values. Typically if you wanted to use dynamic values you would use the ValidateScript attribute instead, but then you lose the tab autocompletion.\r\n\r\nA way to get the best of both worlds is to create a class that implements the System.Management.Automation.IValidateSetValuesGenerator interface. This interface has a single method, GetValidValues(), that returns an array of strings. You can put the logic to dynamically retrieve your allowed parameter values in the GetValidValues() method. You can then use the ValidateSet attribute with the type of your class, and the tab autocompletion will work as expected.",
    "Example": "class AllowedParameterValues : System.Management.Automation.IValidateSetValuesGenerator {\r\n [string[]] GetValidValues() {\r\n # Populate these values dynamically by querying a database, reading a file, calling an API, etc.\r\n $values = @('Value1', 'Value2', 'Value3')\r\n return $values\r\n }\r\n}\r\n\r\nfunction Test-ValidateSet {\r\n param (\r\n [ValidateSet([AllowedParameterValues])]\r\n [string] $Value\r\n )\r\n return $Value\r\n}\r\n\r\nTest-ValidateSet -Value # Tab complete here to see the dynamic values.",
    "Urls": [
      "https://www.linkedin.com/feed/update/urn:li:activity:7113300637735407618/"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-10-02T00:00:00",
    "Title": "Quickly create temporary file",
    "TipText": "Quickly create a temporary file by using the New-TemporaryFile command, or the GetTempFileName() .NET function.\r\n\r\nThis is handy when you want save data to a temporary log file and not worry about path/permissions/filename. The temporary file will be created in \"C:\\Users\\USER\\AppData\\Local\\Temp\\1\\some-tmp.tmp\".",
    "Example": "# Create temp file and get the path to it using the .NET class.\r\n[string] $tmpFile = [System.IO.Path]::GetTempFileName()\r\n\r\n# Or use the native PowerShell cmdlet instead, which returns a full FileInfo object.\r\n[System.IO.FileInfo] $tmpFile = New-TemporaryFile\r\n\r\n# Easily write/read/remove the temp file.\r\n\"Some data to be saved\" | Out-File $tmpFile\r\n\r\n# Cleanup when you no longer need it.\r\nRemove-Item $tmpFile",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/new-temporaryfile",
      "https://learn.microsoft.com/en-us/dotnet/api/system.io.path.gettempfilename#system-io-path-gettempfilename"
    ],
    "Category": 5
  },
  {
    "CreatedDate": "2023-10-02T00:00:00",
    "Title": "Use PowerShell classes for strongly-typed objects",
    "TipText": "PowerShell 5.0 introduced classes. Classes allow you to create strongly-typed objects, encapsulating properties and methods. This allows you to keep related data together and to define functions for manipulating the data, allowing for validation if necessary. Classes also allow for inheritance.\r\n\r\nThere are some caveats to working with classes in PowerShell though:\r\n- If you make changes to the class definition you must reload the PowerShell session for the changes to take effect.\r\n- PowerShell classes defined in modules are not exported when 'Import-Module' is used; Instead the 'using module' syntax must be used.",
    "Example": "class Employee\r\n{\r\n\t[string] $FirstName\r\n\t[string] $LastName\r\n\t[DateTime] $DateOfBirth\r\n\t[int] $Salary\r\n\r\n\t[string] GetFullName()\r\n\t{\r\n\t\treturn \"$this.FirstName $this.LastName\"\r\n\t}\r\n\r\n\t[void] IncreaseSalary([int] $amount)\r\n\t{\r\n\t\t$this.Salary += $amount\r\n\t}\r\n}\r\n\r\n$employee = [Employee]::new()\r\n$employee.FirstName = 'John'\r\n$employee.LastName = 'Doe'\r\n$employee.DateOfBirth = [DateTime]::Parse('1983-01-15')\r\n$employee.Salary = 50000\r\n$employee.GetFullName()\r\n$employee.IncreaseSalary(10000)",
    "Urls": [
      "https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_classes",
      "https://xainey.github.io/2016/powershell-classes-and-concepts/",
      "https://blog.danskingdom.com/PowerShell-class-definition-pros-cons-and-performance-comparison/"
    ],
    "Category": 5
  }
]