{"id":14064028,"url":"https://github.com/cavo789/powershell_tips","last_synced_at":"2026-05-21T09:01:38.205Z","repository":{"id":101354674,"uuid":"222681741","full_name":"cavo789/powershell_tips","owner":"cavo789","description":"Tips and tricks and snippets of PowerShell functions","archived":false,"fork":false,"pushed_at":"2021-11-01T20:47:29.000Z","size":478,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-12-31T21:43:46.451Z","etag":null,"topics":["powershell","powershell-scripts","powershell-tips"],"latest_commit_sha":null,"homepage":null,"language":"PowerShell","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cavo789.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-11-19T11:36:16.000Z","updated_at":"2025-10-06T09:29:31.000Z","dependencies_parsed_at":null,"dependency_job_id":"fb1ff9a5-448e-4a75-b6c4-991899990b8d","html_url":"https://github.com/cavo789/powershell_tips","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cavo789/powershell_tips","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavo789%2Fpowershell_tips","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavo789%2Fpowershell_tips/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavo789%2Fpowershell_tips/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavo789%2Fpowershell_tips/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cavo789","download_url":"https://codeload.github.com/cavo789/powershell_tips/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cavo789%2Fpowershell_tips/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33295232,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-21T02:57:32.698Z","status":"ssl_error","status_checked_at":"2026-05-21T02:57:31.990Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["powershell","powershell-scripts","powershell-tips"],"created_at":"2024-08-13T07:03:38.239Z","updated_at":"2026-05-21T09:01:38.155Z","avatar_url":"https://github.com/cavo789.png","language":"PowerShell","funding_links":[],"categories":["PowerShell"],"sub_categories":[],"readme":"﻿\u003c!-- This file has been generated by the concat-md.ps1 script. --\u003e\n\u003c!-- Don't modify this file manually (you'll loose your changes) --\u003e\n\u003c!-- but run the tool once more --\u003e\n\n\u003c!-- Last refresh date: 2020-06-05 11:44:14 --\u003e\n\n\u003c!-- below, content of ./index.md --\u003e\n\n# PowerShell tips and snippets\n\n![Banner](./banner.svg)\n\n\u003e A few PowerShell tips and functions snippets\n\n\u003c!-- table-of-contents - start --\u003e\n* [Core features](#core-features)\n  * [Syntax elements](#syntax-elements)\n    * [Define global variables](#define-global-variables)\n    * [Include external script](#include-external-script)\n    * [Split long string on multiple lines](#split-long-string-on-multiple-lines)\n  * [Variables](#variables)\n* [Some helpers](#some-helpers)\n  * [Files](#files)\n    * [Check if file exists](#check-if-file-exists)\n    * [Get a flat list of files](#get-a-flat-list-of-files)\n      * [Get the depth too](#get-the-depth-too)\n      * [Get list of files, recursively](#get-list-of-files-recursively)\n  * [Folders](#folders)\n    * [Get parent folder](#get-parent-folder)\n    * [Get the target filename of a symlink](#get-the-target-filename-of-a-symlink)\n    * [Prettify JSON](#prettify-json)\n    * [Consume XML response](#consume-xml-response)\n* [Regex](#regex)\n  * [Between two tags](#between-two-tags)\n  * [Case insensitive](#case-insensitive)\n  * [Match all occurrences](#match-all-occurrences)\n  * [Multiline](#multiline)\n* [License](#license)\n\u003c!-- table-of-contents - end --\u003e\n\n\u003c!-- below, content of ./010-core/readme.md --\u003e\n\n## Core features\n\n\u003c!-- below, content of ./010-core/syntax/readme.md --\u003e\n\n### Syntax elements\n\n\u003c!-- below, content of ./010-core/syntax/global_variables/readme.md --\u003e\n\n#### Define global variables\n\nDefining a variable for the entire script; initialize it once and use it everywhere.\n\nThe key is to use the `$global:` prefix like below:\n\n```powershell\nbegin {\n\n    # Folder where the running Powershell script is stored\n    $global:scriptDir = \"\"\n\n    function initialize() {\n        $global:scriptDir = Split-Path $script:MyInvocation.MyCommand.Path\n    }\n\n    function someFunction() {\n        Write-Host $global:scriptDir\n    }\n}\n```\n\n\u003c!-- below, content of ./010-core/syntax/include/readme.md --\u003e\n\n#### Include external script\n\nIncluding an external script (f.i. `my_helper.ps1`) can be done using the dot notation: `. my_helper.ps1`.\n\n```powershell\n# Define the debug mode constant\nset-variable -name DEBUG -value ([boolean]$FALSE) -option Constant\n\nfunction include_helpers() {\n\n    # List of helpers to load\n    $helpers = @(\"files\", \"images\", \"markdown\")\n\n    if ($DEBUG -eq $TRUE) {\n        # If debug mode is enabled, debug.ps1 will also be loaded\n        $helpers = $helpers + @(\"debug\")\n    }\n\n    foreach ($helper in $helpers) {\n        # Suppose that files are in the helpers sub folder\n        $filename = \".\\helpers\\$helper.ps1\"\n\n        try {\n            if ([System.IO.File]::Exists($filename)) {\n                # The file exists; load it\n                . $filename\n            }\n        }\n        catch {\n            Write-Error \"Error while loading helper $filename\"\n        }\n    }\n\n    return;\n}\n```\n\nNote: functions should be declare with the `global:` prefix.\n\n\u003c!-- below, content of ./010-core/syntax/split_command/readme.md --\u003e\n\n#### Split long string on multiple lines\n\nDon't write things like:\n\n```powershell\nWrite-Error \"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab ...\")\n```\n\nbut split the string using the `$( ...)` syntax:\n\n```powershell\nWrite-Error $(\"Sed ut perspiciatis unde omnis iste natus error \" +\n    \"sit voluptatem accusantium doloremque laudantium, totam rem \"\n    \"aperiam, eaque ipsa quae ab ...\")\n```\n\nFor commands too, don't write things like:\n\n```powershell\n$target = Get-Item -Path $filename | Select-Object -ExpandProperty Target | Select-Object -First 1\n```\n\nbut split the command like this:\n\n```powershell\n$target = Get-Item -Path $filename `\n    | Select-Object -ExpandProperty Target `\n    | Select-Object -First 1\n```\n\n\u003c!-- below, content of ./010-core/variables/readme.md --\u003e\n\n### Variables\n\n| Variable                       | Description                                                               |\n| ------------------------------ | ------------------------------------------------------------------------- |\n| `[string](Get-Location)`       | Get the current folder.                                                   |\n| `$MyInvocation.MyCommand.Name` | Return the full name of the running script (return f.i. `c:\\temp\\a.ps1`). |\n| `$PSScriptRoot`                | Return the folder of the running script (`c:\\temp`)                       |\n\n\u003c!-- below, content of ./040-helpers/readme.md --\u003e\n\n## Some helpers\n\n\u003c!-- below, content of ./040-helpers/files/readme.md --\u003e\n\n### Files\n\n\u003c!-- below, content of ./040-helpers/files/file_exists/readme.md --\u003e\n\n#### Check if file exists\n\n```powershell\n\u003c#\n.SYNOPSIS\n    Check if a file exists on disk\n.PARAMETER Filename\n    Name of the file to check\n.OUTPUTS\n    True if the file exists,\n    False othwerise\n#\u003e\nfunction fileExists([string] $filename) {\n    return [Boolean](Test-Path $filename -PathType Leaf)\n}\n```\n\nAlternative solution: `[System.IO.File]::Exists($filename)` (no support for wildcard characters)\n\n\u003c!-- below, content of ./040-helpers/files/get_list_of_files/readme.md --\u003e\n\n#### Get a flat list of files\n\nThe function below will retrieve the list of all files below the current running folder and will returns a flat list (i.e. only files name).\n\nThe function support exclusions like skipping specific folders or files.\n\n```powershell\n\u003c#\n.DESCRIPTION\n    Retrieve the list of all files (based on the mentioned pattern).\n    The result will be a flat list (i.e. only files name).\n    Support exclusions like skipping folders or files.\n.PARAMETER Pattern\n    Pattern for files like c:\\temp\\*.* or just *.*\n.PARAMETER Exclude\n    It's a regex that contains patterns to exclude\n    For instance, exclude some folders\n        \".*\\\\\\.config\\\\|.*\\\\\\.git\\\\|.*\\\\backup\\\\\"\n    And exclude files based on their extensions\n        \".bmp$|.gif$|.ico$|.jpe?g$|.png$\"\n.OUTPUTS\n    Array\n#\u003e\nfunction getListOfFiles([string] $pattern = \"*.*\", [string] $exclude = \"\") {\n    # Get the list of all files, retrieve a flatlist and\n    # don't report errors when f.i. a folder is a symlink\n    $files = Get-ChildItem . -Filter $pattern -Recurse `\n    | Where-Object { $_.Fullname -notmatch $exclude } `\n    | Group-Object \"FullName\" `\n    | Select-Object \"Name\"\n\n    return $files\n}\n\n# Sample\n# Skip .git and backups folders\n$exclude = \".*\\\\\\.git\\\\|.*\\\\backups\\\\\"\n# and skip some extensions\n$exclude += \"|.bmp$|.gif$|.ico$|.jpe?g$|.png$\"\n\n$files = getListOfFiles '*.*'  $exclude\n\nforeach ($file in $files) {\n    Write-Host \"Process\" $file.Name\n}\n```\n\nThis will return something like below:\n\n```text\nC:\\Christophe\\demo\\readme.md\nC:\\Christophe\\demo\\03_Annex\\index.md\nC:\\Christophe\\demo\\03_Annex\\01_Annex1\\index.md\nC:\\Christophe\\demo\\07_Date\\index.md\n```\n\n##### Get the depth too\n\nThe following snippet calculate a FolderDepth column based on the number of `\\` separator in the filename:\n\n```powershell\n\u003c!-- concat-md::include \"./files/getListOfFilesWithDepth.ps1\" -- \u003e\n```\n\nThis will return something like below:\n\n```powershell\n\u003c!-- concat-md::include \"./files/getListOfFilesWithDepth.txt\" -- \u003e\n```\n\n##### Get list of files, recursively\n\nGet the list of files, with or without a filter like a file's extension and define the maximum deep allowed so it's possible to get only the root folder (`MaxDepth=0`, the root and the first children, ...).\n\n```powershell\n\u003c!-- concat-md::include \"./files/getListOfFilesRecursiveWithMaxDepth.ps1\" -- \u003e\n```\n\n\u003c!-- below, content of ./040-helpers/folders/readme.md --\u003e\n\n### Folders\n\n\u003c!-- below, content of ./040-helpers/folders/get_parentfolder/readme.md --\u003e\n\n#### Get parent folder\n\n```powershell\n\u003c#\n.SYNOPSIS\n    Return the parent folder of a file\n.PARAMETER Filename\n    Filename for which the parent folder should be returned\n.OUTPUTS\n    String\n#\u003e\nfunction getParentFolderName([string] $filename) {\n    return (Split-Path -Path $filename)\n}\n```\n\n\u003c!-- below, content of ./040-helpers/folders/get_symlinktargetpath/readme.md --\u003e\n\n#### Get the target filename of a symlink\n\nWhen a file is a symbolic or hard link, the following function will return the original filename.\n\nFor instance if `c:\\temp\\a.ps1` is symlink to `c:\\christophe\\repositories\\tools\\utils.ps1`, the following function will return the full name of the original filename so will return `c:\\christophe\\repositories\\tools\\utils.ps1`.\n\n```powershell\n\u003c#\n.DESCRIPTION\n    When a file is a symlink, return the target path i.e. the original path of the file\n    Note: when the same file is symlinked multiple times, the ExpandProperty\n    will return all files so get only the first item which is the original file\n.PARAMETER Filename\n    That file should be a symlink (hard or symbolic)\n.OUTPUTS\n    String\n#\u003e\nfunction getSymLinkTargetPath([string] $filename) {\n    $target = Get-Item -Path $filename  `\n    | Select-Object -ExpandProperty Target `\n    | Select-Object -First 1\n\n    return [string]$target\n}\n```\n\n\u003c!-- below, content of ./040-helpers/json/prettify/readme.md --\u003e\n\n#### Prettify JSON\n\n```powershell\n$objJSON = Get-Content -Path \".\\test.json\"\n$objJSON | ConvertFrom-Json | ConvertTo-Json | Out-File -FilePath \".\\test-Pretty.json\"\nGet-Content \".\\test-Pretty.json\"\n```\n\n\u003c!-- below, content of ./040-helpers/webservice/consume_xml/readme.md --\u003e\n\n#### Consume XML response\n\nConsume a service returning XML and display the response\n\n```powershell\n[int] $Amount = 5\n[string] $Type = \"pargraphs\"\n[string] $Start = \"yes\"\n\n[xml]$Temp = Invoke-WebRequest -UseBasicParsing -Uri \"https://www.lipsum.com/feed/xml?amount=$Amount\u0026what=$Type\u0026start=$Start\"\n\n$Temp.feed.lipsum\n```\n\n\u003c!-- below, content of ./050-regex/readme.md --\u003e\n\n## Regex\n\n\u003e [List of modifiers](https://www.regular-expressions.info/modifiers.html)\n\n\u003c!-- below, content of ./050-regex/between_tags/readme.md --\u003e\n\n### Between two tags\n\nRetrieve the content between two HTML tags:\n\n```powershell\n\n# Search for the pattern like:\n#       \u003c!-- start --\u003e\n#       CONTENT\n#       \u003c!-- end --\u003e\n#\n# Can be on the same line or on multiple lines\n$content = \"\u003c!-- start --\u003eIpso Lorem\u003c!-- end --\u003e\"\n\n$pattern = [regex]$(\n    \"\\n?\\\u003c\\!\\-\\- start \\-\\-\\\u003e\" +\n    \"([\\s\\S]*?)\" +\n    \"\\\u003c\\!\\-\\- end \\-\\-\\\u003e\\n?\"\n)\n\n# Write the CONTENT\nWrite-Host $([string]($pattern).Match($content).groups[1].value)\n```\n\n\u003c!-- below, content of ./050-regex/case_insensitive/readme.md --\u003e\n\n### Case insensitive\n\nThe default mode is case sensitive, to change this, the mode to use is `(?i)` at the very start of the `[regex]` expression:\n\n```powershell\n$content = \"Ipso lorem`n`n@TOdo Christophe: do this.`n`nIpso lorem\"\n\n$pattern = [regex]\"(?msi)^(\\@todo ([^\\n\\r]*))\"\n\nif (($pattern.Match($content)).success) {\n    Write-Warning \"@TODO found at the beginning of the string\"\n    Write-Host \"There is a TODO for $($pattern.Match($content).groups[2].value)\"\n}\n```\n\n\u003c!-- below, content of ./050-regex/match_all/readme.md --\u003e\n\n### Match all occurrences\n\nProcess every occurrences:\n\n```powershell\n$content = \"# Heading 1`n`n## Heading 1.1`n`n## Heading 1.2`n`n## Heading 1.3\"\n\n# Skip heading 1 so start at 2\n#    (?ms)       ==\u003e Multi-lines regex\n#    ^           ==\u003e The start of the line\n#    (\\#{2,})    ==\u003e We need to find at least two consecutive #\n#     ([^\\n\\r]*) ==\u003e Capture the end of the line (exclude CRLF)\n#    $          ==\u003e End of the line\n$pattern = [regex]\"(?ms)^(\\#{2,}) ([^\\n\\r]*)$\"\n\n$headings = $pattern.Matches($content);\n\nif ($headings.Count -gt 0) {\n    $match = $pattern.Match($content)\n\n    while ($match.Success) {\n        # Isolate the # (one or more) and the title\n        $pattern = [regex]\"(#{2,})* (.*)\"\n\n        # Display \"Heading 1.1\", \"Heading 1.2\", ...\n        Write-Host $pattern.Match($match).Groups[2].Value\n\n        $match = $match.NextMatch()\n    }\n}\n```\n\n\u003c!-- below, content of ./050-regex/multiline/readme.md --\u003e\n\n### Multiline\n\nTo make a search on more than one line:\n\n```powershell\n\n# Match a YAML block\n#\n#   The block start with --- on his own line\n#   Then there is a content (one or more line)\n#   The block ends with --- on his own line\n\n$content = \"---`nTitle: My great title`n---`n\"\n\n$pattern = [regex]\"(?ms)(^\\-{3}([\\s\\S]*\\s)^\\-{3})\"\n\n# Write the YAML content\nWrite-Host $([string]($pattern).Match($content).groups[2].value)\n```\n\n\u003c!-- below, content of ./999-license/readme.md --\u003e\n\n## License\n\n[MIT](./../LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcavo789%2Fpowershell_tips","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcavo789%2Fpowershell_tips","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcavo789%2Fpowershell_tips/lists"}