Array values don't show up during debugging

Post feature requests, product enhancement ideas, and other product-specific suggestions here. Do not post bug reports.
Forum rules
Do not post any licensing information in this forum.
Locked
User avatar
C3PO_R2D2
Posts: 22
Joined: Sun Mar 03, 2013 12:33 pm

Array values don't show up during debugging

Post by C3PO_R2D2 » Tue Apr 08, 2014 7:21 am

Well, I thought this issue:

http://www.sapien.com/forums/viewtopic.php?f=9&t=6578

was going to be solved with the Powershell Studio 2014 product, but it's still the same.
Isn't this really anoying for anyone?

What I find a bit weird, is the fact that when you hoover your mouse over the array in the script (during debugging), a popup appears with (part of) the info, but in the Variables pane, this info isn't showing up nowhere...

User avatar
Bosparan
Posts: 282
Joined: Sun Mar 03, 2013 12:45 pm

Re: Array values don't show up during debugging

Post by Bosparan » Wed Apr 09, 2014 12:12 am

Hi C3PO,

actually, I do find it mildly irritating. Since however I've long since moved to modular design and interactive debugging in the shell it has less of an impact on me as it had in the old days.
Doing the debugging in the shell makes it a lot easier to interact with a state and inspect variables, since I have the full information manipulation capability of the Powershell at my fingertips (plus a few custom tools).

To do this, do ...
... Create a development Script File (the file you devlop in).
... Modify your profile to automatically import / dotsource that file.
... Code your script as a series of functions (a good practice anyway).
... Declare the scope of every variable you want to inspect as "script", so you'll be able to inspect it outside of the function.
... Start Powershell and have fun :)

Cheers,
Bosparan

User avatar
C3PO_R2D2
Posts: 22
Joined: Sun Mar 03, 2013 12:33 pm

Re: Array values don't show up during debugging

Post by C3PO_R2D2 » Wed Apr 09, 2014 12:29 am

Hello Bosporan,

thanks a lot for your interesting reply.
Do you have the time to explain me a bit more your coding techniques, as I'm just a simple system engineering occasionaly using Powershell.
I don't understand some of your techniques:


- Modify your profile to automatically import / dotsource that file.
- Declare the scope of every variable you want to inspect as "script", so you'll be able to inspect it outside of the function



Thanks a lot for your reply :D

User avatar
Bosparan
Posts: 282
Joined: Sun Mar 03, 2013 12:45 pm

Re: Array values don't show up during debugging

Post by Bosparan » Wed Apr 09, 2014 1:03 pm

Hi C3PO,

I'll be most happy to explain some of it :)
Sorry if some of the information is a bit redundant, I like being thorough.

Powershell Profile
Your Powershell profile is a script in your windows Profile that is run, whenever you run Powershell.
You can edit it by typing this in the shell:
PowerShell Code
Double-click the code block to select all.
notepad $profile
If it doesn't exist yet, it will be created.

So, whatever you put in there, you have available in your Powershell session. Let's give it a try and put this into it:
PowerShell Code
Double-click the code block to select all.
Function Restart-Shell
{
	Start-Process powershell.exe -ArgumentList @("-NoExit","-NoLogo",'-WindowStyle "Normal"')
	exit
}
Save your profile file, and start a new powershell console. It should now have the function "Restart-Shell" available, just like any other command.

