Posh-SSH and Cisco Gear - powershell

I've been working on doing some scripting with Powershell and the Posh-SSH module. I'm connecting to mainly Cisco gear, but have some other network gear as well. My issue seems to be that I can connect to the gear just fine, but my commands don't seem to run. I've attempted Invoke-SSHCommand as well as creating New-SSHShellStream. What is odd is if I open Powershell and step through each command manually, it appears to work just fine, but for some reason running in a script doesn't produce the results I'm looking for.
I have found that plink.exe works just fine, but I'd really rather code all this from Powershell if possible. Is there something I'm missing with these network devices that might be different than a Linux server?
Code:
New-SSHSession -ComputerName $fw-ip -Credential (Get-Credential) -Verbose<br/>
$session = Get-SSHSession -Index 0<br/>
$stream = $session.Session.CreateShellStream("dumb", 0, 0, 0, 0, 1000)<br/>
$stream.Write("show ver")<br/>
$stream.Read()
What I get back:
Type help or '?' for a list of available commands.<br/>
FW/Admin>

So after working with you in the comments it looks like there were two problems, the first being that the SSH shell supported by the SSH.NET library does not seem to support partial commands, swapping "Show Ver" to "Show Version" corrected that. In addition the command was taking a bit longer to run than the script was waiting before calling its read() on the stream, which can be fixed by adding a start-sleep -seconds 5 between the write() and the read(). If you are planning to use this with commands that may take longer or where you are not sure how long they will take you may want to look into some additional handling that checks to see if the command is done by checking the dataavailable property or creating a listener for the DataReceived event but if your keeping things simple a basic timer will work great for you.

Related

Start-Process, set focus (?) and press key on virtual machine disconnected from RDP

I have a situation which I need some help with.
I'm running an Azure build pipeline on microsoft hosted private VM with quite a old build program/IDE which does not have any CLI.
So I have to start the program and then press a key (F10) to start the build, right now i'm using Powershell for this.
I have issues though to get this to work on the VM when I have disconnected RDP, almost always (not 100%) when I have rdp open my script works and set focus to the program and presses the key. But sometimes it doesn´t work, and it seems to always fail when the rdp is disconnected. My build fails and when I connect with RDP the window is just grey:d out and it hasn't registered any keypress.
I have found some similar threads which seems to touch upon the issue, but not any solution for Powershell.
Setting focus to window in a virtual machine
Sendkeys On Disconnected RDP Session
One solution seems to be to redirect standard input to the started program which means we don't have to care about focusing the window, but how do I redirect a keypress to a started process with Powershell? (Any other scripting language available in azure pipelines yaml is also ok)
The best solution so far has been
param
(
[string]$appName,
[string]$key
)
$objShell = New-Object -ComObject wscript.shell
$proc = Get-Process $appName
$objShell.AppActivate($proc.Id)
Start-Sleep -Seconds 1
$keyString = "'{" + $key + "}'"
$objShell.SendKeys($keyString)
But as stated, this seems to only work when I have an active RDP connection (and not 100% of the time). I have also tried using SetForegroundWindow which works fine when I run the script on my own computer but not on the VM.
Many thanks
Carl

Can you use a powershell script to create a powershell script?

So this may be an odd request and maybe I'm going about this all wrong but I also have a unique situation. I have servers that are sometimes cloned and I need to run a script that I created on the clones servers. Due to the nature of the clones they cannot be connected to a network.
Currently I am manually putting the generic script on each server before cloning and then running the script on the clone server.
What I would like to do is have a script that runs and gathers all the information, say installed programs as an example, and generate a custom version of my current script on the servers before they are cloned.
I have both the powershell script that gets the server information and the generic one that makes the changes to the clone but I have not found a way to merge the two or any documentation so I don't know if i am hitting a limitation with this one.
Edit for more explanation and examples. I'm doing this from my phone atm so I dont have an example I can post.
Current I have a script that has a set number of applications to uninstall, registry keys to remove, services to stop ect. In another application I have a list of all the software that we have for each server and I can pull that data for each server. What I need to do is pull the data for each server, and have a script placed on each server that will uninstall just the programs for that server.
Currently the script has to run through every potential software and try to uninstall it and then check the other application to see if there are any additional programs that need to be uninstalled.
Hope this extra info helps.
Thanks.
Stop thinking of it as code.
Use script 1 to export blocks of text into a new file. for example, you might have a configuration that says all Dell servers must have this line of code run:
Set-DELL -attribute1 unmanaged
where on HP, the script would have been
Set-HP -attribute1 unmanaged
on web servers, you want:
set-web -active yes
where if not a web server, you want nothing.. so, your parent script code would look like:
$Dell = "Set-DELL -attribute1 unmanaged"
$HP = "Set-HP -attribute1 unmanaged"
$web = "set-web -active yes"
if (Get-servermake -eq "Dell")
{
$dell | out-file Child.ps1 -append
}
if (Get-servermake -eq "HP")
{
$HP | out-file Child.ps1 -append
}
if (Get-webserver -eq $true)
{
$web | out-file Child.ps1 -append
}
The result is a customized script for the specific server, child.ps1.
Now, you can take this and run with it. You could say add functionality to the child script like "Is it an AD controller", etc.
However, you might be better off having all of this in a single script, and just block off sections that don't apply in an if statement for example.
I'm still not totally sure I understand what your asking. If I've missed the mark, tell me how, and I'll tell you how to tweak this better. (And hopefully obvious is that the Get-whatever is sample code. I don't expect that to be what your using to determine a computer make/model/etc)

Powershell 6.2 and Get-CimInstance to remotely stop/start/restart service issues

