Categories
How To Powershell Tech

Error Trapping in Powershell With a Windows Popup

If you’re old school like me and you write Powershell scripts using ISE or Notepad++, it gets a little tricky to troubleshoot issues with your scripts when you are dealing with many variables.

When I’m writing long complicated scripts, I like to put some useful error trapping in to show me where my script is failing and why. In this blog I will show you the basics of error trapping and then show how to make a popup window that will show the error message and the variables that were used at a particular point in your script’s execution.

Let’s say you have a script with some variables and you are trying to do some mathematical operations on those variables:

$VARIABLE1 = 10
$VARIABLE2 = 0

$RESULT = $VARIABLE1 / $VARIABLE2

Write-host $RESULT 

It’s pretty obvious in this simple script why you are getting an error, the variable you are trying to divide by has a value of zero. Dividing by zero is not defined in mathematics, so it errors out.

This is helpful if you are running your script in ISE, but if you’re running the stand-alone .ps1 file on a server, it’s going to open a command window, error out and close before you can see what’s going on. You could put a Read-Host command at the end of the script to keep the command window open until you press enter on the keyboard. This will at least give you time to read the error message before the window closes.

Simple scripts like this are very easy to troubleshoot, but let’s say you have a bunch of variables that you are doing operations on and the final result of those is causing your script to error out. Powershell isn’t going to give you much useful information in that case and you’ll have to mine it out the information you need yourself.

I like to use the Try{…}Catch{…} feature of Powershell along with a Windows Popup to capture the error and variables and present them to me in a GUI popup window.

The Try{…}Catch{…} feature in Powershell is much like other coding languages, it lets you wrap your code in a Try statement, and then “Catch” the error information generated, assuming there is an error.

The general form is this:

Try{
	
Some Powershell code

}Catch{"Do something if there is an error"}  

The errors are caught in a field called $_.Exception.Message which you can output to the console with a write-host command or to a popup window. If you leave the Catch statement blank it will capture the error, but it won’t do anything with it, so you will not see any error output.

I like to put a windows Message box in the Catch Statement which will show me the error message and the variables used that caused the message. You can do this with the [System.Windows.MessageBox]::Show command.

Here’s an example:

Try{

  $VARIABLE1 = 10
  $VARIABLE2 = 0

  $RESULT = $VARIABLE1 / $VARIABLE2

   }Catch{[System.Windows.MessageBox]:: Show($_.Exception.Message +"  VARIABLE1 = " +  $VARIABLE1 + "  VARIABLE2 = " + $VARIABLE2 +  "  RESULT = " + $RESULT) }

If you run this, it will pop up a window with the error message and the variable values at that point in the script:

Be sure to leave plenty of space around your output text “  VARIABLE1 =  “ so Windows doesn’t cram all the words together in the popup.

This error trapping method is helpful when are trying to troubleshoot a long script and you aren’t sure what values your variables are getting at a particular point in the script. Obviously, you could also output the information to a file or do a write-host to output the info to the command window, but I like this method because it’s quick and clean and once you are done troubleshooting the script and ready to deploy it, you can modify the message so that it will continue to trap errors and show users any error message that a particular part of the script is generating. This is useful if you are writing the script for other users to run and you are unable to anticipate every scenario that will arise.

One thing I should point out about the Try{…}Catch{..} command, it’s only useful if it’s put in strategic points in your script. You could put the Try at the beginning of your script and the Catch at the very end, but it’s probably not going to give you much useful information in a very long script, especially if your script is capable of generating multiple errors.

In a later blog I’ll show you how to put the line number of the error in your popup for better troubleshooting.

Categories
How To Powershell Tech

Backup and clear all Windows Event Logs using Powershell

Whenever I’m building a new server, PC or Windows VM, I like to clear all the event logs before turning it over to the end users. This way if any issues occur, I’m not trying to filter through thousands of useless event logs that occurred during the build process. There are a myriad of event logs to pour over now days in the Windows Event Viewer. There are your standard Windows Logs, App, Security, Setup, System:

Then there are the Applications and Services Logs:

