Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 482
  • Last Modified:

Remote Powershell Script to

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
patelbg2001
Asked:
patelbg2001
  • 8
  • 7
1 Solution
 
QlemoC++ DeveloperCommented:
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
 
patelbg2001Author Commented:
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
 
QlemoC++ DeveloperCommented:
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
patelbg2001Author Commented:
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
 
QlemoC++ DeveloperCommented:
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
 
patelbg2001Author Commented:
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
 
patelbg2001Author Commented:
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
 
patelbg2001Author Commented:
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
 
QlemoC++ DeveloperCommented:
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
 
patelbg2001Author Commented:
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
 
QlemoC++ DeveloperCommented:
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
 
patelbg2001Author Commented:
Can you show me your complete code, so I understand, where I am going wrong?
0
 
QlemoC++ DeveloperCommented:
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
 
patelbg2001Author Commented:
the script does not return any data
0
 
QlemoC++ DeveloperCommented:
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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 8
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now