2

I have a pretty straightforward PS script, that refers to a bunch of self written modules (psm1). When I run my script from PowerShell ISE I am often pulling my hair out because due to the fact that the latest version of my module is not executed (but some outdated-somewhere-stored-in-memory-version).

I have google-d, and google-d, and read, and tried, and now comes the time that I'd really appreciate to understand what the hell is going on, instead of working around these issues all the time.

Some example code :

(the script will configure PCs that will serve in our machines, setting shares, creating local users, configuring NICs, stuff like that)

I start with adding the location of my modules to the module path as follows:

# Make sure .\Modules is part of the PSModulePath environment variable
$currentPSModulePath = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
If (-Not ($currentPSModulePath -Like '*.\Modules*'))
{
    [Environment]::SetEnvironmentVariable("PSModulePath", $currentPSModulePath + ";.\Modules", "Machine")
}
Write-Host ("Environment variable for PSModulePath = {0}" -f [Environment]::GetEnvironmentVariable("PSModulePath", "Machine"))

Then, I load the required modules:

### Import Modules
Import-Module -DisableNameChecking ConfigureSystemPC
Import-Module -DisableNameChecking ConfigureChipPC
Import-Module -DisableNameChecking ConfigureEngravePC
Import-Module -DisableNameChecking ConfigureCInkPC
Import-Module -DisableNameChecking ConfigureIPPC
Import-Module -DisableNameChecking ConfigureNPPC

And finally, I ask the user which PC should be configured:

### Start configuring new PC ###

Write-Host "`nChoose the PC type form the options below:`n"
Write-Host "1. System PC"
Write-Host "2. Chip PC"
Write-Host "3. Engrave PC"
Write-Host "4. CInkjet PC"
Write-Host "5. IP PC"
Write-Host "6. NP PC"
Write-Host "7. Output PC"

$pcType = Read-Host "Please enter the PC type and press [enter]"
Write-Host ("You choose option: {0}" -f $pcType)

switch ($pcType)
{
    1 { Configure-SystemPC }
    2 { Configure-ChipPC }
    3 { Configure-EngravePC }
    4 { Configure-CInkPC }
    5 { Configure-IPPC }
    6 { Configure-NPPC }
    7 { Configure-OutputPC }
}

The problem arises, when I change something in my Configure- module. When I simply add (e.g.) Write-Host "bla bla", press the Save button, and debug my main script again (the script shown above), PowerShell will run the OLD version of the module.

Unless I reload the module via either:

  • rmo Configure-EngravePC followed by ipmo Configure-EngravePC
  • ipmo Configure-EngravePC -Force

the exact same "old" version of my module will be executed.

Who can point me out how to normally deal with this? And why, why oh why, do I even have to reload Modules when I run my script via the debugger? Why would it "store" Modules that were run in a different session?? Am I doing something wrong?

Many many thanks in advance, I hope somebody can elaborate on this, I get stuck way to often..

I highly prefer an answer with proper explanation (or reference to good documentation on this topic)

bas
  • 13,550
  • 20
  • 69
  • 146

1 Answers1

1

You need to restart ISE since it keeps single console AFAIK.

Now, in order to do that without the restart you will either have to create new ISE Runspace (File>New PowerShell Tab) or ditch ISE (recommended since it sux) and use something normal such as Cmder and enter ISE only for extensive debug or implement some form of autoreloading.

The poor solution would be to replace prompt function when you enter ISE (or add that into your profile):

rename-item Function:prompt Function:old_prompt -ErrorAction ignore
function global:prompt() {
    import-module -force Configure-EngravePC
    Function:old_prompt
}

This will work OK except on first prompt after the change since prompt function isn't executed yet. You can optimize this to reload module only if file is recently changed (like in last 10 minutes).

Since that first prompt may be problematic there are ways to automate it :) Create Autohotkey script that monitors module for changes and sends to its console once it detects changes. If you do this, then there is even no need for prompt change as you can Send ipmo -force.. with Autohotkey itself. I ROFLMAOd when I wrote this, but its epic and will work perfectly to be honest if AHK script is done correctly.

I am not sure if there is any other way to automatically reload module on change in active session unless you use some freakish things like create powershell proxies for all cmdlets that will basically do the same as prompt function just in advance. But...

EDIT

I found this thingy that is semi-related, but I still think AHK solution is way to go

https://stackoverflow.com/a/7341211/82660

EDIT2

And here is the Ahk script that does the hard part (i didn't wrote file modifications check, that is trivial):

;Find window
SetTitleMatchMode, 2
ise := WinExist("PowerShell ISE")
WinGetPos, x,y,w,h

;Click somewhere inside console to select it
x := x + 20
y := h - 100  ;you may need to tweak this number depending on windows theme etc...
WinActivate
CoordMode, Mouse ,Screen
Click %x%, %y%
SendInput {ESC}import-module -force Configure-EngravePC{ENTER}

The script can probably be much better and more precise but my AHKfoo is poor nowdays...

Community
  • 1
  • 1
majkinetor
  • 8,730
  • 9
  • 54
  • 72