I have a 2 node cluster, on Windows Server 2012R2, version 4.0 of PowerShell installed. One of the roles in the cluster is 'Messaging Queuing', named 'TESTMSMQ', which has about 20 private queues installed.
In a fresh PowerShell console, I set the environment variable _CLUSTER_NETWORK_NAME_ to be 'TESTMSMQ', using the command
$env:_CLUSTER_NETWORK_NAME_='TESTMSMQ'
When I run Get-MsmqQueue -Name *, I get nothing back. But if I run compmgmt.msc I can see all the queues listed, and if I load the System.Messaging assembly into the PowerShell session, I can see the queues.
[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging")
[System.Messaging.MessageQueue]::Exists('.\private$\MyTestQueue')
returns True
Does anybody have an idea why the MSMQ cmdlets cannot find the queues, but the .net assembly can and the Computer Managment snap in sees the queues as well?
Just to be clear, there are no queues defined on the local node or physical nodes. "private$\MyTestQueue" is only defined on the MSMQ installed role "TESTMSMQ".
So, if Exists() is returning True using a localhost name, then I would assume that the environment is the MSMQ role, not the physical node.
A little late, but I couldn't find the answer to this question anywhere. Maybe others are looking too...
Finally pieced together some ideas from a couple of places and got this working on Windows Server 2016.
On one of the cluster nodes:
$env:computername = "MsmqHostName"
Get-MsmqQueue | Format-Table -Property QueueName,MessageCount
remote from the cluster:
Invoke-Command -ScriptBlock {$env:computername = "msmqHostName";Get-MsmqQueue | Format-Table -Property QueueName,MessageCount } -ComputerName ClusternNodeName
Sounds like the classic clustered MSMQ problem.
Clustering MSMQ applications β rule #1
You don't specify where you are running your apps. For example, if "Exists('.\private$\MyTestQueue')" returns True then that means the MSMQ service is running locally to your test. So if you ran the test from the command prompt on a node, you are talking to MSMQ on the node - not the cluster. You would need to run the test from a clustered command prompt instead to use the clustered MSMQ service.
Related
I am trying to write a powershell script to install and set up Hyper-V machines. The install seems to be ok, however, I get contradictory responses from the system.
Basically, I use the (gcim Win32_ComputerSystem).HypervisorPresent to determine if HyperV is running.
It return False.
There is a similar class with the same member (gcim CIM_ComputerSystem).HypervisorPresent what is also returning False.
Also found this question How do you check to see if Hyper-V is enabled using PowerShell?
and this state property is Enabled
Do I miss something? These queries aren't the same? Could you point if any of these are deprecated?
Am I totally fooled, and Enabled means the system is capable to run HyperV, but actually it is not running?
CIM and WMI are a long tale but the short summary is that WMI is a Microsoft implementation of the OMI Standards defined by the DMTF, the Distributed Management Task Force, to come up with an industry wide standard. So, of course, creating one new standard resulted in a bunch of different implementations, which are basically their own standard.
But otherwise CIM and WMI can be thought of as different gateways to the same information for Windows computers. Different doors to the same house. More on that history and the distinctions here.
When I run the PowerShell commands you shared (either of them) on my machine with Hyper-V present, even when running as a standard, non-admin user, I get True back for both.
You can also check to see if the BIOS firmware has virtualization enabled by looking in the CIM_Processor class.
(Get-CimInstance win32_processor).VirtualizationFirmwareEnabled
True
You could also check to see if the Windows Feature is installed but that doesn't give you the full picture (what if the Windows feature is enabled in an image applied to a machine without virtualization components enabled in the BIOS, for instance.)
[ADMIN] C:\>(Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-All -Online).State
Enabled
Also, that technique π requires admin permissions.
Another way, and maybe the easiest is to check is to see if the Hyper-V Computer Service is running, which is needed for any VMs to launch, and can only run if everything else on the machine is done correctly to enable Hyper-V.
Get-Service vmcompute
Status Name DisplayName
------ ---- -----------
Running vmcompute Hyper-V Host Compute Service
We used to deploy servers with a MDT Task Sequence and enable Hyper-V along the way. It required reboots and special commands to run to apply the right bios settings. Then, we could enable the Windows Features, but those required two reboots, so it was quite tricky to handle with most imaging systems. Our final 'Sanity Check' was whether the Hyper-V compute service was running.
In my workplace, we administer hospital intensive care PCs (Windows 7 desktop clients) that are meant to be on and running a particular program in near-perpetuity. To that end we've developed a few powershell scripts that run every 5 minutes and alert us whenever the PCs drop off the network or the processes / programs we require crash.
Our program monitoring script relies on the powershell cmdlet "get-process" run remotely by an admin-credentialed account. The script works on all of our PCs except one and we haven't been able to determine what's causing the failure.
At its most basic, the command looks something like
get-process -computername [hostname]
When pointing toward our problem PC we get the error
Get-Process : Couldn't connect to remote machine
Our research indicates that this is likely caused by permissions, firewall, or remote registry service problems. We've triple-checked and on this PC and
the monitoring account has admin privileges, no firewall is active, and remote registry service is on and set to start automatically. The code works when run on the local machine but not when run remotely.
Similar powershell cmdlets run remotely, like "get-service", work with no issues. As noted above "get-process" runs successfully on our other PCs. Any insight into this strange issue would be appreciated.
One thing to note is that the Invoke-Command workaround that has been offered in answer to other, similar questions doesn't work on this PC or any of our others.
Have you tried validating the all RPC services are up?
1.Remote Procedure Call(RPC)
2.Remote Procecure Call(RPC) Locator
3.Remote Registry (You said it's up though)
Scenario: Windows service with Powershell host embedded into it. Single runspace is allocated at startup. Multi-dll solution.
Requirement: Need to access .NET classes inside running service. From a local Powershell instance using
Enter-PSHostProcess -Name MyService
...gives me exactly what I want since I can access the .NET classes.
[MyNameSpace.MyClass]::CallStaticFunction()
Question: How can this Powershell behavior be made available to remote endpoints using Enter-PSSession to a custom endpoint? From the Register-PSSessionConfiguration we can specify a dll but this will spawn up a process and won't connect to a running instance. Not interested in writing proxy via HTTPS, or named pipes, but using the native functionality offered in Powershell for .NET support.
Is it possible to extend this via PSSessions? Or would we just have to first do Enter-PSSession or Invoke-Command?
Reviewing the sources it appears that Enter-PSHostProcess and Enter-PSSession are very independent mechanisms. Enter-PSHostProcess communicates via named pipes, while Enter-PSSession uses WinRM (which is effectively uses http(s) over ports 5985/5986. I don't think you need either Enter-PSSession or Invoke-Command if you want interactive access to a local service process through Enter-PSHostProcess.
You may have already done this, but to try this out I started up both Powershell.exe and Powershell_ise.exe, then from the former used this command to connect to the later:
get-process Powershell_ise | Enter-PSHostProcess
and the prompt changed to include the PID of the ISE. Just to be sure static methods worked as you are expecting, I killed the ISE from the Powershell.exe command line using the command:
[System.Environment]::exit(0)
Powershell creates the named pipe this connects to using the default security descriptor for the thread, which typically allows access only to LocalSystem, Administrators, and the account the process is running under. My test worked because both processes were running under the same account (I didn't need administrator priv.)
To be clear however, Enter-PSHostProcess makes no provision for connecting to processes on another machine. It might be possible to double-hop, connecting to the machine first using Enter-PSSession, then connecting to the process using Enter-PSHostProcess.
I've recently upgraded a number of servers from 2003 to 2008R2. Since the upgrade I've started to see the following error:
[servername] Connecting to remote server failed with the following error message : The WSMan service could not launch a host process to process the given request. Make sure the WSMan provider host server and proxy are properly registered. For more information, see the about_Remote_Troubleshooting Help topic.
The error is seemingly random. The script will work and then fail. The command to create the session is in a loop (create session, remove session) and is called numerous times as part of a set of deployment scripts. When the script fails, it fails at different points.
I've checked the event log on the local workstation (win7) destination server (win2008R2) but there are no errors that I can see.
This is the lines that randomly fails:
$session = New-PSSession -ComputerName $serverName -Credential $credential
I did not see this issue on Win2003. The scripts have not changed. I'm assuming the problem is on the destination server but cannot find any errors or logs to look at. It will work once and then fail so my deployment scripts will sometimes succeed and then fail at different points.
Any guidance on tracking down this problem would be much appreciated.
You can get this error when trying to connect to localhost with an account that's not an administrator.
It used to be possible to use accounts that weren't an administrator, but a Windows Update in January 2019 disabled the functionality for security reasons. From the patch notes:
By default, PowerShell remoting only works with administrator accounts, but can be configured to work with non-administrator accounts. Starting with this release, you cannot configure PowerShell remote endpoints to work with non-administrator accounts. When attempting to use a non-administrator account, the following error will appear:βNew-PSSession: [computerName] Connecting to remote server localhost failed with the following error message: The WSMan service could not launch a host process to process the given request. Make sure the WSMan provider host server and proxy are properly registered. For more information, see the about_Remote_Troubleshooting Help topic.β
You need to be setting the WSMan TrustedHosts. If you want, you can set it to everything using wildcards (*).
You can do it via PowerShell: Set-Item WSMan:\localhost\Client\TrustedHosts -Value *.
Keep in mind that you also need to enable the Windows Remote service. Use the native winrm qc command for this. Enable-PSRemoting -Force might do it as well.
You can also use the PSExec Tools from Sysinternals. Keep in mind that these tools will likely be blocked by your EndPoint Security, so don't forget to white list it.
Is there a specific reason you migrate your old OSes to a newer, but still EOL OS? You can do a lot via PowerShell in 2008R2, but it's still pretty limited. IMO, Using PowerShell is best starting from 2012R2 and onwards.
Are you hitting the number of processes limit by creating pssessions that are crashing and leaving processes open?
Default limit is 15. I'd agree with the above comment and not use sessions, instead use invoke-command like:
invoke-command -scriptblock $scriptBlock -ArgumentList $args -computername $compName -Credential $encodedRemoteCredentials
to Check your limit:
PS C:\aws> ls WSMan:\localhost\Shell
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Shell
Name Value
---- ----
MaxProcessesPerShell 15
As a quick and dirty test - next time your pssession version of your script fails, increase the maxProcessesPerShell limit using set-item cmdlet to 50 and retry. If the script no longer fails, you know that's the issue (and should consider moving to invoke-command!).
We are migrating to Windows 2008 R2 Standard and will be using a Microsoft Clustering (active-passive) configuration. Our application is heavily dependent on MSMQ private queues and our install creates well over 100 private queues using the following C# code.
MessageQueue.Create(".\private$\myqueue", false);
Since the install is not running inside the context of the cluster, the queues are created on the local node and not in the cluster.
We then tried changing the code to:
MessageQueue.Create("MYCLUSTERNAME\private$\myqueue", false);
However, you can't create private queues on a different server (in this case the cluster server context) and you receive the error "Invalid queue path name".
My two questions are:
1) Is there a way I can run the install in the cluster's context so that when creating a private queue, it would actually be creating the queue in the cluster?
2) If not, what's the best approach on creating queues in the cluster via .NET? I've read some blogs where people create a middle-man Windows service that resides inside the cluster and then their install uses interprocess communication to tell the service which queues to create. That seems like a hack, but is doable if that turns out to be the only approach.
Here is how to do it manually on the clustered instance. (Not via code)
ON THE ACTIVE NODE ONLY, Create the necessary MSMQ Queues.
a. Click Start, right click on Command prompt and click Run as administrator.
b. In the command prompt enter the following commands (Where {virtualname} is the name of the instance.)
i. SET _CLUSTER_NETWORK_HOSTNAME_={virtualname}
ii. SET _CLUSTER_NETWORK_NAME_={virtualname}
iii. Compmgmt.msc
c. Now that computer management has been started from the same command prompt as the variables, it will look like you are making changes locally, but you are actually changing them in the clustered instance.
d. Expand Services and Applications.
e. Expand Message Queuing.
f. Right Click on Private Queues and click New, Private Queue.
g. Verify that the Create in: is the virtual name.
h. In the Queue name: private$\ field put in the queue name and click the OK button.
i. Close Computer Management.
This worked on Windows 2008 R2
Same solution From Powershell (what you aren't using it yet???)
I was working on this problem for a while, found this thread recently.
http://winterdom.com/2011/10/using-powershell-with-clustered-msmq
Here's a sample script which I've been using recently that will create the private queues and set permission on it. Creates on remote machines. I work with Win2k3 servers.
Invoke-Command -ScriptBlock {
$env:_CLUSTER_NETWORK_NAME_ = 'myclusterMSMQ'
Write-Host "... load the .NET Messaging assembly"
[Reflection.Assembly]::LoadWithPartialName("System.Messaging")
$environment="perf2"
$groups=#{`
"MessageRouters"="DomainName\Group";`
"CalcDaemons"="DomainName\GroupB";`
"MessageSenders"="DomainName\GroupC";`
}
function new-queue ([string] $queuepath,[bool] $transactional)
{
if (([System.Messaging.MessageQueue]::Exists($queuepath))){throw "$queuepath already exists"}
Write-Host "creating $queuepath"
[System.Messaging.MessageQueue]::Create($queuepath,$transactional)
}
function set-msmqpermission ([string] $queuepath,[string] $account, [string] $accessright)
{
if (!([System.Messaging.MessageQueue]::Exists($queuepath))){
throw "$queuepath could not be found."
}
$q=New-Object System.Messaging.MessageQueue($queuepath)
$q.SetPermissions($account,[System.Messaging.MessageQueueAccessRights]::$accessright,
[System.Messaging.AccessControlEntryType]::Set)
}
#example usage
new-queue ".\private$\$($environment)ack" $false
set-msmqpermission ".\private$\$($environment)ack" $groups.messagerouters "FullControl"
} -ComputerName "servername (or array)"
To solve your problem try setting two environment variables before running the application:
SET _CLUSTER_NETWORK_HOSTNAME_=cluster_name
SET _CLUSTER_NETWORK_NAME_=cluster_name
It worked on Windows Server 2003 R2.
For the sake of the poor souls (like me) who have spent hours scouring how to achieve this using the .NET MessageQueue, it is possible to create queues on a clustered MSMQ without Powershell:
Environment.SetEnvironmentVariable("_CLUSTER_NETWORK_HOSTNAME_", "yourclustername", EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable("_CLUSTER_NETWORK_NAME_", "yourclustername", EnvironmentVariableTarget.User);
var path = #"yourclustername\Private$\yourprivatequeuepath";
MessageQueue.Create(path, false);
Tested on server 2012.
WARNING: Take care setting environment variables as they can be hard to clear afterwards EVEN if you set them using EnvironmentVariableTarget.User. Also, it appears that it is only necessary to set the environment variables if you're trying to access a private queue in a cluster from a machine within the cluster.
If you've accidentally set the environment variables, you can clear them in the registry at HKCU\Environment. One problem that can occur is if you've run code under a different user context that has set environment variables. In one case, I was able to log in as that user and then remove them from the registry but in another case I was debugging a website under IIS and the LOCALSYSTEM account had them set. To clear them, I published a website that set the values to null. You also want to check what the env variable values are for .User, .Process and .Machine. Note that .Process-scoped changes don't take effect until the machine is restarted if the process in question is LOCALSYSTEM.