All the basics for running Scripts in Powershell

Basics for Running Scripts in PowerShell

Once you start creating and writing PowerShell commands, it can become quite troublesome to move them to a server or another machine, specially when the commands are long, complex, or they define functions intended to be reusable.

Let's take the following example

Below, we see a screenshot of a "one-liner" command to find the location of the ErrorLog on a SQL Server:


The Actual script looks like this:

((Get-Item -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL??*\MSSQLServer\parameters" | Select-Object -ExpandProperty property | ForEach-Object { New-Object psobject -Property @{"property"=$_; "Value" = (Get-ItemProperty -Path $RegKey -Name $_).$_}} | Where-Object {$_.Value -like "-e*"}).Value).Replace("-e","")

Wouldn't be difficult to type that in? or even to cut&paste into a console?

The obvious solution is to place them in a file. A file with a list of commands is sometimes called a script, and we'll use the term interchangeable in this article. PowerShell scripts are generally named <Verb>-<Noun>.ps1  (More Best Practices here )

Example:  Get-SQLParam.ps1

$RegKey = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL??*\MSSQLServer\parameters"

$Param = Get-Item $RegKey | Select-Object -ExpandProperty property |
 ForEach-Object {New-Object psobject -Property @{"property"=$_; "Value" = (Get-ItemProperty -Path $RegKey -Name $_).$_}

To call the file, while in the same directory, use the notation:

  .\Get-SQLParam.ps1 or . .\Get-SQLParam.ps1 , depending if you want to dot-source the file.


Setting Execution Policies

If you are an Administrator on a server, you should be able to run all commands on PowerShell directly, however, if you want to run commands saved on a file, you'll need to check if the execution policy allows it.

To check what is the current execution policy:


PowerShell has a number of execution policies that defines what files or scripts are allowed to run:

  •     Restricted: Default execution policy, does not run scripts, interactive commands only.
  •     All Signed: Runs scripts; all scripts and configuration files must be signed by a publisher that you trust; opens you to the risk of running signed (but malicious) scripts, after confirming that you trust the publisher.
  •     Remote Signed: Local scripts run without signature. Any scripts saved in an UNC path and downloaded scripts need a digital signature. Scripts saved locally are fine.
  •     Unrestricted:Runs scripts; all scripts and configuration files downloaded from communication applications such as Microsoft Outlook, Internet Explorer, Outlook Express and Windows Messenger run after confirming that you understand the file originated from the Internet; no digital signature is required; opens you to the risk of running unsigned, malicious scripts downloaded from these applications

See this link for more information regarding Execution Policies.

The default execution policy one is Restricted.  Attempting to run a script under this policy will yield an error:

File <path to the file> cannot be loaded because the execution of scripts is disabled on this system.

Changing the Execution Policy to "unrestricted" will certainly let you run all your scripts, however it will leave the system exposed because it might allow potential malware run scripts stored remotely. Strongly not recommended.

The most secure setting is "All Signed", but it's not practical when visiting one server and that's it. ( Click here to learn how to sign your scripts)

A a happy compromise regarding security is using RemoteSigned, where you can run your own scripts stored locally, but not those stored in a network location. It even allows you to run scripts on a remote system, as long as the scripts are stored local to your console.

To change the Execution Policy, run:

Set-ExecutionPolicy RemoteSigned -Force

The "-Force" parameter suppresses the confirmation screen.

In the screenshot below we see what happen when you try to run a script and the policy is set to "restricted". Next we change the policy and we are able to run our script:


There are a number of ways to bypass the Execution Policy, but it will NOT set global variables or define functions. In other words, if you define a function or variables on a script and call it using the method below, it will not be available for the current session (the equivalent of not sourcing your script, more on that below).
You might want to bypass the policy when your script simply outputs information to the host and you do not need variables or functions later on.  In our example, we are simply outputting registry key values corresponding to the SQL Server start up parameters, so it's a good candidate to run without changing the execution policies:

	Get-Content .\Get-SQLParam.ps1 | PowerShell.exe -noprofile -

Please note the <dash><noprofile><space><dash> syntax.


More about these methods in this link


Running Scripts

OK, so we are ready to run a file with commands, known as a PoweShell script.

 There are two ways of running the commands in a file. You either source the file, or you don't.

If you define a variable or function within a script, and are not interested in bringing that variable or function over to the current session, you do not need to source the script.

Per example, in the screenshot below, we first show the content of the file, and you can tell that we have stored our results, an object, in the $Param variable.

Next we run the script by typing .\Get-SQLParam.ps1  . After we execute the script, we check the value of $Param and see that it's empty.  Therefore, the object stored on $Param did not come to the our session, even though the script did output the needed information.


On the other hand, if you define a variable or function within a file, and want to bring over a variable or function, you source the script.

Per example, in the screenshot below we again first list the content of the script (we don't need to "Get-Content" every time but we do it for demonstration purposes), then run the sourced script, by typing dot-space-dot-slash-name:  . .\Get-SQLParam.ps1

After we execute the script, we check the value of $Param and see that is not empty this time: it has the value assigned within the script.


Since in our script we actually defined a PowerShell Custom Object, and we are sourcing the script, we are bringing over the entire object to our current session:


First, we show that the variable $Param is empty. Next we run a dot-sourced script. Then we show that the variable $Param is an actual PS Object.

Please note that variables defined inside a function will not be available, unless the function specifically returns such variables, as we explain below.

Running Functions defined on a Script

OK, let's transform our script into a function:

Function Get-SQLParam {
$RegKey = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL??*\MSSQLServer\parameters"

$Param = Get-Item $RegKey | Select-Object -ExpandProperty property |
 ForEach-Object {
                New-Object psobject -Property @{“property”=$_; “Value” = (Get-ItemProperty -Path $RegKey -Name $_).$_}

Notice that we changed $Param.Value for $Param because we want the script to return an object, not a string (see best practices link above)


Below, we first list the content of the script, where you can see that now it is a function (again, no need for this step, but it's helpful for demonstration purposes)

Next we run the script, but do not source it. We will attempt to run the function defined inside the script, and we will encounter an error saying that the cmdlet is not recognized. To be expected when we do not source a script when running it.


We received the error because the function was defined inside the script but never sourced, therefore it does not exists within our session.

If we run the script again, but this time we source it, we will see that now the function is available for us to use:


Notice that this time we run (Get-SQLParam).Value because we are only interested in the "Value" field of the PowerShell object defined within the function.

Additionally, because the object $Param was defined inside the function, but it was not capture nor returned, then it's not available for the current session.

If you would like the entire object available for the current session, we can do the following:


Here we assign the output of the Function to a variable $Results. Hence, storing the object on that variable for later use.


To Source or to Not Source

When is important to source a script?

If you have functions defined inside a file or create objects that you need in your current session, you must source the script.

Whenever you are running scripts with the intention to simply output information to the console, you may not source your scripts.



Leave a Reply

Your email address will not be published. Required fields are marked *