Solved

Remote Powershell Script to

Posted on 2014-01-24
18
445 Views
Last Modified: 2014-04-06
Hi, I was wondering if anyone could help me.
When a server has more than five remote powershell sessions running, the sixth is declined.  Without increasing the number of sessions I found this site which manages to solve the issue, by termintaing sessions which are no longer used, Link - http://jrich523.wordpress.com/2012/01/19/managing-remote-wsman-sessions-with-powershell/

I'm just trying to understand how to get this to work within a script using PowerShell v2.

#
param(
	[Parameter(Mandatory = $false,valueFromPipeline=$true)][string] $ChkSSL
)
#
$oldremote = "D:\temp\Remote.csv"
$oldservers = "D:\temp\servers.txt"
#
#
remove-item $oldremote -ErrorAction:SilentlyContinue
remove-item $oldtxt2 -ErrorAction:SilentlyContinue
#
#
$remote = "D:\temp\Remote.csv"
$Servers = "D:\temp\servers.txt"
$ComputerName = Get-Content -Path $Servers
#
#

#
	IF($Computername -eq $NULL) {
		Write-Host "No Computers Names Were Found" -Fore White
	} ELSE {
		
		$port = If($chkssl){5986}else{5985}
		$uri = "http://$($computername):$port/wsman"
		$sessions = Get-WSManInstance -ConnectionURI $URI shell -Enumerate -erroraction:silentlycontinue | Out-Null
		
		Foreach($session in $sessions)

		$hash = @{
					Server = $ComputerName.ToString()
					Session = $session.owner
					clientip = $session.clientIp
					sessiontime = [System.Xml.XmlConvert]::ToTimeSpan($session.shellRunTime).tostring()
					idletime = [System.Xml.XmlConvert]::ToTimeSpan($session.shellInactivity).tostring()         
					shellid = $session.shellid         
					connectionuri = $uri
					ChkSSL = $chkssl
					$results += $object
				}
	
	
	{
		$Object = New-Object
		$Object | Add-Member -Name 'Server' -MemberType Noteproperty -Value $hash.server
		$Object | Add-Member -Name 'owner' -MemberType Noteproperty -Value $hash.owner
		$Object | Add-Member -Name 'clientip' -MemberType Noteproperty -Value $hash.clientip
		$Object | Add-Member -Name 'sessiontime' -MemberType Noteproperty -Value $hash.sessiontime
        $Object | Add-Member -Name 'idletime' -MemberType Noteproperty -Value $hash.idletime
		$Object | Add-Member -Name 'shellid' -MemberType Noteproperty -Value $hash.shellid
		$Object | Add-Member -Name 'connectionuri' -MemberType Noteproperty -Value $hash.connectionuri
		$Object | Add-Member -Name 'ChkSSL' -MemberType Noteproperty -Value $hash.chkssl
		$results += $Object
		}
	}
	{
	$results | Format-Table | Out-File -FilePath $remote
	}

$data = Get-Content -Path $remote
write-host $data.count total lines read from file
 foreach ($line in $data)
 {
     write-host $line
 }

Open in new window

0
Comment
Question by:patelbg2001
  • 8
  • 7
18 Comments
 
LVL 68

Expert Comment

by:Qlemo
ID: 39812316
You don't include that code that way. You should put it into an own file, and import that (using . C:\PathTo\Script.ps1); or put the complete code as-is in front of your own.
In both cases just call the functions defined: Get-RemotePSSession $Computername to get the sessions.
0
 
LVL 6

Author Comment

by:patelbg2001
ID: 39812784
I would just prefer to call it from a .\name.ps1 file. I dont seem to return any values from the script, this is why I'm asking for help. Could you help?
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39812988
The script is not return anything, because it just defines the tools to use later in your code. You need to "call" the functions. But since you didn't provide the limits you think "inactive" means, and your code making no sense to me, I'll have to guess.

In raw, your script should look like this:
# load the definition
. c:\ScriptPath\Get-RemotePSSession.ps1

# use it
$servers = "D:\temp\servers.txt"
$MaxIdleTime = '00:30:00'   # This means 30 minutes.

Get-Content -Path $Servers | 
  Get-RemotePSSession |
  where { $_.IdleTime -ge $MaxIdleTime } |
  Remove-RemotePSSession

Open in new window

