Remote Get-WmiObject call fails when within Start-Job scriptblock - powershell

Alright, I've tried to figure this out, but figured it's time to ask the interwebs. I'm wondering if this is a bug or what.
I'm trying to start jobs against multiple computers to determine which database names reside on them.
My Computer1 system setup is: Powershell 2.0, Windows 2k3 Enterprise x64
On Computer1 I can run:
Start-Job -scriptblock {gwmi -query "select * from win32_computersystem" -ComputerName "Computer2"}
And the job will be stuck in a state of "Running" forever. But not if I run the same command outside the job's script block in the shell.
I've tried this exact setup here with a local admin's (vs my domain) credentials, but same result. It doesn't work for me for some reason.
I've tried building a custom WMI dotnet object that doesn't use gwmi, but I get the same result!
The -asjob parameter?:
This is not a solution.
When using this parameter, the powershell window crashes at around 2GB memory used on a 12GB system; Whereas I can use start-job all the way to 12GB without problems. I might as well run every query in serial fashion.
Also, memory is never reclaimed when using the -Asjob parameter on Gwmi, so no further jobs can continue; even after running "remove-job * -force" or "[GC]::Collect()", the memory consumption for powershell.exe stubbornly remains the same (again, unlike start-job).
Since SQL instance names vary, the wmi class names vary. So I need to run multiple query commands against multiple classes. While is technically doable, its more complex and, given the above memory requirements, limited to 2gb. I'm hoping someone will just know how to make start-job work like it should.
So about the only thing I haven't tried is maybe I have to specify the authority parameter?

I use Invoke-Command -asJob for this :
PS C:\> Invoke-Command -ComputerName "WM2008R2ENT" -ScriptBlock {gwmi -query "select * from win32_computesystem"} -AsJob
Id Name State HasMoreData Location Command
-- ---- ----- ----------- -------- -------
1 Job1 Running True wm2008r2ent gwmi -query "select * ...
PS C:\> Get-Job
Id Name State HasMoreData Location Command
-- ---- ----- ----------- -------- -------
1 Job1 Completed True wm2008r2ent gwmi -query "select * ...
PS C:\Développements> Receive-Job 1
Domain : dom.fr
Manufacturer : VMware, Inc.
Model : VMware Virtual Platform
Name : WM2008R2ENT
PrimaryOwnerName : Utilisateur Windows
TotalPhysicalMemory : 683139072
PSComputerName : wm2008r2ent
You can replace the machine name by a list of machines. Don't try to code again '-Computername in the CmdLets you are using in the script block.
(Edited)
I try you command line and it works for me from a client Windows Seven (64 Bits) to a W2K3 (32 bits)
My client is NOT in the domain of the server and I use domain admin credentials.
Have you made the test from a 32Bit Powershell or a 64 Bits Powershell ?
Do you try to stop WMI service on remote machine and clean the WMI database, it's sometime suitable when you made too much tests on a WMI server (with events for example).

Related

How to shutdown the computer after closing the powershell window?