Incidentally, Restart-Shell is probably the single most useful function I ever wrote (Mine is a bit more elaborate, but I'm a bit reluctant about posting the ~2000 lines of code in a forum post. This will serve both as being a simple example and being vastly useful). Now, everytime you want to load an update to something you want to test, all you'll have to do is type restart-shell and get started trying out the changes.

Dotsourcing and what it does
For this to work, you will always develop your scripts in a single script file (in PSS of course), and copy it somewhere else once it does what you want. Let's assume for the purpose of our discussion that this place happens to be "H:\Data\Scripts\Files\Development.ps1"

Then all you'd have to do is put this line in your profile:
PowerShell Code
Double-click the code block to select all.
. "H:\Data\Scripts\Files\Development.ps1"
(As a good practice, I recommend ordering things in your profile in ascending order of priority to you. If you accidentally happen to define the same function / variable twice, the last one loaded will overwrite the previous one)

Now everytime you start your powershell console, it will load your profile - including the function Restart-Shell - and when it reaches the above line, it will continue loading everything in Development.ps1. Once done with that it will continue loading the rest of your profile.

Developing and Debugging
First of all, let's start of with a sample script:
PowerShell Code
Double-click the code block to select all.
#region Runtime Parameters

# Write your parameters here
$ComputerName = "SRV01"
#endregion

#region Runtime Execution
Function DoIt
{
	# Here you call the functions you define later in the script. This basically is the process of your script, where you can read what it is doing in what order
	
	$Test = Test-ComputerConnectivity $ComputerName
	if ($Test.Success -eq $false)
	{
		$Test | Export-Csv "H:\Output\script.log"
	}
	else
	{
		Set-ComputerTask $ComputerName | Export-Csv "H:\Output\script.log"
	}
}
#endregion

#region Functions

# this is where the functions go

Function Test-ComputerConnectivity
{
	Param
	(
		# This is where the parameters of the function go
		[Parameter(Mandatory = $True, Position = 0)]
		[string]
		$ComputerName
	)
	
	# Do something
	$wmi = Get-WmiObject -Class win32_NetworkAdapterConfiguration -ComputerName $ComputerName -ErrorAction 'SilentlyContinue'
	$script:Debug1 = ($wmi -ne $null)
	
	# Do Some more
	# ...
	
	# report results
	Return $Results
}

Function Set-ComputerTask
{
	Param
	(
		# This is where the parameters of the function go
		[Parameter(Mandatory = $True, Position = 0)]
		[string]
		$ComputerName
	)
	
	# Do something
	
	# report results
	Return $Results
}
#endregion

# and finally, you actually launch it
DoIt
This is pretty much my default structure for a script:
- First the Comments (which I omitted)
- then the parameters (either static parameters, a Param Block or the section where I read it from the computer somehow).
- Then the function DoIt which is where I put the pieces together.
- Then the various functions doing part of my overall purpose.
- Finally I execute the whole thing by launching DoIt

The order is based on two simple principles:
- Order of interest of people who may read it (first the things you need to use it, then the things you need to understand it, then the details)
- For a function to be visible, the script must have passed it. Otherwise it isn't loaded yet and powershell would throw an error.

Debugging this
First of all, I comment out the final line while debugging. This means, the DoIt Function never runs. Soo, let's save this and start Powershell. It will start up like usual, and nothing happens. Except now the variable $ComputerName exists, as do the additional functions DoIt, Test-ComputerConnectivity and Set-ComputerTask.
I can either run any of the latter functions individually, or run DoIt to test the entire process. This means I can run each individual step of the script and inspect the return values.

Now, if you inspect the function Test-ComputerConnectivity you will notice, that one variable is a bit odd: $script:Debug1
After running this function, we will have access to the variable $Debug1 in the console. This is because we declared the variable to the script scope. Now what might that mean ...

Scopes
Imagine being on a project to build a deep cellar of many floors. You start out on ground level, and then dig downwards, one floor at a time. Your friends upstairs will easily be able to throw you a tool you need with little effort. Bringing it back though will be a bit of a pain.
Powershell works very similar. Ground level is the script level. Everything that is here, will be passed down effortlessly. However, if you want something available on the script scope, you need to declare it as that.
If you call a function, everything that happens in that function stays inside that function (Running DoIt will thus not make the $test variable available)

There are several reasons for this to work that way, the most simple one however is to avoid accidentally overwriting a variable you defined by one that was named the same during a function call.

Practical consequences
Whenever something doesn't quite work the way I expect it to, I simply declare some debug variables at key steps inside a function, run the function and check at which point things didn't quite work out the way I expected.

Also, this way it's a lot easier to test out different kinds of input and several sequential test runs. If the function returns masses of values, I can inspect them each individually (by storing the returned results into a variable and then inspect that).

Adding tools
It gets even better. Let's return to the profile file and add another line:
PowerShell Code
Double-click the code block to select all.
. "H:\Data\Scripts\Files\Tools.ps1"
Whenever I find or write a useful function, I store it for later use. Adding those to your profile as another dotsourced script will make them available everytime I start powershell. Doesn't even need to be a debug session but common daily administrative tasks. For example, instead of writing a script to create a new user, you could just create a function and add it to your console session.
This makes it a lot easier to make use of some of the more neat comfort scripts out there. For example, you could just add this nice upgrade to the common ping to that tools script.

Of course you could add them to the profile itself, but this would make it hard to read if you keep adding things to it. You could even store your tools.ps1 on a network share and grant all admins access to it (beware though, since anything put in there will be run by admins, make sure it's properly secured).

Cheers, and I hope this makes your script development a lot more comfortable,
Bosparan

User avatar
C3PO_R2D2
Posts: 22
Joined: Sun Mar 03, 2013 12:33 pm

Re: Array values don't show up during debugging

Post by C3PO_R2D2 » Thu Apr 10, 2014 8:41 am

Waaw, a lot of information -> thanks a lot for that.
I'll try to capture this very interesting info the coming days with my simple brain...

Locked