This will kill all WSMan session not doing anything for 30 minutes.
[rant mode on]
Be aware that you have to use exactly that time format of 'hh:mm:ss', because the function converts the idle time to a string, which is plain stupid for processing it further. No clue why the author did that. The functions are clumsy, and there is no need for a custom class definition in it - much ado about nothing ;-).
[rant mode off]
0
 
LVL 6

Author Comment

by:patelbg2001
ID: 39814463
The term 'Get-RemotePSSession' is not recognized as the name of a cmdlet, function, script file, or operable program. So that does not work!
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39814605
You stuffed the original code of JRich into a file Get-RemotePSSession.ps1, and used the correct path for it in my code snippet? And no error before that "The term ..."?
0
 
LVL 6

Author Comment

by:patelbg2001
ID: 39817550
No, I don't intend to use the complete code, I was looking for better understanding of this code, so I could apply it into something I was looking into. and I was looking for help creating something around this which is just as effective
0
 
LVL 6

Author Comment

by:patelbg2001
ID: 39817972
PowerShell here-strings don’t like whitespace. The here-string’s “@ terminator needs to be on its own line, with no preceding white-space/tabs/whatever.
0
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
LVL 6

Author Comment

by:patelbg2001
ID: 39818227
Still recieving errors, this is being run on Powershellv2

Get-Member : No object has been specified to the get-member cmdlet.
At D:\Bhav\RemoteCheckv2.ps1:25 char:27
+                     $session | Get-Member <<<<
    + CategoryInfo          : CloseError: (:) [Get-Member], InvalidOperationException
    + FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand

Exception calling "ToTimeSpan" with "1" argument(s): "The string '' is not a valid TimeSpan value."
At D:\Bhav\RemoteCheckv2.ps1:32 char:47
+                         $x = [System.Xml.XmlConvert]::ToTimeSpan <<<< ($session.shellRunTime)
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

Exception calling "ToTimeSpan" with "1" argument(s): "The string '' is not a valid TimeSpan value."
At D:\Bhav\RemoteCheckv2.ps1:36 char:47
+                         $y = [System.Xml.XmlConvert]::ToTimeSpan <<<< ($session.shellInactivity)
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

Function Get-RemotePSSession {
	[CmdletBinding()]
	Param ([Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)][string] $ComputerName,
					[Switch] $UseSSL
					)
#
#
		
Begin
	{
	Write-Host "Script Begin"
	$results = @()
	}
		
#
#
 Process
	{
	 Write-Host "Script Process"
	 $port = If($usessl){5986}else{5985}
	 $uri = "http://$($computername):$port/wsman"
	 $sessions = Get-WSManInstance -ConnectionURI $URI shell -Enumerate
		foreach($session in $sessions)
					{
					$session | Get-Member
						$obj = New-Object PSObject
						#$obj.owner = $session.owner
						$obj | Add-Member -Name 'owner' -MemberType Noteproperty -Value $session.owner
						#$obj.clientip = $session.clientIp
						$obj | Add-Member -Name 'clientIp' -MemberType Noteproperty -Value $session.clientIp
						# $obj.sessiontime = [System.Xml.XmlConvert]::ToTimeSpan($session.shellRunTime).tostring()
						$x = [System.Xml.XmlConvert]::ToTimeSpan($session.shellRunTime)
						$xx = [String] $x
						$obj | Add-Member -Name 'sessiontime' -MemberType Noteproperty -Value $xx
						# $obj.idletime = [System.Xml.XmlConvert]::ToTimeSpan($session.shellInactivity).tostring()
						$y = [System.Xml.XmlConvert]::ToTimeSpan($session.shellInactivity)
						$yy = [STRING] $y
						$obj | Add-Member -Name 'idletime' -MemberType Noteproperty -Value $yy
						# $obj.shellid = $session.shellid
						$obj | Add-Member -Name 'shellid' -MemberType Noteproperty -Value $session.shellid
						# $obj.connectionuri = $uri            
						$obj | Add-Member -Name 'ConnectionURI' -MemberType Noteproperty -Value $uri
						# $obj.UseSSL = $usessl
						$obj | Add-Member -Name 'SSL' -MemberType Noteproperty -Value $usessl
						$results += $obj
						}
					}
#
#
End
	{
	Write-Host "Script End"
	$results
	}
}

