Your problem is because System.Windows.Forms.MessageBox.Show() runs in the session of the caller.
the fact of it working on ISE is because you are running in the session that contains the window handle.
The easiest way of doing this is using P/Invoke, and the WTSSendMessage Win32 Terminal Services API.
This API allows you to send messages to all or selected sessions on a local or remote computer.
There are a LOT of ways to accomplish this, and you can find examples here.
On our method, we list all sessions on the current computer using WTSEnumerateSessions, filter the active, or selected ones and send the message.
First we add the signature for these functions:
Add-Type -Namespace 'Utilities' -Name 'WtsApi' -MemberDefinition @'
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern int WTSEnumerateSessions(
IntPtr hServer,
int Reserved,
int Version,
ref IntPtr ppSessionInfo,
ref int pCount
);
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSSendMessage(
IntPtr hServer,
int SessionId,
String pTitle,
int TitleLength,
String pMessage,
int MessageLength,
int Style,
int Timeout,
out int pResponse,
bool bWait
);
'@
This method uses the least amount of C# possible, so we're not actually defining the WTS_SESSION_INFO struct. We're taking advantage that the layout of these structs are sequential and that each member it's 8 bytes long.
# Enumerating sessions.
$pSessionInfo = [System.IntPtr]::Zero
$count = 0
[void][Utilities.WtsApi]::WTSEnumerateSessions(0, 0, 1, [ref]$pSessionInfo, [ref]$count)
# Converting the data pointed by $pSessionInfo into a byte array.
$bufferSize = $count * 24
$buffer = [byte[]]::new($bufferSize)
[System.Runtime.InteropServices.Marshal]::Copy($pSessionInfo, $buffer, 0, $bufferSize)
# For each session info structure returned, we send the message.
$Message = 'Test message'
$Caption = 'Test title'
$offset = 0
for ($i = 0; $i -lt $count; $i++) {
# Getting the current struture from the byte array
$nativeSessionId = [System.BitConverter]::ToInt32($buffer[$offset..($offset + 8)], 0)
$response = 0
# Sending the message
[void][Utilities.WtsApi]::WTSSendMessage(0, $nativeSessionId, $Caption, $Caption.Length, $Message, $Message.Length, $Style, $Timeout, [ref]$response, [bool]$Wait)
# Incrementing the offset for the next operation
$offset += 24
}
We tidy it up, put into a function inside the script block for your event action:
function New-WtsMessage {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$Caption,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$Message,
[Parameter()]
[long]$Style = 0x00001040L,
[Parameter()]
[int]$Timeout = 0,
[Parameter()]
[switch]$Wait
)
try {
Add-Type -Namespace 'Utilities' -Name 'WtsApi' -MemberDefinition @'
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern int WTSEnumerateSessions(
IntPtr hServer,
int Reserved,
int Version,
ref IntPtr ppSessionInfo,
ref int pCount
);
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSSendMessage(
IntPtr hServer,
int SessionId,
String pTitle,
int TitleLength,
String pMessage,
int MessageLength,
int Style,
int Timeout,
out int pResponse,
bool bWait
);
'@
}
catch { }
$pSessionInfo = [System.IntPtr]::Zero
$count = 0
[void][Utilities.WtsApi]::WTSEnumerateSessions(0, 0, 1, [ref]$pSessionInfo, [ref]$count)
$bufferSize = $count * 24
$buffer = [byte[]]::new($bufferSize)
[System.Runtime.InteropServices.Marshal]::Copy($pSessionInfo, $buffer, 0, $bufferSize)
$offset = 0
for ($i = 0; $i -lt $count; $i++) {
$nativeSessionId = [System.BitConverter]::ToInt32($buffer[$offset..($offset + 8)], 0)
$response = 0
# Session 0 is the system session.
if ($nativeSessionId -ne 0) {
[void][Utilities.WtsApi]::WTSSendMessage(0, $nativeSessionId, $Caption, $Caption.Length, $Message, $Message.Length, $Style, $Timeout, [ref]$response, [bool]$Wait)
[PSCustomObject]@{ SessionId = $nativeSessionId; Response = [WtsMessageResponse]$response }
}
$offset += 24
}
}
New-WtsMessage -Caption 'Warning!' -Message 'New fax in folder \\server_name\Public\folder_x\folder_y\FAX'
Also, it's a good idea putting a check inside the action to make sure it's being triggered, like:
Add-Content -Path C:\Path\To\Folder\FaxFolderFileWatch.log -Value "Hit! $([datetime]::Now)"
Hope it helps.
Happy scripting!