There are the Microsoft Logs, Hardware Event logs and it goes on. If you want to quickly backup and clear all the logs, unfortunately the event log GUI doesn’t give you an easy way to do this. I wrote this Powershell script to accomplish this task in one fell swoop.  

$LOGS = wevtutil el
$PATH = Test-path C:\backup
if ($PATH -eq $false)
{
    New-Item -Path c:\backup -ItemType directory
}

Foreach($LOG in $LOGS)
{
           
    wevtutil epl $log c:\backup\$log.evtx
    
    wevtutil cl $log     
    
} 

The script will create a backup folder on the C:\ drive if it doesn’t exist (change this path to suit your needs). It will then enumerate all the Event Logs, back each one up to the backup folder and then clear it before moving on to the next log.

Before:

After running script:

The events that are 68KB are the empty ones.

There are a few caveats to running this. One, you will see errors when you run this script, it will try to enumerate logs that don’t exist. Because wevtutil is not a native Powershell command, there is no error suppression available. And Try{} Catch{} won’t work either. Just ignore the errors. Another thing to keep in mind, it will backup logs whether they have data or not. You could probably add some query logic to only backup logs that have data, but you’re probably never going to use these logs anyway. At least you can tell your boss you backed them all up before you deleted them.

Categories
Citrix How To Powershell Tech

Configuring RDS Licensing on a Client Machine

This article shows how to configure a client machine to point to specific Remote Desktop Licensing servers. A client machine will need to access an Remote Desktop Services (RDS) license server if it brokering more than two remote connections at a time. This includes Citrix Virtual Apps (formerly known as Xenapp) as Citrix connections also require a RDS license for remote connections.

First off this can and should be done through Active Directory Group Policy. The example I show below uses the local group policy editor, but the settings are the same whether you are using an AD GPO or local GPO.

Open up the Local Group Policy Editor.
Go to Start Run > gpedit.msc
Navigate to Computer Configuration\Administrative Templates\Windows Components\Remote Desktop Services\Licensing.

There are two settings that must be configured:
1: Use the specified Remote Desktop license servers
2: Set the Remote Desktop Licensing Mode

Open up the first one “Use the specified Remote Desktop license servers”

Check the Radio Button next to “Enabled” then input one or more license servers into the field “License servers to use:” Although not necessary, it’s best to put the FQDN for the server(s). Separate the server names by commas if using more than one. (Note: don’t worry about every license server having the particular OS version of license you need. The system will check each license server in the list until it finds the proper license. It’s best to put all the license servers in your environment into the list as administrators will most likely be updating the license servers over time.)

Click Ok when finished and open up the second setting “Set the Remote Desktop Licensing Mode”Check the Radio Button next to “Enabled” and then choose the license type from the dropdown. If you don’t know which license type to use, check with the person who administers the license servers.

Click Ok.

Now open up a command prompt as administrator and type gpupdate /force to update the policies.

If you are configuring this through Active Directory GPO, then you would link the GPO to the OU in Active Directory where the particular machine account of the machine needing licenses lives.

Categories
How To Powershell Tech

Add a “Are You Sure” popup to your Powershell scripts

In a previous post “Customize the output of Powershell Gridview”, I showed how to create a Gridview script that would allow you to select files by type and delete them. In this post I will show how to add a popup window that will allow you to confirm your choice to delete. In that post I placed a series of files of different types in my C:\temp folder and then used Out-GridView with the -passthrough option to select certain files and delete them.

But what if you are like me and too quick to click buttons and accidentally do stuff you didn’t want to do? That’s where a confirmation popup comes in handy and I use them a lot in my code. Here is the code from the previous post:

$FILEPATH = “C:\TEMP”
Set-Location -Path $FILEPATH
$FILES= Get-childitem $FILEPATH |
SELECT Name, @{Name=”Type”;
Expression={
if($_.name -like ‘.doc’) {“Word Document”} if($_.name -like ‘.txt’) {“Text Document”}
if($_.name -like ‘*.pdf’) {“Adobe Document”}
}
} | Out-GridView -PassThru -Title “Select Files For Deletion”
Foreach ($SELECTION in $FILES)
{
Remove-Item $SELECTION.name
}

