{"id":8709,"date":"2021-12-10T12:28:39","date_gmt":"2021-12-10T17:28:39","guid":{"rendered":"https:\/\/jdhitsolutions.com\/blog\/?p=8709"},"modified":"2021-12-10T12:28:43","modified_gmt":"2021-12-10T17:28:43","slug":"converting-powershell-scripts-to-functions","status":"publish","type":"post","link":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/","title":{"rendered":"Converting PowerShell Scripts to Functions"},"content":{"rendered":"\n<p>Recently, I shared some PowerShell code to <a href=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8693\/exporting-powershell-functions-to-files\/\" target=\"_blank\" rel=\"noreferrer noopener\">export a function to a file<\/a>. It was a popular post. My friend <a href=\"https:\/\/twitter.com\/richardhicks\" target=\"_blank\" rel=\"noreferrer noopener\">Richard Hicks <\/a>(no relation) thought we was joking when he asked about converting files to functions. His thought was to take a bunch of PowerShell scripts, turn them into a group of functions which could then be organized into a module. This is not that far-fetched. So I spent some time the last few days and came up with a PowerShell function to take an existing PowerShell script file and turn it into a PowerShell function.<\/p>\n\n\n\n<p>Practically speaking, there is no difference between running the code inside a function and a script. A function is at its core a scriptblock with a name that makes it easier to run. The code inside the scriptblock is no different than what you might have in a stand-alone script. Depending on your script, you could simply wrap your script code in a Function declaration. Of course, the best practice is for functions to do a single task and write a single type of object to the pipeline so you might still need to edit your resulting function. What I came up with was a PowerShell tool using the AST to accelerate the process.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Basic Example<\/h2>\n\n\n\n<p>Here is an extremely simple PowerShell script.<\/p>\n\n\n\n<pre title=\"SampleScript.ps1\" class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">#requires -version 3.0\n\n#this is a sample script\n\nWrite-Host \"this is a sample script that doesn't do anything but write a random number\" -ForegroundColor Yellow\n\nGet-Random -Minimum 1 -Maximum 1000<\/code><\/pre>\n\n\n\n<p>I want to turn this into a PowerShell function, so I'll use my new tool.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"576\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png\" alt=\"\" class=\"wp-image-8710\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png 960w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1-300x180.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1-768x461.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1-850x510.png 850w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/a><\/figure>\n\n\n\n<p>My Convert-ScriptToFunction command obviously needs the path to file. I also need to specify a name for the new function. The conversion generates a new function definition complete with comment-based help. The original script didn't have defined parameters, so the conversion defined them. If I wanted to save this to a file all I need to do is run the command and pipe to Out-File. I can then open the file in my scripting editor to polish it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Getting Requirements<\/h2>\n\n\n\n<p>You'll notice that the new code included #requires statements from the original file. I wrote a separate function, also using the AST to get any requirements. In my New-SystemReport.ps1 script,  I have these requirements.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">#requires -version 5.1\n#requires -module CimCmdlets<\/code><\/pre>\n\n\n\n<p>I can use this function to discover them.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Function Get-PSRequirements {\n    [cmdletbinding()]\n    Param(\n        [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]\n        [string]$Path\n    )\n    Begin {\n        Write-Verbose \"Starting $($MyInvocation.MyCommand)\"\n        New-Variable astTokens -Force\n        New-Variable astErr -Force\n    }\n    Process {\n        $Path = Convert-Path $path\n        Write-Verbose \"Processing $path\"\n\n        $AST = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$astTokens, [ref]$astErr)\n        #add the Path as a property\n        if ($ast.ScriptRequirements) {\n            $ast.ScriptRequirements | Add-Member -MemberType NoteProperty -Name \"Path\" -Value $Path-Force -PassThru\n        }\n        else {\n            Write-Verbose \"No requirements detected in $Path.\"\n        }\n    }\n    End {\n        Write-Verbose \"Ending $($MyInvocation.MyCommand)\"\n    }\n}<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/get-psrequirements.png\"><img loading=\"lazy\" decoding=\"async\" width=\"536\" height=\"252\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/get-psrequirements.png\" alt=\"\" class=\"wp-image-8711\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/get-psrequirements.png 536w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/get-psrequirements-300x141.png 300w\" sizes=\"auto, (max-width: 536px) 100vw, 536px\" \/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Comment-Based Help<\/h2>\n\n\n\n<p>I also wanted to be able to generate comment-based help if it wasn't already defined. Using the AST ParamBlock I create such a block. I'm always telling people to use the HelpMessage attribute, and if you do, it will be used for the .Parameter definition.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Function New-CommentHelp {\n    [cmdletbinding()]\n    [OutputType(\"string\")]\n    Param([System.Management.Automation.Language.ParamBlockAst]$ParamBlock)\n\n    $h = [System.Collections.Generic.List[string]]::new()\n    $h.Add(\"&lt;#\")\n    $h.Add(\"`t.Synopsis\")\n    $h.Add(\"`t  &lt;short description&gt;\")\n    $h.add(\"`t.Description\")\n    $h.add(\"`t  &lt;long description&gt;\")\n\n    foreach ($p in $ParamBlock.Parameters) {\n        $paramName = $p.name.variablepath.userpath\n        $h.Add(\"`t.Parameter $paramName\")\n        $paramHelp = $p.Attributes.namedArguments.where({ $_.argumentname -eq 'helpmessage' })\n        if ($paramHelp) {\n            $h.add(\"`t  $($paramHelp.argument.value)\")\n        }\n        else {\n            $h.Add(\"`t  &lt;enter a parameter description&gt;\")\n        }\n    }\n    $h.add(\"`t.Example\")\n    $h.Add(\"`t  PS C:\\&gt; $Name\")\n    $h.Add(\"`t  &lt;output and explanation&gt;\")\n    $h.Add(\"`t.Link\")\n    $h.Add(\"`t  &lt;enter a link reference&gt;\")\n    $h.Add(\"#&gt;\")\n\n    $h\n}\n<\/code><\/pre>\n\n\n\n<p>Here's a sample script.<\/p>\n\n\n\n<pre title=\"SampleScript3.ps1\" class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">#requires -version 3.0\n\n#this is a sample script\n\nParam (\n[Parameter(Position = 0,HelpMessage = \"How many numbers do you want?\")]\n[int]$Count = 1,\n[string]$Name,\n[switch]$Demo\n)\n\nWrite-Host \"this is a sample script that doesn't do anything but write a random number\" -ForegroundColor Yellow\n    \n#get numbers\n1..$count | Foreach-Object {\nGet-Random -Minimum 1 -Maximum 1000\n}\n    \nWrite-Host \"Ending script\" -ForegroundColor yellow\n\n#eof<\/code><\/pre>\n\n\n\n<p>Using my conversion function I get this output.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">#requires -version 3.0\n\n\n# Function exported from C:\\scripts\\SampleScript3.ps1\n\nFunction Invoke-Sample {\n\n&lt;#\n\t.Synopsis\n\t  &lt;short description&gt;\n\t.Description\n\t  &lt;long description&gt;\n\t.Parameter Count\n\t  How many numbers do you want?\n\t.Parameter Name\n\t  &lt;enter a parameter description&gt;\n\t.Parameter Demo\n\t  &lt;enter a parameter description&gt;\n\t.Example\n\t  PS C:\\&gt; Invoke-Sample\n\t  &lt;output and explanation&gt;\n\t.Link\n\t  &lt;enter a link reference&gt;\n#&gt;\n\n\n\t[cmdletbinding()]\n\tParam (\n\t[Parameter(Position = 0,HelpMessage = \"How many numbers do you want?\")]\n\t[int]$Count = 1,\n\t[string]$Name,\n\t[switch]$Demo\n\t)\n\n\nWrite-Host \"this is a sample script that doesn't do anything but write a random number\" -ForegroundColor Yellow\n1..$count | Foreach-Object {\nGet-Random -Minimum 1 -Maximum 1000\n}\nWrite-Host \"Ending script\" -ForegroundColor yellow\n\n} #close Invoke-Sample<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Function Names<\/h2>\n\n\n\n<p>Because I have to define a new function name, I wanted this to be as simple as possible. I use this helper function to format the name to the proper case. I'm assuming a Verb-Noun naming convention.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Function Format-FunctionName {\n    [cmdletbinding()]\n    Param (\n        [ValidateScript({\n        if ($_ -match \"^\\w+-\\w+$\") {\n            $true\n        }\n        else {\n            Throw \"Your function name should have a Verb-Noun naming convention\"\n            $False\n        }\n    })]\n    [string]$Name\n    )\n\n    $split = $name -split \"-\"\n    \"{0}{1}-{2}{3}\" -f $split[0][0].ToString().ToUpper(), $split[0].Substring(1).Tolower(),$split[1][0].ToString().ToUpper(), $split[1].Substring(1).ToLower()\n\n}<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/format-functionname.png\"><img loading=\"lazy\" decoding=\"async\" width=\"448\" height=\"72\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/format-functionname.png\" alt=\"\" class=\"wp-image-8713\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/format-functionname.png 448w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/format-functionname-300x48.png 300w\" sizes=\"auto, (max-width: 448px) 100vw, 448px\" \/><\/a><\/figure>\n\n\n\n<p>It isn't always perfect, especially if your noun is complex like this example. The function also doesn't validate that you are using a standard verb. However, I have an argument completer that will insert a standard verb.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Register-ArgumentCompleter -CommandName Convert-ScriptToFunction -ParameterName Name -ScriptBlock {\n    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)\n\n    #PowerShell code to populate $wordtoComplete\n    Get-Verb | Where-Object {$_.verb -match \"^$wordToComplete\"} |\n    ForEach-Object {\n        #this will autocomplete with Verb-\n        [System.Management.Automation.CompletionResult]::new(\"$($_.verb)-\", $_.verb, 'ParameterValue', $_.Group)\n    }\n}<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/verbcompletion.png\"><img loading=\"lazy\" decoding=\"async\" width=\"660\" height=\"95\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/verbcompletion.png\" alt=\"\" class=\"wp-image-8714\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/verbcompletion.png 660w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/verbcompletion-300x43.png 300w\" sizes=\"auto, (max-width: 660px) 100vw, 660px\" \/><\/a><\/figure>\n\n\n\n<p>All I need to do is begin typing the verb name and hit Tab. The completion will insert the verb and the dash. All I need to type is the noun.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Working with Output<\/h2>\n\n\n\n<p>My function does exactly what it says it does. It converts. It is up to you to decide how you want to use the output. You can pipe to Out-File or Set-Clipboard. But since I expect you will be immediately editing your output, I added a dynamic parameter (use my <a href=\"https:\/\/github.com\/jdhitsolutions\/PSScriptTools\/blob\/master\/docs\/New-PSDynamicParameterForm.md\" target=\"_blank\" rel=\"noreferrer noopener\">New-PSDynamicParameterForm<\/a> function) called ToEditor. This parameter will be defined if you run the function in the PowerShell ISE or VS Code. The output will be opened in a new, unsaved file.<\/p>\n\n\n\n<p>Again, here's the source file. These are script files I created merely to test my function.<\/p>\n\n\n\n<pre title=\"SampleScript4.ps1\" class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">#requires -version 4.0\n#requires -runasAdministrator\n\n#this is a sample script\n\nParam (\n[Parameter(Position = 0,HelpMessage = \"How many numbers do you want?\")]\n[ValidateRange(1,100)]\n[int]$Count = 1\n)\nDynamicParam {\n    #this is a sample dynamic parameter\n    If ($True) {\n\n    $paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary\n\n    # Defining parameter attributes\n    $attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]\n    $attributes = New-Object System.Management.Automation.ParameterAttribute\n    $attributes.ParameterSetName = '__AllParameterSets'\n    $attributeCollection.Add($attributes)\n\n    # Defining the runtime parameter\n    $dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('Demo', [String], $attributeCollection)\n    $paramDictionary.Add('Demo', $dynParam1)\n\n    return $paramDictionary\n} # end if\n} #end DynamicParam\n\nBegin {\n    Write-Host \"this is a sample script that doesn't do anything but write a random number\" -ForegroundColor Yellow\n}\nProcess {\n    #get numbers\n    1..$count | Foreach-Object {\n    Get-Random -Minimum 1 -Maximum 1000\n    }\n}\nEnd {\n    write-host \"Ending script\" -ForegroundColor yellow\n}\n#eof<\/code><\/pre>\n\n\n\n<p>I'll run this code in the integrated PowerShell terminal in VS Code to create a new file. The function will also get a new alias.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Convert-ScriptToFunction .\\SampleScript4.ps1 -Name Invoke-Sample -Alias ins -ToEditor<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/ToEditor.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"720\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/ToEditor-1024x720.png\" alt=\"\" class=\"wp-image-8718\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/ToEditor-1024x720.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/ToEditor-300x211.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/ToEditor-768x540.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/ToEditor-850x597.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/ToEditor.png 1524w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>I can then use VSCode to clean up the file such as formatting, expanding aliases, and converting tabs to spaces.  Then I can save the file. The output includes a reference to the original source file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Convert-ScriptToFunction<\/h2>\n\n\n\n<p>Here is the conversion function.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Function Convert-ScriptToFunction {\n    &lt;#\n    .Synopsis\n    Convert a script file to a PowerShell function.\n    .Description\n    This command takes the body of a script file and wraps it in a function\n    declaration. The command will insert missing elements like [cmdletbinding()]\n    and comment-based help. You will most likely need to edit and clean up the\n    result in your scripting editor.\n\n    If you run this command in the PowerShell ISE or the VS Code PowerShell\n    integrated terminal, you can use the dynamic parameter ToEditor to open a\n    new file with with the output. You can edit and save the file manually.\n\n    It is assumed that your script file is complete and without syntax errors.\n    .Parameter Path\n    Enter the path to your PowerShell script file.\n    .Parameter Name\n    What is the name of your new function? It should have a Verb-Noun name.\n    .Parameter Alias\n    Define an optional alias for your new function.\n    .Parameter ToEditor\n    If you run this command in the PowerShell ISE or the VS Code PowerShell\n    integrated terminal, you can use this dynamic parameter to open a new\n    file with with the output. You can edit and save the file manually.\n    .Example\n    PS C:\\> Convert-ScriptToFunction c:\\scripts\\Daily.ps1 -name Invoke-DailyTask | Set-Clipboard\n\n    Convert Daily.ps1 to a function called Invoke-DailyTask and copy the\n    results to the Windows clipboard. You can then paste the results into\n    scripting editor.\n    .Example\n    PS C:\\> Convert-ScriptToFunction c:\\scripts\\systemreport.ps1 -name New-SystemReport | Out-File c:\\scripts\\New-SystemReport.ps1\n\n    Convert the SystemReport.ps1 script file to a function called\n    New-SystemReport and save the results to a file.\n    .Example\n    PS C:\\> Convert-ScriptToFunction c:\\scripts\\systemreport.ps1 -name New-System -alias nsr | Tee-Object -variable f\n\n    Convert the script to a function called New-System and tee the output to $f.\n    This will also define an function alias of nsr.\n    #>\n    [cmdletbinding()]\n    [Outputtype(\"System.String\")]\n    [alias('csf')]\n    Param(\n        [Parameter(\n            Position = 0,\n            Mandatory,\n            ValueFromPipelineByPropertyName,\n            HelpMessage = \"Enter the path to your PowerShell script file.\"\n        )]\n        [ValidateScript({Test-Path $_ })]\n        [ValidatePattern(\"\\.ps1$\")]\n        [string]$Path,\n\n        [Parameter(\n            Position = 1,\n            Mandatory,\n            ValueFromPipelineByPropertyName,\n            HelpMessage = \"What is the name of your new function?\")]\n        [ValidateScript({\n            if ($_ -match \"^\\w+-\\w+$\") {\n                $true\n            }\n            else {\n                Throw \"Your function name should have a Verb-Noun naming convention\"\n                $False\n            }\n        })]\n        [string]$Name,\n\n        [Parameter(ValueFromPipelineByPropertyName,HelpMessage = \"Specify an optional alias for your new function. You can define multiple aliases separated by commas.\")]\n        [ValidateNotNullOrEmpty()]\n        [string[]]$Alias\n    )\n    DynamicParam {\n        &lt;#\n        If running this function in the PowerShell ISE or VS Code,\n        define a ToEditor switch parameter\n        #>\n        If ($host.name -match \"ISE|Code\") {\n\n            $paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary\n\n            # Defining parameter attributes\n            $attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]\n            $attributes = New-Object System.Management.Automation.ParameterAttribute\n            $attributes.ParameterSetName = '__AllParameterSets'\n            $attributeCollection.Add($attributes)\n\n            # Defining the runtime parameter\n            $dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('ToEditor', [Switch], $attributeCollection)\n            $paramDictionary.Add('ToEditor', $dynParam1)\n\n            return $paramDictionary\n        } # end if\n    } #end DynamicParam\n    Begin {\n        Write-Verbose \"Starting $($MyInvocation.MyCommand)\"\n        Write-Verbose \"Initializing\"\n        New-Variable astTokens -Force\n        New-Variable astErr -Force\n        $new = [System.Collections.Generic.list[string]]::new()\n    } #begin\n    Process {\n        #normalize\n        $Path = Convert-Path $path\n        $Name = Format-FunctionName $Name\n\n        Write-Verbose \"Processing $path\"\n        $AST = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$astTokens, [ref]$astErr)\n\n        if ($ast.extent) {\n            Write-Verbose \"Getting any comment based help\"\n            $ch = $astTokens | Where-Object { $_.kind -eq 'comment' -AND $_.text -match '\\.synopsis' }\n\n            if ($ast.ScriptRequirements) {\n                Write-Verbose \"Adding script requirements\"\n               if($ast.ScriptRequirements.RequiredPSVersion) {\n                   $new.Add(\"#requires -version $($ast.ScriptRequirements.RequiredPSVersion.ToString())\")\n               }\n               if ($ast.ScriptRequirements.RequiredModules) {\n                    Foreach ($m in $ast.ScriptRequirements.RequiredModules) {\n                        #test for version requirements\n                        $ver = $m.psobject.properties.where({$_.name -match 'version' -AND $_.value})\n                        if ($ver) {\n                            $new.Add(\"#requires -module @{ModuleName = '$($m.name)';$($ver.Name) = '$($ver.value)'}\")\n                        }\n                        else {\n                            $new.add(\"#requires -module $($m.Name)\")\n                        }\n                    }\n               }\n               if ($ast.ScriptRequirements.IsElevationRequired) {\n                    $new.Add(\"#requires -RunAsAdministrator\")\n               }\n               If ($ast.ScriptRequirements.requiredPSEditions) {\n                    $new.add(\"#requires -PSEdition $($ast.ScriptRequirements.requiredPSEditions)\")\n               }\n\n               $new.Add(\"`n\")\n            }\n            else {\n                Write-Verbose \"No script requirements found\"\n            }\n\n\n           $head = @\"\n# Function exported from $Path\n\nFunction $Name {\n\n\"@\n        $new.add($head)\n\n            if ($ch) {\n                $new.Add($ch.text)\n                $new.Add(\"`n\")\n            }\n            else {\n                Write-Verbose \"Generating new comment based help from parameters\"\n                New-CommentHelp -ParamBlock $ast.ParamBlock | Foreach-Object { $new.Add(\"$_\")}\n                $new.Add(\"`n\")\n            }\n\n            [regex]$rx = \"\\[cmdletbinding\\(.*\\)\\]\"\n            if ($rx.Ismatch($ast.Extent.text)) {\n                Write-Verbose \"Using existing cmdletbinding\"\n                #use the first match\n                $cb = $rx.match($ast.extent.text).Value\n                $new.Add(\"`t$cb\")\n            }\n            else {\n                 Write-Verbose \"Adding [cmdletbinding()]\"\n               $new.Add(\"`t[cmdletbinding()]\")\n            }\n\n           if ($alias) {\n                Write-Verbose \"Adding function alias definition $($alias -join ',')\"\n                $new.Add(\"`t[Alias('$($alias -join \"','\")')]\")\n           }\n            if ($ast.ParamBlock) {\n                Write-Verbose \"Adding defined Param() block\"\n                [void]($ast.ParamBlock.tostring().split(\"`n\").Foreach({$new.add(\"`t$_\")}) -join \"`n\")\n                $new.Add(\"`n\")\n            }\n            else {\n                Write-Verbose \"Adding Param() block\"\n                $new.add(\"`tParam()\")\n            }\n            if ($ast.DynamicParamBlock) {\n                #assumes no more than 1 dynamic parameter\n                Write-Verbose \"Adding dynamic parameters\"\n                [void]($ast.DynamicParamBlock.tostring().split(\"`n\").Foreach({$new.Add($_)}) -join \"`n\")\n            }\n\n            if ($ast.BeginBlock.Extent.text) {\n                Write-Verbose \"Adding defined Begin block\"\n                [void]($ast.BeginBlock.Extent.toString().split(\"`n\").Foreach({$new.Add($_)}) -join \"`n\")\n                $UseBPE = $True\n            }\n\n            if ($ast.ProcessBlock.Extent.text) {\n                Write-Verbose \"Adding defined Process block\"\n                [void]($ast.ProcessBlock.Extent.ToString().split(\"`n\").Foreach({$new.add($_) }) -join \"`n\")\n            }\n\n            if ($ast.EndBlock.Extent.text) {\n                if ($UseBPE) {\n                    Write-Verbose \"Adding opening End{} block\"\n                    $new.Add(\"`tEnd {\")\n                }\n                    Write-Verbose \"Adding the remaining code or defined endblock\"\n                    [void]($ast.Endblock.Statements.foreach({ $_.tostring() }).Foreach({ $new.Add($_)}))\n                if ($UseBPE) {\n                Write-Verbose \"Adding closing End {} block\"\n                    $new.Add(\"`t}\")\n                }\n            }\n            else {\n                $new.Add(\"End { }\")\n            }\n            Write-Verbose \"Closing the function\"\n           $new.Add( \"`n} #close $name\")\n\n           if ($PSBoundParameters.ContainsKey(\"ToEditor\")) {\n                Write-Verbose \"Opening result in editor\"\n                if ($host.name -match \"ISE\") {\n                    $newfile = $psise.CurrentPowerShellTab.Files.add()\n                    $newfile.Editor.InsertText(($new -join \"`n\"))\n                    $newfile.editor.select(1,1,1,1)\n                }\n                elseif ($host.name -match \"Code\") {\n                    $pseditor.Workspace.NewFile()\n                    $ctx = $pseditor.GetEditorContext()\n                    $ctx.CurrentFile.InsertText($new -join \"`n\")\n                }\n                else {\n                    $new -join \"`n\" | Set-Clipboard\n                    Write-Warning \"Can't detect the PowerShell ISE or VS Code. Output has been copied to the clipboard.\"\n                }\n        }\n        else {\n            Write-Verbose \"Writing output [$($new.count) lines] to the pipeline\"\n            $new -join \"`n\"\n        }\n        } #if ast found\n        else {\n            Write-Warning \"Failed to find a script body to convert to a function.\"\n        }\n\n    } #process\n    End {\n        Write-Verbose \"Ending $($MyInvocation.mycommand)\"\n    }\n}<\/code><\/pre>\n\n\n\n<p>The function assumes your script file is syntactically complete and without error. Understand that not every script file and can be converted into a PowerShell function that you can immediately use. The convert function is making the best effort possible. You should look at this as a tool to accelerate your scripting work.  I assume I will need to edit the new file. But this is a good start.<\/p>\n\n\n\n<p>I can take an old PowerShell script like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">#requires -version 3.0\n\n#Basic-HotFixReport.ps1\n\nParam([string[]]$Computername = $env:COMPUTERNAME)\n\n$ErrorActionPreference = \"SilentlyContinue\"\n\nGet-Hotfix -ComputerName $Computername | \nSelect-Object -Property PSComputername,HotFixID,Description,InstalledBy,InstalledOn,\n@{Name=\"Online\";Expression={$_.Caption}}<\/code><\/pre>\n\n\n\n<p>And create a new function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">csf .\\Basic-HotfixReport.ps1 -Name Get-HotFixReport -Alias ghfr | out-file c:\\scripts\\get-hotfixreport.ps1<\/code><\/pre>\n\n\n\n<p>My function has an alias of <em>csf<\/em>. After editing the file to bring it up-to-date, I have something like this.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">#requires -version 5.1\n\n# Function exported from C:\\scripts\\Basic-HotfixReport.ps1\n\nFunction Get-HotfixReport {\n\n    &lt;#\n    .Synopsis\n      Get a hotfix report\n    .Description\n      Use this command to get a report of installed hotfixes on a computer.\n    .Parameter Computername\n     Enter the name of a computer.\n    .Example\n\nPS C:\\scripts> Get-HotfixReport thinkp1 | format-table\n\n\nComputername HotFixID  Description InstalledBy         InstalledOn            Online\n------------ --------  ----------- -----------         -----------            ------\nTHINKP1      KB5006363 Update      NT AUTHORITY\\SYSTEM 11\/6\/2021 12:00:00 AM  http:\/\/support.microsoft.com\/?kbid=5006363\nTHINKP1      KB5004567 Update      NT AUTHORITY\\SYSTEM 7\/4\/2021 12:00:00 AM   https:\/\/support.microsoft.com\/help\/5004567\nTHINKP1      KB5008295 Update      NT AUTHORITY\\SYSTEM 11\/6\/2021 12:00:00 AM  https:\/\/support.microsoft.com\/help\/5008295\nTHINKP1      KB5007262 Update      NT AUTHORITY\\SYSTEM 11\/22\/2021 12:00:00 AM https:\/\/support.microsoft.com\/help\/5007262\nTHINKP1      KB5007414 Update      NT AUTHORITY\\SYSTEM 11\/13\/2021 12:00:00 AM\n\n    .Link\n      Get-HotFix\n#>\n\n    [cmdletbinding()]\n    [Alias('ghfr')]\n    Param([string[]]$Computername = $env:COMPUTERNAME)\n\n    Try {\n        Get-HotFix -ComputerName $Computername -ErrorAction Stop |\n        Select-Object -Property @{Name = \"Computername\"; Expression = { $_.CSName } },\n        HotFixID, Description, InstalledBy, InstalledOn,\n        @{Name = \"Online\"; Expression = { $_.Caption } }\n    }\n    Catch {\n        Throw $_\n    }\n\n} #close Get-Hotfixreport\n<\/code><\/pre>\n\n\n\n<p>I'd probably continue to refine the function.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building a Module<\/h2>\n\n\n\n<p>I'll wrap this up with a proof-of-concept. Assuming I know the script files I want to use and the function names I want to assign, I could use a PowerShell script to quickly build a module.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">#a proof of concept to convert scripts to a new module\n\n#dot source the conversion functions\n. C:\\scripts\\dev-scripttofunction.ps1\n\n$NewModuleName = \"PSMagic\"\n$Description = \"A sample module\"\n$ParentPath = \"C:\\work\"\n$path = New-Item -Name $NewModuleName -Path $ParentPath -ItemType Directory -Force\n\n#create the module structure\n\"docs\", \"functions\", \"en-us\", \"formats\" |\nForEach-Object { New-Item -Path $path -Name $_ -ItemType Directory }\n\n#file data\n$data = @\"\n\"Path\",\"Name\"\n\"C:\\scripts\\SampleScript.ps1\",\"Get-Foo\"\n\"C:\\scripts\\SampleScript2.ps1\",\"Set-Foo\"\n\"C:\\scripts\\SampleScript3.ps1\",\"Invoke-Foo\"\n\"C:\\scripts\\SampleScript4.ps1\",\"Remove-Foo\"\n\"C:\\scripts\\SampleScript5.ps1\",\"Test-Foo\"\n\"@\n\n$csv = $data | ConvertFrom-Csv\nforeach ($item in $csv) {\n    $out = Join-Path $path\\functions \"$($item.name).ps1\"\n    $item | Convert-ScriptToFunction |  Out-File -FilePath $out\n    Get-Item $out\n\n} #foreach item\n\n#create the root module\n$psm1 = @\"\n\nGet-Childitem `$psscriptroot\\functions\\*.ps1 |\nForeach-Object {\n. `$_.FullName\n}\n\n\"@\n\n$psm1 | Out-File \"$path\\$newmodulename.psm1\"\n\n#create the module manifest\n$splat = @{\n    Path                 = \"$path\\$newmodulename.psd1\"\n    RootModule           = \"$path\\$newmodulename.psm1\"\n    ModuleVersion        = \"0.1.0\"\n    Author               = \"Jeff Hicks\"\n    Description          = $Description\n    FunctionsToExport    = $csv.name\n    PowerShellVersion    = \"5.1\"\n    CompatiblePSEditions = \"Desktop\"\n}\nNew-ModuleManifest @splat\n\nGet-ChildItem $path<\/code><\/pre>\n\n\n\n<p>Running this script quickly builds my module.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-module.png\"><img loading=\"lazy\" decoding=\"async\" width=\"833\" height=\"646\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-module.png\" alt=\"\" class=\"wp-image-8720\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-module.png 833w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-module-300x233.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-module-768x596.png 768w\" sizes=\"auto, (max-width: 833px) 100vw, 833px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-modulecommands.png\"><img loading=\"lazy\" decoding=\"async\" width=\"956\" height=\"317\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-modulecommands.png\" alt=\"\" class=\"wp-image-8721\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-modulecommands.png 956w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-modulecommands-300x99.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-modulecommands-768x255.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/poc-modulecommands-850x282.png 850w\" sizes=\"auto, (max-width: 956px) 100vw, 956px\" \/><\/a><\/figure>\n\n\n\n<p>Naturally, there would still be editing and revisions, but this gives me a huge jump start on the process.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Next Steps<\/h2>\n\n\n\n<p>I hope some of you will give this code a spin and let me know what you think. Remember, it probably won't generate perfect PowerShell functions. I think I now have enough commands that I might bundle all of this together into a new module. In fact, I can use the tools themselves to build the module. Talk about meta!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently, I shared some PowerShell code to export a function to a file. It was a popular post. My friend Richard Hicks (no relation) thought we was joking when he asked about converting files to functions. His thought was to take a bunch of PowerShell scripts, turn them into a group of functions which could&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"New on the blog: Doing more with the #PowerShell AST","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[4,8],"tags":[447,224,534,540],"class_list":["post-8709","post","type-post","status-publish","format-standard","hentry","category-powershell","category-scripting","tag-ast","tag-function","tag-powershell","tag-scripting"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Converting PowerShell Scripts to Functions &#8226; The Lonely Administrator<\/title>\n<meta name=\"description\" content=\"The next step in working with the PowerShell AST is to convert a script file to a PowerShell function. Here&#039;s code to get you started.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Converting PowerShell Scripts to Functions &#8226; The Lonely Administrator\" \/>\n<meta property=\"og:description\" content=\"The next step in working with the PowerShell AST is to convert a script file to a PowerShell function. Here&#039;s code to get you started.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/\" \/>\n<meta property=\"og:site_name\" content=\"The Lonely Administrator\" \/>\n<meta property=\"article:published_time\" content=\"2021-12-10T17:28:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-12-10T17:28:43+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png\" \/>\n<meta name=\"author\" content=\"Jeffery Hicks\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:site\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeffery Hicks\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/\"},\"author\":{\"name\":\"Jeffery Hicks\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"headline\":\"Converting PowerShell Scripts to Functions\",\"datePublished\":\"2021-12-10T17:28:39+00:00\",\"dateModified\":\"2021-12-10T17:28:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/\"},\"wordCount\":946,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/12\\\/convert-script1.png\",\"keywords\":[\"AST\",\"Function\",\"PowerShell\",\"Scripting\"],\"articleSection\":[\"PowerShell\",\"Scripting\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/\",\"name\":\"Converting PowerShell Scripts to Functions &#8226; The Lonely Administrator\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/12\\\/convert-script1.png\",\"datePublished\":\"2021-12-10T17:28:39+00:00\",\"dateModified\":\"2021-12-10T17:28:43+00:00\",\"description\":\"The next step in working with the PowerShell AST is to convert a script file to a PowerShell function. Here's code to get you started.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/#primaryimage\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/12\\\/convert-script1.png\",\"contentUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/12\\\/convert-script1.png\",\"width\":960,\"height\":576},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8709\\\/converting-powershell-scripts-to-functions\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"PowerShell\",\"item\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/category\\\/powershell\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Converting PowerShell Scripts to Functions\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/\",\"name\":\"The Lonely Administrator\",\"description\":\"Practical Advice for the Automating IT Pro\",\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\",\"name\":\"Jeffery Hicks\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"caption\":\"Jeffery Hicks\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Converting PowerShell Scripts to Functions &#8226; The Lonely Administrator","description":"The next step in working with the PowerShell AST is to convert a script file to a PowerShell function. Here's code to get you started.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/","og_locale":"en_US","og_type":"article","og_title":"Converting PowerShell Scripts to Functions &#8226; The Lonely Administrator","og_description":"The next step in working with the PowerShell AST is to convert a script file to a PowerShell function. Here's code to get you started.","og_url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/","og_site_name":"The Lonely Administrator","article_published_time":"2021-12-10T17:28:39+00:00","article_modified_time":"2021-12-10T17:28:43+00:00","og_image":[{"url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png","type":"","width":"","height":""}],"author":"Jeffery Hicks","twitter_card":"summary_large_image","twitter_creator":"@JeffHicks","twitter_site":"@JeffHicks","twitter_misc":{"Written by":"Jeffery Hicks","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/#article","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/"},"author":{"name":"Jeffery Hicks","@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"headline":"Converting PowerShell Scripts to Functions","datePublished":"2021-12-10T17:28:39+00:00","dateModified":"2021-12-10T17:28:43+00:00","mainEntityOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/"},"wordCount":946,"commentCount":2,"publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png","keywords":["AST","Function","PowerShell","Scripting"],"articleSection":["PowerShell","Scripting"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/","url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/","name":"Converting PowerShell Scripts to Functions &#8226; The Lonely Administrator","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/#primaryimage"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png","datePublished":"2021-12-10T17:28:39+00:00","dateModified":"2021-12-10T17:28:43+00:00","description":"The next step in working with the PowerShell AST is to convert a script file to a PowerShell function. Here's code to get you started.","breadcrumb":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/#primaryimage","url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png","contentUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/convert-script1.png","width":960,"height":576},{"@type":"BreadcrumbList","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8709\/converting-powershell-scripts-to-functions\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"PowerShell","item":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},{"@type":"ListItem","position":2,"name":"Converting PowerShell Scripts to Functions"}]},{"@type":"WebSite","@id":"https:\/\/jdhitsolutions.com\/blog\/#website","url":"https:\/\/jdhitsolutions.com\/blog\/","name":"The Lonely Administrator","description":"Practical Advice for the Automating IT Pro","publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jdhitsolutions.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9","name":"Jeffery Hicks","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","caption":"Jeffery Hicks"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg"}}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":6348,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/6348\/building-more-powershell-functions\/","url_meta":{"origin":8709,"position":0},"title":"Building More PowerShell Functions","author":"Jeffery Hicks","date":"January 3, 2019","format":false,"excerpt":"In a recent post I discussed the the process you might go through in developing a PowerShell function. By the end, I not only had a new tool for my PowerShell toolbox, but I had a function outline that I could re-use. If you read the previous article then you\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2019\/01\/image_thumb-3.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2019\/01\/image_thumb-3.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2019\/01\/image_thumb-3.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2019\/01\/image_thumb-3.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":8666,"url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/8666\/friday-fun-powershell-console-editing\/","url_meta":{"origin":8709,"position":1},"title":"Friday Fun: PowerShell Console Editing","author":"Jeffery Hicks","date":"October 29, 2021","format":false,"excerpt":"The other day I read an interesting article on Adam Bertram's blog about editing files with a text editor in PowerShell. Naturally, the PowerShell wheels in my head began turning. While I was intrigued by some of the options in the article, I've in fact installed the Micro editor to\u2026","rel":"","context":"In &quot;Scripting&quot;","block_context":{"text":"Scripting","link":"https:\/\/jdhitsolutions.com\/blog\/category\/scripting\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/10\/nano-verbose.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/10\/nano-verbose.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/10\/nano-verbose.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/10\/nano-verbose.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1869,"url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/1869\/add-whatif-support-to-your-powershell-scripts\/","url_meta":{"origin":8709,"position":2},"title":"Add WhatIf Support to Your PowerShell Scripts","author":"Jeffery Hicks","date":"December 2, 2011","format":false,"excerpt":"In one of my recent articles for SMB IT, I included a PowerShell module. In the article I referenced that I included support for -Whatif in one of the functions. I was asked on Twitter to explain what I meant and how it works. So here goes. There are a\u2026","rel":"","context":"In &quot;PowerShell v2.0&quot;","block_context":{"text":"PowerShell v2.0","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell-v2-0\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":8724,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8724\/discovering-aliases-with-the-powershell-ast\/","url_meta":{"origin":8709,"position":3},"title":"Discovering Aliases with the PowerShell AST","author":"Jeffery Hicks","date":"December 15, 2021","format":false,"excerpt":"I've been working on a new PowerShell module that incorporates code from a few of my recent posts on converting PowerShell scripts and functions to files. I even whipped up a script, think of it as a meta-script, to create the module using the commands that I am adding to\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/find-alias-string.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/find-alias-string.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/find-alias-string.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/find-alias-string.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":418,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/418\/out-notepad\/","url_meta":{"origin":8709,"position":4},"title":"Out-Notepad","author":"Jeffery Hicks","date":"October 6, 2009","format":false,"excerpt":"Maybe this isn\u2019t the most earth shattering PowerShell function you\u2019ll ever come across, but it saves me a few keystrokes. There are times when I want to see the results of PowerShell expression but the console output is insufficient. I want to see the results in a text file opened\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":8741,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8741\/building-a-powershell-module-inception-style\/","url_meta":{"origin":8709,"position":5},"title":"Building a PowerShell Module Inception-Style","author":"Jeffery Hicks","date":"December 17, 2021","format":false,"excerpt":"Over the course of the last week or so, I've been sharing PowerShell functions and scripts for working with PowerShell functions and scripts. I showed PowerShell functions to export functions to a script file and code to convert scripts to functions It has all been very Inception-like. To wrap this\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/psinception.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8709","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=8709"}],"version-history":[{"count":0,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8709\/revisions"}],"wp:attachment":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=8709"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=8709"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=8709"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}