I am new to powershell. I have a powershell script I've been using to backup my files. After it runs, I would like to shutdown the computer and close the powershell window. It seems I can do one or the other, but not both. So when I restart the computer, powershell complains that it was not closed properly.
How to shutdown the computer after closing the powershell window?
TIA
p.s. Contrary to popular belief, I have read the manual. However, as mentioned below, if I put EXIT before Stop-Computer, the script exits before executing Stop-Computer. If I put EXIT after Stop-Computer, powershell complains that the file was not closed properly on reboot. Either way, I lose. :(
PowerShell does provid and 'Exit', as noted in my comment. As for stopping, just put the 'Stop-Computer' cmdlet at the end of your script to shut down the computer.
Get-Help -Name Stop-Computer -examples
# Results
<#
NAME
Stop-Computer
SYNOPSIS
Stops (shuts down) local and remote computers.
----------- Example 1: Shut down the local computer -----------
Stop-Computer -ComputerName localhost
Example 2: Shut down two remote computers and the local computer
Stop-Computer -ComputerName "Server01", "Server02", "localhost"
`Stop-Computer` uses the ComputerName parameter to specify two remote computers and the local computer. Each computer is shut down.
-- Example 3: Shut down remote computers as a background job --
$j = Stop-Computer -ComputerName "Server01", "Server02" -AsJob
$results = $j | Receive-Job
$results
`Stop-Computer` uses the ComputerName parameter to specify two remote computers. The AsJob parameter runs the command as a background job. The job objects are stored in the `$j` variable.
The job objects in the `$j` variable are sent down the pipeline to `Receive-Job`, which gets the job results. The objects are stored in the `$results` variable. The `$results` variable displays the job information
in the PowerShell console.
Because AsJob creates the job on the local computer and automatically returns the results to the local computer, you can run `Receive-Job` as a local command.
------------ Example 4: Shut down a remote computer ------------
Stop-Computer -ComputerName "Server01" -Impersonation Anonymous -DcomAuthentication PacketIntegrity
`Stop-Computer` uses the ComputerName parameter to specify the remote computer. The Impersonation parameter specifies a customized impersonation and the DcomAuthentication parameter specifies authentication-level
settings.
---------- Example 5: Shut down computers in a domain ----------
$s = Get-Content -Path ./Domain01.txt
$c = Get-Credential -Credential Domain01\Admin01
Stop-Computer -ComputerName $s -Force -ThrottleLimit 10 -Credential $c
`Get-Content` uses the Path parameter to get a file in the current directory with the list of domain computers. The objects are stored in the `$s` variable.
`Get-Credential` uses the Credential parameter to specify the credentials of a domain administrator. The credentials are stored in the `$c` variable.
`Stop-Computer` shuts down the computers specified with the ComputerName parameter's list of computers in the `$s` variable. The Force parameter forces an immediate shutdown. The ThrottleLimit parameter limits the
command to 10 concurrent connections. The Credential parameter submits the credentials saved in the `$c` variable.
#>
Or use the Restart-Computer cmdlet, if that is your goal instead.
Update
Use two scripts, main and child.
# Start-Main.ps1
0..4 |
ForEach{
"Inside function... $PSItem"
Start-Sleep -Seconds 1
}
.\Start-Child
Exit
# Start-Child.ps1
'Preparing to shutdown in 10 seconds'
Start-Sleep -Seconds 10
Stop-Computer
or Using PS Jobs is another option as noted in my comment:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/start-job?view=powershell-7.2

Get status of service on a remote server

I need to find the status of a service on a remote computer. Though I can use the following command:
Write-Host (Get-Service -ComputerName "remoteServerName" -Name "serviceName").Status
which would give me correct status of service. However I have PowerShell 1.0 installed on the server where i need to run this script. -ComputerName parameter doesn't work for PowerShell 1.0. Currently I'm not supposed to install higher version of PowerShell.
Any idea how to get the status of a service in PowerShell 1.0?
First and foremost (and I can't stress this point enough): If the operating system supports it you should upgrade to at least PowerShell v2.0. No exception. If the system doesn't support PowerShell 2 or newer it's already out of support and should have been replaced/upgraded months ago.
With that said, you can use either WMI (as suggested by #vonPryz):
Get-WmiObject -Computer 'remoteServerName' -Class Win32_Service -Filter "DisplayName='ServiceName'"
or sc.exe (as suggested by #Kayasax):
& sc.exe \\remoteServerName query 'ServiceName'
Of these two WMI is the more PoSh approach, as it doesn't require parsing text output.

Grabbing system product keys

So I'm trying to use the PS script found at http://gallery.technet.microsoft.com/scriptcenter/Get-product-keys-of-local-83b4ce97#content to pull Windows product keys from my domain remotely. However, when it hits a host it returns Exception calling “OpenRemoteBaseKey” with “2″ argument(s): “The network path was not found” instead of the product key. It should also be noted that this works locally. After poking around at the internals of the script, it seems like the offending line is
$remoteReg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$Computer)
Research (because I'm totally new to PoSH) indicates that this type of error gets thrown when remote registry access isn't working. Trying to hook into the registry on my test target via regedit shows that I need to have Windows Firewall: Allow inbound remote administration exception set to enabled in Group Policy. I set it and then pulled the updated policy down to the same result. What other stuff might be getting in the way of my connection?
I would recommend using PSRemoting over using the remote registry. Assuming this is set up, all you would have to do is:
$computers = #('localhost')#list of computers
#unless you are currently logged in as a domain admin
# you will need to provide credentials
$cred = Get-Credential domain\administrator
Invoke-Command -Credential $cred -ComputerName $computers -ScriptBlock {
function Get-ProductKey{
#from http://gallery.technet.microsoft.com/scriptcenter/Get-product-keys-of-local-83b4ce97
}
get-ProductKey
}| ft Computername,OSDescription,OSVersion,ProductKey
This will print out the following output:
Computername OSDescription OSVersion ProductKey
------------ ------------- --------- ----------
%name% Microsoft Windows 8 Pro 6.2.9200 XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
I used the following command through powershell, ran it as admin:
wmic /user:jc1_admin /node:pc00202 os get "SerialNumber"

Getting all open PS Sessions on a remote server (from new console window)

I can start 5 new PS sessions on a remote server and see them all by running Get-PSSession
PS C:\> New-PSSession -ComputerName MyServerName
Id Name ComputerName State ConfigurationName Availability
-- ---- ------------ ----- ----------------- ------------
1 Session1 MyServerName Opened Microsoft.PowerShell Available
[repeat 4 more times]
As expected, when I try to open a 6th session, I get the error saying that's a no-no (due to PoswerShells default limit of 5 concurrent remote PSSessions). But running Get-Session shows all 5 sessions so all is working as it should be so far:
PS C:\> New-PSSession -ComputerName MyServerName
New-PSSession : [......maximum number of 5 concurrent shells]
PS C:\> Get-PSSession
Id Name ComputerName State ConfigurationName Availability
-- ---- ------------ ----- ----------------- ------------
1 Session1 MyServerName Opened Microsoft.PowerShell Available
2 Session2 MyServerName Opened Microsoft.PowerShell Available
3 Session3 MyServerName Opened Microsoft.PowerShell Available
4 Session4 MyServerName Opened Microsoft.PowerShell Available
5 Session5 MyServerName Opened Microsoft.PowerShell Available
However, when I close that console and open a new one, running Get-PSSession (with or without the '-ComputerName' parameter defined) shows no open sessions at all.
PS C:\> Get-PSSession
PS C:\>
I know those sessions are still open because when I try to open a new one in my new console I get the same error regarding more than 5 concurrent sessions:
PS C:\> New-PSSession -ComputerName MyServerName
New-PSSession : [......maximum number of 5 concurrent shells]
According to 'Get-PSSession Get-Help -full' running 'Get-PSSession -ComputerName MyServerName should get all remote PS sessions on a particular server regardless of what session or computer they were started from (at least the way I understand it):
"The command returns all of the sessions on [the remote server], even
if they were created in different sessions or on different computers."
So, is there a way to find and/or remove any open PS sessions on a remote server -- without having to do it all from one console session?
From what I can tell...
The PSSessions you created live on "MyServerName" and, for the duration of the session you first created them, will also be returned by Get-PSSession (with no arguments, in the PowerShell window on the box you're remoting FROM). When you close the session they are created in, the sessions are no longer on your computer. This is why Get-PSSession doesn't return anything when you close and open a new PowerShell window. They never "lived" on your computer, they are remote sessions, however, they were in scope in your original PowerShell window because that is the local scope you created them in.
If your sessions are still on MyServerName, as it seems they are due to the error you mention about max sessions, then typing the following command should list them:
Get-PSSession -ComputerName MyServerName
If you wanted to reconnect them all in your existing session/window, you could do:
Get-PSSession -ComputerName MyServerName | Connect-PSSession
To remove them all, enabling you to create new PSSessions to MyServerName
Get-PSSession -ComputerName MyServerName | Remove-PSSession
Looking a bit further in the docs, all sessions do not live indefinitely when you close your PowerShell window. See:
Get-Help about_Remote_Disconnected_Sessions -ShowWindow
partial excerpt (with emphasis mine):
If you close (exit) the session in which a PSSession was created while
commands are running in the PSSession, Windows PowerShell maintains
the PSSession in the Disconnected state on the remote computer. If you
close (exit) the session in which a PSSession was created, but no
commands are running in the PSSession, Windows PowerShell does not
attempt to maintain the PSSession.
From what I can see, sessions that aren't a) disconnected, or b) busy running a command, are discarded when you close the PowerShell window you started the PSSessions from. Additionally, the documentation does seem to mention there are also timeouts (which probably depend on PSSessionConfigurations on the server, but I don't know anything about those yet myself (other than they exist).
This was a good excuse for me to sift through some of the PowerShell Remoting documentation, also look at:
Get-Help *PSSession*
Get-Help *remote*
From my experimentation, if the sessions aren't doing anything then they get closed on the remote end. To prevent that, either have them do something e.g.:
Invoke-Command -Session $s { ... } -AsJob
Invoke-Command server01 { ... } -Disconnected
Or the other option is to disconnect your sessions:
Disconnect-PSSession -Id (1..5)
Both approaches will result in the remote sessions staying alive.
Having this same issue today I came across this nice set of functions from jrich.
I even simply pasted the functions into my PS window and ran
"<computername>" | Get-RemotePSSession | Remove-RemotePSSession
and voila! no more left-open sessions on said computer.
Here's the direct link to his blog.
https://jrich523.wordpress.com/2012/01/19/managing-remote-wsman-sessions-with-powershell/#comment-1079

Get Windows Last Reboot Timestamp?

I have a PC on remote connected by network, but it occasionally crashes or is restarted by remote users. After the restart, some services and applications have to be in running status. So I would like to find out the reboot as soon as possible. I think PS may be a good choice with some scripts so that I could make remote call to get the last reboot timestamp information.
Is there any way to get a remote Windows XP last reboot timestamp by using PowerShell 2.0(its remoting feature)?
You can do this via WMI:
$wmi = Get-WmiObject -Class Win32_OperatingSystem -Computer "RemoteMachine"
$wmi.ConvertToDateTime($wmi.LastBootUpTime)
For a remote computer:
$wmi = Get-WmiObject -Class Win32_OperatingSystem -Computer RemoteComputerName
$wmi.ConvertToDateTime($wmi.LastBootUpTime)
The uptime of the computer in seconds is available in the "System Up Time" performance counter. Though that's probably overkill.
Obviously, for services the easiest thing is to just set their start mode to "Automatic" but if you have other things that need to be running, the easiest way to do that is via the Windows task scheduler: you can set up a schedule that runs when the computer starts up.
FYI, if you are on the PowerShell Community Extensions 2.0 Beta, you can use Get-Uptime e.g.:
PS> Get-Uptime
Uptime LastBootUpTime
------ --------------
00:44:01.4401754 3/21/2010 12:07:17 AM