The basic rundown of this script is that it uses the Get-childitem commandlet to retrieve the list of files in the c:\temp folder, then uses the Expression command with an IF statement to create a column with file types. Then it uses the -passthrough option of Out-GridView to pass the filenames selected through to a Remove-Item command which deletes the files.
First we will add some code to the beginning of the script:
Add-Type -AssemblyName System.Windows.Forms
This will add the proper .NET Code class to the Powershell session.
Next will add some code between the Out-GridView code and the Remove-Item If statement. This will cause a window with yes/no buttons to popup before deleting the files. The button “answer” is passed to the variable $OUTPUT. If the value of $OUTPUT is “YES” then the code to delete the files (which will be placed inside this IF statement) will execute, otherwise the popup window will close and nothing will happen:

$OUTPUT=[System.Windows.Forms.MessageBox]::Show("Thomas, you are about to delete some important files, are you really, really sure you want to do this? Come on man!!!" , "WARNING!!!" , 4)
if ($OUTPUT -eq "YES" )
{
           Foreach ($SELECTION in $FILES)
          {
                          Remove-Item $SELECTION.name
           }
}

Now when you execute the script, select some files for deletion and click ok, you will get this popup window:

Here is the complete code:

Add-Type -AssemblyName System.Windows.Forms
$FILEPATH = “C:\TEMP”
Set-Location -Path $FILEPATH
$FILES= Get-childitem $FILEPATH |
SELECT Name, @{Name=”Type”;
Expression={
if($_.name -like ‘.doc’) {“Word Document”} if($_.name -like ‘.txt’) {“Text Document”}
if($_.name -like ‘*.pdf’) {“Adobe Document”}
}
} | Out-GridView -PassThru -Title “Select Files For Deletion”
$OUTPUT=[System.Windows.Forms.MessageBox]::Show("Thomas, you are about to delete some important files, are you really, really sure you want to do this? Come on man!!!" , "WARNING!!!" , 4)
if ($OUTPUT -eq "YES" )
{
           Foreach ($SELECTION in $FILES)
          {
                          Remove-Item $SELECTION.name
           }
}

Categories
How To Powershell Tech

Customize the output of Powershell Gridview.

Powershell – Customizing Gridview

The Powershell Out-GridView commandlet is a very useful visual aid for Powershell coders to get output into a graphical window for quickly viewing and sorting data retrieved from Powershell commands. It’s out-of-the-box functionality is somewhat limited however, so in this post I will show how to customize some of the output to make it more useful.

The Out-GridView command simply takes output from a Powershell command and pipes it to a spreadsheet-like window. For instance if you type the command:

Get-process | Out-GridView

You will get something like this:

Lets start by updating the Title of the Gridview window. We do this with the Title option: Get-process | Out-GridView -Title “My Computer’s Processes” Now the Title looks a little more professional:

Next let’s change the column names to be more useful. Some people may not know what NPM(K) means. We can change the column names by using the SELECT Statement similar to SQL along with the Expression command. The SELECT Statement tells Powershell which columns of data you want to present to Gridview. For instance let’s say you only want to see the ProcessName and CPU cycles. You would use this command:
Get-process | SELECT ProcessName,CPU | Out-GridView
Then you would get the following:

If you want to change the name of one or more columns you would use the SELECT command along with the Expressions command. For instance maybe you want to change “ProcessName” to just “Process” and “NPM(k)” to “Non-Paged Memory”. You would do so in the following way using the SELECT command along with expression:

Get-Process | SELECT @{Name="Process";Expression={$_.ProcessName}}, @{Name="Non Paged Memory"; Expression={$_.NPM}} | Out-GridView

This gives you a much cleaner looking Gridview:

Next we’ll add some rounding to the CPU column to clean up the numbers, we probably don’t need to know the numbers down to the 1/100,000.

This image has an empty alt attribute; its file name is image.png

