PowerShell and Multi-Threading? RRS feed

  • Question

  • We desperately need a NetSend tool for Windows 7.   I know there is msg.exe but so far that does not work for us.  I wrote a PowerShell script that will use msg.exe but it sends messages to each machine in a .txt file one at a time.  When we have 700+ machines it takes over 30 min to send to all machines and given our environment we need something that works like NetSend did.  A message pops up within seconds on all target systems.

    Can PowerShell do this if multi-threading is used?    If so how? 


    • Moved by Bill_Stewart Tuesday, November 24, 2015 3:02 PM This is not "scripts on demand"
    Monday, September 28, 2015 5:08 PM


All replies

  • Sounds like an interesting project. But this isn't the right place to post script requests.

    You can post script requests here:


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by Bill_Stewart Tuesday, November 24, 2015 3:02 PM
    Monday, September 28, 2015 5:14 PM
  • You may be able get around the one-at-a-time conundrum, by using Invoke-Command, as opposed to what I have to assume is a standard, looping construct (do something, loop, do somthing else). Invoke-Command will run against 32 computers at a time, by default.

    You might not spot this at first, but there's a difference where msg.exe is run, in the two examples below. In the first, looping example, it runs from the computer where you run the script. In the Invoke-Command example, it runs msg.exe from the remote computer.

    $Servers = Get-Content -Path C:\Servers.txt
    ForEach ($Server in $Servers) {
        msg.exe * /Server:$Server 'Free donuts in break room.'
    $Servers = Get-Content -Path C:\Servers.txt
    Invoke-Command -ComputerName $Servers -ScriptBlock {
        msg.exe * 'Free donuts in break room.'

    Monday, September 28, 2015 8:51 PM
  • Hi mqh7,

    Could you please provide us the script that you have written for sending the messages using powershell so that we can help you out in modifying the script for multi threading. But I suggest to check with the run spaces in this regard which can give you a better multi threading thing that you are looking for. Check this link Runspace

    Naveen Basati

    Tuesday, September 29, 2015 11:12 AM
  • I am using a tool called PowerShell Studio that allows you to create very nice GUI's around your code.   So the user running this tool will see a dialog that has a few buttons.  Each button will send an MSG.EXE to a different group of machines.   Each button has the same PowerShell code behind it.

     $Message = Read-Host -Prompt "Enter your message here"
     $pc = Get-Content "\\Server\Share\AllWin7.txt"
     foreach ($desktop in $pc)
      msg /SERVER:$desktop * /TIME:2000 $Message

    In the example above I'm sending a message to all windows 7 machines and this is the one that takes 30-45 min to complete.   

    I watched a YouTube video (from Powershell.com) that showed how to run things faster.   Here is an example of what they were teaching.

    $all = @('some text' * 20) * 1000000
    $file = "c:\temp\testfile.txt"
    Set-Content $file -Value $all -Encoding Unicode

    This ran very fast Vs using a foreach loop, which took about 3 minutes.   I just don't know how to use this in my script.   I like the Invoke-Command and did not know it can do blocks of 32 machines at a time.  I will play around with that.

    thank you all for the help. 


    Tuesday, September 29, 2015 1:55 PM
  • Hi mqh,

    Please check the code. It might be helpful for you. 

    function Test{
    $Message = Read-Host -Prompt "Enter your message here"
        $computernames = gc C:\1.txt
        $RunspaceCollection = @()
        $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1,8)
        $ScriptBlock = {
          [parameter(Position=0, ValueFromPipeline=$true)][string]$ip,
          [parameter(Position=1, ValueFromPipeline=$true)][string]$test,
            [parameter(Position=2, ValueFromPipeline=$true)][string]$test1,  
            [parameter(Position=3, ValueFromPipeline=$true)][string]$Message 
         $test = Test-Connection -ComputerName $ip -Count 1 -Quiet  
     $test1 = msg /SERVER:$ip * /TIME:2000 $Message
    foreach($ip in $computernames)
     #Create a PowerShell object to run add the script and argument.
      $Powershell = [PowerShell]::Create().AddScript($ScriptBlock).AddArgument($ip).AddArgument($test1).AddArgument($test).AddArgument($Message)
      #Specify runspace to use
      $Powershell.RunspacePool = $RunspacePool
       #Create Runspace collection
      [Collections.Arraylist]$RunspaceCollection += New-Object -TypeName PSObject -Property @{
       Runspace = $PowerShell.BeginInvoke() 
       PowerShell = $PowerShell  
     Foreach($Runspace in $RunspaceCollection.ToArray()){

    You can call the test function with button onclick function


    Mark as answer if it is helpful for you

    Naveen Basati

    Sunday, October 4, 2015 5:19 AM
  • Hi mqh7,

    Are you checking your script requests status?

    You request:


    Proposed Solution:


    Solution from Naveen, looks good as well.



    Please “Vote As Helpful” if you find my contribution useful or “Mark As Answer” if it does answer your question. That will encourage me - and others - to take time out to help you.

    Monday, October 5, 2015 6:22 AM