Open in new window

0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39818720
Re "No, I don't intend to use the complete code": In PowerShelll you should use the concept of small functions doing some specific work. It is not praticable to take parts of code into a new script, changing here and there, to get something slightly different, because that is prone to errors, and removes the ability to perform tests in small units.
I see you now followed that advice somehow, which is a good start.

I don't know what to say in regard of your here-string comment - yes, that is true, no spaces in front of the end terminator allowed.

Get-Member will throw that error whenever it encounters an empty var/object, which has the value of $null by definition. You probably run into another issue with the foreach statement, which goes to the loop even if the var is $null. I assume $sessions = Get-WSManInstance -ConnectionURI $URI shell -Enumerate did not return anything, then $sessions is $null, and the loop will be run once.

As far as I can see, your modifications should work that way you do. Though it is less effective to use Add-Member then to provide a hash table with the
$result += New-Object PsObject -Property @{
  name1 = value1
  name2 = value2
}

Open in new window

The only (potential) issue is that foreach behaviour. Another explanation is that you get an error, but ignored that?
0
 
LVL 6

Author Comment

by:patelbg2001
ID: 39818765
The original code is based on v3, so unless it's works for v2, I have no choice but to change the logic to make it fit for this purpose.
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39818852
It works with v2, and is not based on v3.
I've checked the foreach issue, and I'm correct. If you have no remote session, the loop is still processed once with a $null value.
Instead of
$sessions = Get-WSManInstance -ConnectionURI $URI shell -Enumerate
foreach($session in $sessions)

Open in new window

this should be used:
foreach($session in Get-WSManInstance -ConnectionURI $URI shell -Enumerate)

Open in new window

or, even better,
Get-WSManInstance -ConnectionURI $URI shell -Enumerate | foreach {

Open in new window

but that requires you replace $server with $_ in the loop.
0
 
LVL 6

Author Comment

by:patelbg2001
ID: 39821718
Can you show me your complete code, so I understand, where I am going wrong?
0
 
LVL 68

Expert Comment

by:Qlemo
ID: 39821774
Applied to the code you posted last:
Function Get-RemotePSSession {
  [CmdletBinding()]
  Param ([Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)][string] $ComputerName,
         [Switch] $UseSSL
        )
#
#
    
Begin {
  Write-Host "Script Begin"
  $results = @()
}
    
#
#
Process {
  Write-Host "Script Process"
  $port = If($usessl){5986}else{5985}
  $uri  = "http://$($computername):$port/wsman"
  foreach($session in Get-WSManInstance -ConnectionURI $uri shell -Enumerate)
  {
    $results += New-Object PSObject -Property @{
                  owner         = $session.owner
                  clientIP      = $session.clientIp
                  sessionTime   = [System.Xml.XmlConvert]::ToTimeSpan($session.shellRunTime   ).tostring()
                  idleTime      = [System.Xml.XmlConvert]::ToTimeSpan($session.shellInactivity).tostring()
                  shellID       = $session.shellid
                  connectionURI = $uri            
                  UseSSL        = $usessl
                }
  }
#
#
End
{
  Write-Host "Script End"
  $results
}
}

Open in new window

I could not resist to make the script more compact.
0
 
LVL 6

Author Comment

by:patelbg2001
ID: 39852741
the script does not return any data
0
 
LVL 68

Accepted Solution

by:
Qlemo earned 500 total points
ID: 39852830
The script only defines a function Get-RemotePSSession. You still need to execute that function, after having defined it. E.g. add something like this as last line:
Get-RemotePSSession Pc1, Pc2, Pc3

Open in new window

0

Featured Post

Don't lose your head updating email signatures!

Do your end users still have the wrong email signature? Do email signature updates bore you or fill you with a sense of dread? You can make this a whole lot easier on yourself by trusting an Exclaimer email signature management solution. Over 50 million users do...so should you!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This script can help you clean up your user profile database by comparing profiles to Active Directory users in a particular OU, and removing the profiles that don't match.
Read this checklist to learn more about the 15 things you should never include in an email signature.
To show how to generate a certificate request in Exchange 2013. We show this process by using the Exchange Admin Center. Log into Exchange Admin Center.:  First we need to log into the Exchange Admin Center. Navigate to the Servers >> Certificates…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

914 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now