So I am at a big roadblock right now. I was working in PowerShell 5.1 and had the Get-WmiObject with the Win32_Service Class working perfectly fine to remotely stop/start/restart services remotely. However, I found out that the .StopService() method has been removed in PowerShell 6 (which I used this to bypass the dependencies issues I kept running in to). As well, I have found out that the -ComputerName variable has also been removed from a lot of the different commandlets.
Since the removed the -ComputerName from things like the Stop-Service commandlet, I am struggling to figure out how to properly handle the stopping of the service itself. I can retrieve the service or services I want without issue. I just can't seem to figure out how to handle stopping the service.
Tried being as detailed as I can. I know I am missing something stupidly small, but all of my Google searches appear to return everything with PowerShell 5, but so little on 6.
Thanks.
Ok, nevermind about this question. I decided to approach my Google searching another way and I stumbled upon the syntax I needed. For those of you wondering, you cannot run commands straight from the returned object. So for example, you could do "$service.StopService()" straight on the service previously. However, now you have to do an invoke of that StopService method by doing "Invoke-CimMethod -Name StopService" and that is only after you pipe the Get-CimInstance returned object to it. So the full syntax would look something like this.
get-ciminstance win32_service -filter "Name='spooler'" | Invoke-CimMethod -Name StartService
A really good website I found to explain and give really good examples of why and how the Cim Instances are they way they are.
https://4sysops.com/archives/managing-services-the-powershell-way-part-7

How do I run Invoke-WebRequest cmdlet from third party program?

I have been trying to get this to work via a game control panel TCAdmin.
$ModPg1 = Invoke-WebRequest "http://steamcommunity.com/sharedfiles/filedetails/?id=731604991"
$ModVer1 = ($ModPg1.ParsedHtml.getElementsByTagName('div') | Where{ $_.className -eq 'detailsStatRight' } ).innerText | Select -Last 1
If I run this cmdlet via a program like TCAdmin (or task scheduler), I get the following error....
Invoke-WebRequest : The response content cannot be parsed because the Internet Explorer engine is not available, or Internet Explorer's first-launch configuration is not complete. Specify the UseBasicParsing parameter and try again.
Explorer is installed, and set up. The script works just fine if I run it manually.
My guess is there is a way to get TCAdmin to run the scripts the same way I would as a windows User.
Cant find a way nearly as simple to scrape the info 'm looking for.
As for this...
get TCAdmin to run the scripts the same way I would as a windows User.
For any app to run as a user, that users profile must be used on the host where the code is to be run. You cannot natively run PoSH on a host as another user context. This is not a PoSH issue, it is a Windows User Principal security boundary. There are tools that let you do this. For example SysInternal PSExec and AutoIT. Yet as stated that error is pretty specific. The user profile for Internet Explorer has not been created and that only happens when you use IE at least once.
So, as Adam points, out, use the setting the error message states to use or use your code to start IE at least once.
$SomeUrl = 'https://stackoverflow.com'
$ie = New-Object -com internetexplorer.application
$ie.visible = $true
$ie.navigate($SomeUrl)
while ($ie.Busy -eq $true) { Start-Sleep -Seconds 1 } # Wait for IE to settle.
Again, if trying to run this in the context of another user, the two above tools will get you there, but you still have to fire up IE to have a profile for it.

Trouble with Remote Sessions and Exchange 2007 Servers

Anyway, I'm working on some Powershell scripts for work, and I'm stuck on something I thought would be fairly simple. Basically, there are some tasks that I need to perform on our Exchange server that would be great to script. I spent time writing a script that would connect me to our server (on the same domain), and run invoke-command for a few test commands. Once I get the test commands running, I can actually start writing the meat of the script.
For now however, I'm stuck just getting get-mailbox to return any information, which is really just me trying to test that things are working. See the three lines of test code here:
$mainSession = New-PSSession -ComputerName TheServerName
invoke-command -session $mainSession -ScriptBlock {add-pssnapin Microsoft.Exchange.Management.Powershell.Admin}
invoke-command -session $mainSession -ScriptBlock {get-mailbox}
I get a "psremotingtransportexception" exception with a "Job_Failure" error. What could this be? I know the snap-in and get-mailbox commands work when I actually log-in to the server via remote-desktop and test them out. Assuming I can get get-mailbox to function, I could actually perform the more complicated tasks I want to put in the script. The Exchange Server I'm connecting to is pretty old (2007?), so it's not that I'm using the wrong snap-in. Am I missing some credentials? Right now it's not asking me for any, but I tried adding the -credential flag and that didn't help either.
I'm super new to Powershell, so any help is greatly appreciated. Here is the exact error, apologies for the crap formatting:
Processing data for a remote command failed with the following error message: The WSMan provider host process did not return a proper response. A provider in the host process may have behaved improperly. For more information, see the about_Remote_Troubleshooting Help topic. + CategoryInfo : OperationStopped: (System.Manageme...pressionSyncJob:PSInvokeExpressionSyncJob) [], PSRemotingTransportException + FullyQualifiedErrorId : JobFailure
I should mention that I already tried increasing the shell MB size via set-item wsman:\localhost\shell\MaxMemoryPerShellMB 1024 -force. My best guess is this has something to do with the -credential flag but so far I haven't had any success with it.
Official support for remote Exchange administration with PowerShell was added in Exchange 2010, I believe.
It seems at least one person has found a way to make it work with Exchange 2007.
Sorry for the link-only answer, but the solution seems to be pretty involved, using impersonation, a special user account created for this purpose, script modules that have to be installed on the exchange server, etc.
Given this solution, I wonder if you could make it work more simply by using a PowerShell endpoint running as an exchange administrator. That would be cleaner than this mess. Basically you would create the endpoint, set the RunAsUser, and then you could use StartupScript to add the snapin. I really can't say if this will work though and I have no access to a Exchange 2007 environment where I could test it.