Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Profiling a Script

Posted on January 14, 2010January 14, 2010

Last summer, Ed Wilson was looking for help with a small part of the book he was finishing up, Windows PowerShell 2.0 Best Practices. The topic he was working on was, “How do I know this script is safe to run?” Which is a great question and one with greater significance as more administrators come to PowerShell and are tempted to run scripts created elsewhere while not having perhaps all the experience and training to fully appreciate what might happen. I offered some comments on some things I would do. I also decided to write a script (trust me) that an administrator could run that would analyze a PowerShell script and produce a report, or profile, for that script.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

The version I provided for the book was supposed to be clearly marked as a work in progress.  I’ve worked with it on and off since then and it is still a work in progress, but I wanted to offer up the latest version for Ed’s readers and for the PowerShell community.

#REQUIRES -VERSION 2.0


<#

.Synopsis

    This script will analyze a PowerShell script and create a script profile.

.Description

    This script analyze a given Powershell script and prepare a script profile.  Within this

    profile you will see what parameters are called in the analyzed script, where they are called,

    what PowerShell commands are executed, what functions are defined internally  and if the script

    is digitally signed.


    The output is written to the pipeline as a document so that you can save it to a file for review.

    If you use the -code parameter, the scripts contents will be included in the script profile.


    If the analyzed script calls another script, references another script via dot sourcing, or loads

    additional modules and snapins those references will NOT be analyzed, although you should see the

    lines of code in the script profile so that you can analyze and review further.

.Parameter Script

    The path to the .ps1 script file you want to profile.

.Parameter Code

    If specified, then the script's code will be displayed at the end of the profile.

.Example

    PS C:\> c:\scripts\get-scriptprofile foo.ps1 | Out-file FooProfile.txt

    Save the basic script profile to a text file.

.Example

    PS C:\> c:\scripts\get-scriptprofile foo.ps1 -code

    Display the script profile along with the code from foo.ps1

.Example

    PS C:\scripts> dir test*.ps1 | .\get-scriptprofile.ps1

    Build a script profile for every PowerShell script that begins with Test.

.Inputs

    Accepts strings as pipelined input

.Outputs

    [object]

.Link

   Get-Command

   Get-AuthenticodeSignature

   About_Functions

   About_Parameters

   About_Scripts


.Notes

 NAME:      Get-ScriptProfile.ps1

 VERSION:   1.2

 AUTHOR:    Jeffery Hicks  https://jdhitsolutions.com/blog

 LASTEDIT:  1/14/2010


 THIS IS A WORK IN PROGRESS...ESPECIALLY WITH POWERSHELL V2.0 SCRIPTS


 DISCLAIMER AND WARNING:

    THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY

    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE

    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

    TEST THOROUGHLY IN A NON-PRODUCTION ENVIRONMENT. IF YOU DON'T KNOW WHAT THIS

    SCRIPT WILL DO...DO NOT RUN IT!


 Microsoft PowerShell Source File -- Created with SAPIEN Technologies PrimalScript 2009


#>


[CmdletBinding()]


#define the parameters

Param (

    [Parameter(

     ValueFromPipeline=$True,

     Position=0,

     Mandatory=$True,

     HelpMessage="Enter a the path and name to a PowerShell script")]

     [String[]]$script,


    [Parameter(

     Mandatory=$False,

     HelpMessage="Specify if you want to see the script's code.")]

     [switch]$code

     )



Begin {


    $ErrorActionPreference="SilentlyContinue"


    #get command information for all current aliaes, functions, filters,cmdlets

    #and external scripts


    $cmdHash=@{}


    Get-Command -CommandType Alias,Function,Filter,ExternalScript,Cmdlet | foreach {

      $cmdHash.add($_.name,$_.CommandType)

      }


    #define some variables

    $Activity="Script Profiling"


} #end Begin Scriptblock


