clear powershell session - powershell

Is there a commandlet that clears the current powershell session variables that I have added?
I am using the Add-Type commandlet, and I am getting the error "Cannot add type. The type name already exists."

A possible "work around": Open a powershell window and then to run your script enter powershell .\yourScriptHere.ps1
This launches a new powershell instance which exits when your script exits. If you want to "play" in the new instance then change the invocation to powershell -NoExit .\yourScriptHere.ps1 and the new instance will not exit when the script completes. Enter exit when you need another restart and hit the "up arrow" key to get the previous command. All script output will appear in the same window. The overhead for starting a new powershell instance is low -- appears to be less than 1 second on my laptop.

Unfortunately you can't unload .NET assemblies that have been loaded into the default AppDomain which is what Add-Type does. You can rename types or namespaces to limp along but at some point you just have to exit and restart PowerShell.
This is not a PowerShell limitation so much as it is a .NET/CLR limitation. You can load .NET assemblies into separate AppDomains which can be unloaded later but you would have to code that yourself and it imposes restrictions on the types you plan to use in the separate AppDomain. That is, those types need to work through .NET Remoting so they either have to derive from MarshByRefObject or they have to be serializable (and this applies to all the objects referenced by their properties, and so on down the object graph).

Related

Powershell IDE: How to restart interactive shell to clear all variables without leaving Powershell ISE?

Let's say I've been using Powershell ISE for a while and my environment space is starting to get dirty, and I need to restart the interactive shell... I don't want to close my editor and reopen it. How to restart powershell ISE interactive shell to clear all variables without closing and reopening the Powershell ISE?
First, the obligatory notice:
The PowerShell ISE is no longer actively developed and there are reasons not to use it (bottom section), notably not being able to run PowerShell (Core) 6+.
The actively developed editor that offers the best PowerShell development experience, across PowerShell editions and platforms, is Visual Studio Code, combined with its PowerShell extension.
ISE:
Colin's helpful answer is a pragmatic solution: open a new tab and close the old one.
However, that new session invariably retains the environment variables of the old one, because the ISE hosts the PowerShell SDK in-process rather than running powershell.exe as a child process.
To restart a session in the current tab you would therefore have to instruct the hosted System.Management.Automation.PowerShell instance to discard its current runspace and create a new one - and I'm not aware of a way to do this.
Even if it were possible, however, the environment variables - which exist at the level of the process that runs the ISE - would be retained.
Visual Studio Code:
It is possible to start a new session in the current tab and to do so without inheriting the old session's environment variables:
While the integrated terminal running is running the PowerShell Integrated Console, which the PowerShell extension comes with - which is the equivalent of the console pane in the ISE - you can kill the current instance by clicking the trash-can icon in the toolbar of the terminal panel as shown below.
After doing so, you're prompted for starting a new session, which runs in a new powershell.exe / pwsh child process.
Alternatively - and preferably - you can configure the PowerShell extension to automatically start a new session whenever you start a new debugging session, as zett42 points out:
Either: Open the Settings (Ctrl-,) view, search for powershell temporary and turn on the PowerShell > Debugging: Create Temporary Integrated Console setting.
Or: Add "powershell.debugging.createTemporaryIntegratedConsole": true directly to your settings.json file.
This automatically starts a new, temporary PowerShell Integrated Console for each debugging session, which remains open until you start the next debugging session, at which point a new temporary console simply replaces the old one.
Curiously, as of extension version 2022.11.0, you cannot exit out of a PowerShell Integrated Console, but you can use the trash-can icon or Stop-Process -Id $PID to kill it, if needed, which in the case of a temporary console will (commendably) not prompt you to restart it; instead, the next debugging session will create a new, temporary console on demand.
This configuration avoids a major pitfall that afflicts the ISE invariably (and may in part be what prompted the question) as well as the PowerShell extension's default configuration:
There, the code runs dot-sourced, i.e. directly in the top-level scope of the same session, so that the state left behind by earlier debugging runs can interfere with subsequent debugging runs; for instance, create a script with content (++$i) and run it repeatedly - you'll see that $i increments every time, across runs.
Starting a new session for every debugging run avoids this problem.
Ctrl+t opens a new powershell tab that starts as if it was a fresh powershell session.
Try either 1 of below to clear variable memory , it shall help
exit # Exit will quit from Powershell.
Get-Variable -Exclude PWD,*Preference | Remove-Variable -EA 0 # this will kill all the memory on current session

Reloading a modified class in Powershell

