Solved

Remote Powershell Script to

Posted on 2014-01-24
18
442 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 6

Author Comment

by:patelbg2001
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Can you show me your complete code, so I understand, where I am going wrong?
0
 
LVL 68

Expert Comment

by:Qlemo
Comment Utility
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
Comment Utility
the script does not return any data
0
 
LVL 68

Accepted Solution

by:
Qlemo earned 500 total points
Comment Utility
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

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Find out how to use Active Directory data for email signature management in Microsoft Exchange and Office 365.
This process describes the steps required to Import and Export data from and to .pst files using Exchange 2010. We can use these steps to export data from a user to a .pst file, import data back to the same or a different user, or even import data t…
To show how to create a transport rule 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 Mail Flow >> Rules tab.:  To cr…
This video discusses moving either the default database or any database to a new volume.

743 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

18 Experts available now in Live!

Get 1:1 Help Now