Process {

    If (-Not (Test-Path $script)) {

      Write-Warning "Cannot find $script."

      return

    }


    $fullname=(Get-Item $script).Fullname


    Write-Progress -Activity $Activity -Status "Analyzing $script" -CurrentOperation "Testing Signature" -PercentComplete 10

    write `n

    write $fullname.ToUpper()

    write ("Digital Signature: {0}" -f (Get-AuthenticodeSignature $script).status)


    Write-Progress -Activity $Activity -Status "Analyzing $script" -CurrentOperation "Parsing content" -PercentComplete 20


    $data=Get-Command $fullname

    $content=($data.scriptContents).Split("`n")


    #get any requires

    Write-Progress -Activity $Activity -Status "Analyzing $script" -CurrentOperation "Checking for requirements" -PercentComplete 30


    write `n

    write "`nRequires"

    write "--------"

    $content | where {$_.ToLower() -match "requires -"} | foreach {

     #parse the requirement and get everything to the left of the first dash

      $_.Substring($_.IndexOf("-")+1).ToLower()

    } |select -unique


    #strip out commented lines

    $content=$content | where {$_ -notmatch "^\s*#"}


    Write-Progress -Activity $Activity -Status "Analyzing $script" -CurrentOperation "Parsing Parameters" -PercentComplete 45

    write "`nParameters"

    write "----------"


    $params=@()

    $data.parameters.values  | foreach {

     $params+=$_.name

     $_ | select Name,ParameterType

     }


    write "`nParameter usage"

    write "---------------"

    $content | foreach {

     $line=$_

     $params | foreach {

       if ($_ -eq "?") {

          $key="\$_"

          [regex]$r="$key"

       }

       else {

          $key="$_"

         [regex]$r="\b$key\b"

       }

       if ($line -match $r) {

         write $line.Trim()

       } #end if

     } #end foreach param


     #select only unique lines to weed out

     #multiple matches for the same line

    } | select -Unique #end foreach line


    Write-Progress -Activity $Activity -Status "Analyzing $script" -CurrentOperation "Parsing defined functions" -PercentComplete 60


    write "`nInternally Defined Functions"

    write "----------------------------"

    $content | foreach {

      if ($_ -match "function \w*.\w*") {$matches.values}

    }


    Write-Progress -Activity $Activity -Status "Analyzing $script" -CurrentOperation "Parsing commands" -PercentComplete 75

    write "`nInvoked Commands"

    write "----------------"

    $content | foreach {

     $line=$_

     $cmdHash.keys | foreach {

     #escape the ? which is a special regex character

       if ($_ -eq "?") {

          $key="\$_"

          [regex]$r="$key"

       }

       else {

          $key="$_"

         [regex]$r="\b$key\b"

       }

       if ($line -match $r) {

         write $line.Trim()

       } #end if

     } #end foreach key


    } | select -unique #end foreach content line


    If ($code) {

        Write-Progress -Activity $Activity -Status "Analyzing $script" -CurrentOperation "Getting script contents" -PercentComplete 90

        #write script contents if -code was specified

        write "`nScript Contents"

        write "---------------"

        write $data.scriptcontents

    }

} #end Process script block


End {

    Write-Progress -Activity $Activity -Status "Done!" -CurrentOperation "Finished" -Completed -PercentComplete 100

} #end End script block


#end of script


The script, Get-ScriptProfile.ps1 requires PowerShell 2.0 and essentially is a giant string parser. It works pretty well with basic PowerShell 1.0 scripts. The basic syntax is to run the profile script and pass it a PowerShell script as a parameter.

PS C:\> c:\scripts\get-scriptprofile foo.ps1

The profiling script will report:

  • Whether the script is signed and the state of the signature
  • If a v2 script, any requirements
  • What parameters the script takes
  • The lines of the script where those parameters are used
  • The names of any internally defined functions
  • Any invoked PowerShell cmdlet, alias or function

All of this information is written to the pipeline more or less as a page but you can pipe the results to Out-File if you wish. Get-ScriptProfile also has a –code parameter which will append the script contents to the output.

The invoked commands section is perhaps the most useful. Within the script I use Get-Command to get all the currently available commands and then simply look for those commands throughout the script. If I was an admin analyzing a script, I’d be looking out for cmdlets that Stop or Remove.

This is far from a perfect and final tool, and perhaps it can’t be. The download version of the script has a short ToDo list. Many of the items are related to handling PowerShell 2.0 scripts.  If you have a suggestion or solution, I hope you’ll let me know.


Behind the PowerShell Pipeline
Download Get-ScriptProfile.ps1

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

1 thought on “Profiling a Script”

  1. Pingback: Tweets that mention Profiling a Script | The Lonely Administrator -- Topsy.com

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d