I've a script file containing a class definition. Using the new V5 Powershell syntax. I've another script file that dot source the class and uses it. I'm testing that file in the console.
On clean startup of the console it will load the class correctly. I then make some changes to the class and saved them back to file. Re-running the script does not appear to pick the changes up. It is as though once loaded into the console, the class is immutable and will not be parsed and reloaded.
This really hurt when developing, since I have to spin up a new console after any change to a class.
Is there a way to force Powershell to reload classes each time it sees them?
This occur in code debugged both in Powershell ISE and in the Powershell console (using vscode).
This is a known issue with classes in Powershell, and looks like the issue remains unresolved at this time of writing.
To workaround this today, you either need to start a new interactive session (which you don't want to do), or load your development class in a child instance of Powershell:
powershell.exe -Command { Your-Code }
# Alternatively, write a script to test your newly updated class
powershell.exe -File \path\to\Test-ClassScript.ps1

PowerShell: Start-Process Firefox, how do he know the path?

When I call the following code:
Start-Process Firefox
Then the PowerShell opens the browser. I can do that with several other programs and it works. My question is: How does the PowerShell know which program to open if I type Firefox? I mean, Im not using a concrete Path or something ...
I though it has something to do with the environment variables ... But I cannot find any variable there which is called Firefox ... How can he know?
I traced two halves of it, but I can't make them meet in the middle.
Process Monitor shows it checks the PATHs, and eventually checks HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe so that's my answer to how it finds the install location, and then runs it.
That registry key is for Application Registration which says:
When the ShellExecuteEx function is called with the name of an executable file in its lpFile parameter, there are several places where the function looks for the file. We recommend registering your application in the App Paths registry subkey.
The file is sought in the following locations:
The current working directory.
The Windows directory only (no subdirectories are searched).
The Windows\System32 directory.
Directories listed in the PATH environment variable.
Recommended: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
That implies PowerShell calls the Windows ShellExecuteEx function, which finds FireFox as a registered application, or it tries the same kind of searching itself internally.
Going the other way to try and confirm that, the Start-Process cmdlet has a parameter set called UseShellExecute. The 'Notes' of that help says:
This cmdlet is implemented by using the Start method of the System.Diagnostics.Process class. For more information about this method, see Process.Start Method
Trying to trace through the source code on GitHub:
Here is the PowerShell source code for Start-Process.
Here, at this line it tries to look up the $FilePath parameter with CommandDiscovery.LookupCommandInfo.
Here it checks else if (ParameterSetName.Equals("UseShellExecute"))
Then Here is the .Start() function which either starts it with ShellExecute or Process.Start()
OK, not sure if ShellExecute and ShellExecuteEx behave the same, but it could be PS calling Windows, which is doing the search for "FireFox".
That CommandSearcher.LookupCommandInfo comes in here and follows to TryNormalSearch() which is implemented here and immediately starts a CommandSearcher which has a state machine for the things it will search
SearchState.SearchingAliases
Functions
CmdLets
SearchingBuiltinScripts
StartSearchingForExternalCommands
PowerShellPathResolution
QualifiedFileSystemPath
and there I get lost. I can't follow it any further right now.
Either it shortcuts straight to Windows doing the lookup
Or the PowerShell CommandSearcher does the same search somehow
Or the PowerShell CommandSearcher in some way runs out of searching, and the whole thing falls back to asking Windows search.
The fact that Process Monitor only logs one query in each PATH folder for "firefox.*" and then goes to the registry key suggests it's not doing this one, or I'd expect many more lookups.
The fact that it logs one query for "get-firefox.*" in each PATH folder suggests it is PowerShell's command searcher doing the lookup and not Windows.
Hmm.
Using Process Monitor I was able to trace the PowerShell.
It first searches the $env:path variable, then the $profile variable.
In my case firefox wasn't found and then it searches through a whole lot in the Registry and somehow finds it.
It might have something to do with how firefox is installed on the system.

Unblock-File - Why do I need to open a new session?

I am using Carbon's Powershell module for some work. When I move the folder to a different machine, the scripts within are flagged and blocked from being executed until I unblock them (which is fine). When I execute the following:
gci .\Carbon -Recurse | Unblock-File
I am still unable to import the module until I create a new Powershell session. The files are definitely unblocked at this point, but I continue to receive the same error until that new session has been created.
I've read over some technet articles and they state that you just need to close and open Powershell to resolve it, but no reasoning as to why this needs to occur.
This actually goes back to the .Net framework on which PowerShell is based. You're essentially loading a new assembly into the process. A blocked file is considered a "remote" file and by default .net is not set to load them.
How the Runtime Locates Assemblies
Checks whether the assembly name has been bound to before and, if so, uses the previously loaded assembly.
The thing is, this step caches "negative" loading as well (at least in my experience, from trying to load other assemblies). .Net doesn't have a way unload assemblies once they're loaded, so you have no other choice than to restart the process.

Can a Batch script know if it's called from PowerShell?

Is there any way a batch script can know if it's called from PowerShell (without extra parameters feeded)?
Need something like..
if (%THIS_BATCH_CALLED_FROM_POWERSHELL%)
... warn the user or drop back to powershell to execute the proper instructions...
Question related with this question - virtualenv-in-powershell.
You could use a tool like "tlist.exe /t" or this one to display the PIDs of the current process and all parent processes. You could check each one of those PIDs to see if any correspond to PowerShell.exe.
You could add a default warning in the script and pass it a flag that tells it not to show the warning. When you call it from power shell pass it that flag.
In my Powershell environment (a PS 2.0 CTP), I seem to have an environment variable PSMODULEPATH which is not set by the normal command line environment, but still exists when Powershell has a child CMD.exe shell.
I think you might be able to "reliably enough" check for the existence of PSMODULEPATH in your batch script.