We do this by adding the [MATH::ROUND] Command along with a number telling Powershell how many decimals to round to. In our case we will use “0” to round to the nearest whole number:
@{Name=”CPU”; Expression={[math]::round( $_.CPU , 0 )}}
Our output now looks like this:

But if we’re troubleshooting a performance issue we may want to sort by memory or CPU. You can do this in Gridview by simply clicking the column headers, however you can also do it in the script. You must sort the data however, before it is presented to the Gridview. You do this by piping the data to the Sort-Object command:
Sort-object CPU -Descending
Here’s the entire line of code we’ve built so far:

Get-Process | SELECT @{Name="Process";Expression={$_.ProcessName}}, @{Name="Non Paged Memory"; Expression={$_.NPM}}, @{Name="CPU"; Expression={[math]::round( $_.CPU,0 )}} | Sort-object CPU -Descending | Out-GridView -Title "My Computer's Processes"

Now let’s say you want to do something useful with the data in the Gridview. You can select rows in the grid and pass the data through to another command using the passthrough command. You must assign the output of the Get command to a variable and then use the passthrough option of Out-GridView like so:
$SELECTION = Get-Process | Out-GridView -passthrough
This allows you to highlight one or multiple rows using your mouse and the CTRL key and once you click ok on your Gridview window, Powershell will pass the data in your selection to the variable you assigned where it can be parsed and used in the next command in your script.

Let’s start fresh with a new example so we can use the -passthrough option and also highlight some other things you can do with the Gridview window. We will build on what we learned so far.

In this example, I have a set of files of different types in a folder. I’m going to use the Get-childitem command to get a list of those files and then add a new column with custom data in it for sorting the file types. Here is a look at the files in the folder:

If we assign the file path to a variable and then do a Get-childitem using that variable and output to Gridview we will get something like this:

$FILEPATH = "C:\TEMP"
Set-Location -Path $FILEPATH
Get-childitem $FILEPATH | Out-GridView

I went ahead and added another line of code Set-Location -Path $FILEPATH. This will set the working directory of the script to the folder we are interested in. You’ll see why later.

We’ll use the knowledge we gained earlier in this post and cleanup the column names using our Expression command from earlier add a window title and put the columns in a more comfortable order:

$FILEPATH = "C:\TEMP"
Set-Location -Path $FILEPATH
Get-childitem $FILEPATH | Select @{Name="File Name";Expression={$_.Name}}, @{Name="Last Write Time";Expression={$_.LastWriteTime}}| Out-GridView -Title "Working Files"

This will give you a window like this:

It looks good, but what if you wanted to sort by file type. File type is not an available data field returned by the Get-childitem command. What we can do is extend our Expression command to use an if statement and create a new column which contains the file type.

$FILEPATH = "C:\TEMP"
Set-Location -Path $FILEPATH
$FILES= Get-childitem $FILEPATH |
SELECT Name, @{Name="Type";
Expression={
if($_.name -like '*.doc') {"Word Document"} 
if($_.name -like '*.txt') {"Text Document"}
if($_.name -like '*.pdf') {"Adobe Document"}
}
} | Out-GridView -title "Working Files"

That’s all fine and dandy, but what if want to do something useful with the files returned, like deleting them? That’s where the passthrough command comes in. We will add the rest of the code to pass the information selected through to a variable and use the foreach command along with the remove-item command to delete the files selected. We’ll also update the title to something more appropriate. Here is the complete code:

$FILEPATH = "C:\TEMP"
Set-Location -Path $FILEPATH
$FILES= Get-childitem $FILEPATH |
SELECT Name, @{Name="Type";
Expression={
if($_.name -like '.doc') {"Word Document"} if($_.name -like '.txt') {"Text Document"}
if($_.name -like '*.pdf') {"Adobe Document"}
}
} | Out-GridView -PassThru -Title "Select Files For Deletion"
Foreach ($SELECTION in $FILES)
{
Remove-Item $SELECTION.name
}

Now when you highlight the files and click ok, they will be deleted:

I clicked Ok and ran the script again and as you can see the files are gone:

In a later post I will explain how to put an “Are You Sure” button in your delete command.