Powershell: Net.Webclient - not getting reply from intranet depending on machine - powershell

Cheers everyone,
I am getting the weirdest problem for which I need your helping ideas how to approach the issue.
So, I have a download script that pulls content off a company intranet using Webclient objects. It requires credentials and it is working on about 80% of the computers. The script pulls a listing using .DownloadString and then parses and gets some files using .DownloadFile.
On the machines that won't work the initial .DownloadString hangs until it appears to run into a timeout and returns $null.
User credentials are irrelevant on these types of machines meaning a user that works on another machine fails on this one.
Addresses, if entered into browser returns content.
Spoken in code I try it this way:
$wc = new-object System.Net.WebClient
$wc.Credentials = new-object System.Net.NetworkCredential($user, $pass, $domain)
$old_eap = $ErrorActionPreference
$ErrorActionPreference = "Stop"
try
{
$tmp = $wc.DownloadString($url)
if ([String]::IsNullOrEmpty($tmp))
{
throw "Intranet server did not return directory listing"
}
Return $tmp #the code is actually part of a function...
}
catch
{
write-error $_.Exception.Message
Return $null
}
finally
{
$ErrorActionPreference = $old_eap
}
I have no idea other than looking for changed settings between different machines. But which settings could be relevant for Webclient behaving like this? Any Ideas? I am seriously stuck...
I forgot... To make things a little easier I am stuck with Version 2.0 and we cant update yet. Bummer...
Thanks in advance
Alex

Maybe try to use xmlhttp as a client. Below is the usage example.
$url = "https://example.com/"
$http = New-Object -ComObject Msxml2.XMLHTTP
$user = "Domain\username"
$pwd = "password"
$utf = [System.Text.Encoding]::UTF8
$http.open("GET", $url, $false, $user, $pwd)
$http.send()
$result = $utf.GetString($http.responseBody)

Related

Why am I getting "SessionOptions.SshHostKeyFingerprint is not set." even though I have the finger print in the script

I am using SFTP to transfer files to a remote server but I keep getting
SessionOptions.SshHostKeyFingerprint is not set.
I referenced this documentation from WinSCP WinSCP .NET Assembly and COM Library
What am I doing wrong? See script below:
try
{
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "psftp-nesam.ms.com"
UserName = "test"
Password = "MSR4sssssnd5"
SshHostKeyFingerprint = "ssh-rsa 1024 +3t0xkOMWqfA7IaH0itjW/w7FQN+EtVyLDMTXk+D300=
ssh-rsa 1024 23:6f:82:11:ec:b1:1a:82:95:1b:ed:7e:96:24:d0:11"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Upload files
$transferOptions = New-Object WinSCP.TransferOptions
$transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
$transferResult =
$session.PutFiles("E:\CMBPAID\BPAID0224_122700.csv", "/NESAMSCARIMED", $False, $transferOptions)
# Throw on any error
$transferResult.Check()
# Print results
foreach ($transfer in $transferResult.Transfers)
{
Write-Host "Upload of $($transfer.FileName) succeeded"
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
exit 0
}
catch
{
Write-Host "Error: $($_.Exception.Message)"
exit 1
}
The easy way to get a correct key is to run the WinSCP application, login to the SFTP server you want to access, then select from drop down menu at top "Sessions->Generate Session URL/Code...". This will display a nice dialog box with different ways to write code to connect to this session. The tab ".NET assembly code" has all the code you need to make the same connection, including the "SshHostKeyFingerprint".
With your code I'm getting a different error message (but it can be a root cause of your error message):
The value supplied is not valid, or the property is read-only. Change the value, and then try again.
What is correct, as your syntax of a SshHostKeyFingerprint value is wrong.
If you want to specify multiple alternative fingerprints, separate them by a semicolon, not a new-line:
SshHostKeyFingerprint = "ssh-rsa 1024 +3t0xkOMWqfA7IaH0itjW/w7FQN+EtVyLDMTXk+D300=;ssh-rsa 1024 23:6f:82:11:ec:b1:1a:82:95:1b:ed:7e:96:24:d0:11"
With this change, your code works for me.

Test app link with powershell

I am using powershell to do some monitoring and I want to check if an application's jnlp
exists on a website and is available for downloading.
I have the link to the .jnlp and so far I'm downloading the file with .navigate().
$ie = new-object -com "InternetExplorer.Application"
Try {
$ie.navigate("http://bla.com/testApp.jnlp")
} Catch {
#$_
$ErrorMessage = $_.Exception.Message
}
I tried to catch an exception by giving invalid filename but it doesn't work.
Also I thought of downloading the app and try to delete the file afterwards so as to
check that it actually exists but it would be too slow since I have many jnlps to check.
Is there another more simple and elegant way to do so? I want to avoid the downloading of
each file I want to test.
How about using WebClient class from .Net? Getting data is simple enough. Like so,
$webclient = new-object System.Net.WebClient
try {
# Download data as string and store the result into $data
$data = $webclient.DownloadString("http://www.google.com/")
} catch [Net.WebException] {
# A 404 or some other error occured, process the exception here
$ex = $_
$ex.Exception
}
If you're using PowerShell 3.0 or higher, you can use Invoke-WebRequest to see if a page exists by issuing an HTTP HEAD request and checking the status code.
$Result = Invoke-WebRequest -uri `http://bla.com/testApp.jnlp` -method head
if ($Result.StatusCode -ne 200){
# Something other than "OK" was returned.
}
This is doable with System.Net.WebClient as well but it's a bit more effort.

ftp via powershell - how to indicate success

I'm using a Powershell script to automate sending a .txt to an FTP site. When I execute it in powershell, nothing happens. The root\prompt just appears...no messages that it was successful. How do I tell if it worked? Here is my script in case it helps.
$localfile = "D:\Export\TESTING.txt"
$remotefile = "/TESTING.txt"
$ftphost = "ftp://ftp.site.com"
$URI = $ftphost + $remotefile
$username="USERNAME"
$password="1234"
function Get-FTPFile
($URI,$localfile,$username,$password){
$credentials=New-Object System.Net.NetworkCredential
($username,$password)
$ftp=[System.Net.FtpWebRequest]::Create($URI)
$ftp.Credentials=$credentials
$ftp.UseBinary=1
$ftp.KeepAlive=0
$response=$ftp.GetResponse()
$responseStream = $response.GetResponseStream()
$file = New-Object
IO.FileStream ($localfile,[IO.FileMode]::Create)
[byte[]]$buffer = New-Object byte[] 1024
$read = 0
do{
$read=$responseStream.Read($buffer,0,1024)
$file.Write($buffer,0,$read)
}
while ($read -ne 0)$file.close()
}
Use WebRequestMethods.Ftp.GetFileSize following completion of the upload to confirm that the uploaded file size matches the local file size.
You could also use a try/catch block to check for exceptions during your read/write operations. A lack of exceptions would give you some confidence that the upload was successful (i.e. no news is good news).

Get email using PowerShell

All I need is get email in PowerShell Script and see at its topic - with pop3 or imap, doesnt matter.
I tried to find solution, but all I found is either 3rd party .net assebmlies, or MS Exchange direct work. Both are not appropriate.
How to use SMTP and send email - its absolutely clear, but how to receive? Isn't there any standard assemblies similar to System.Net.Mail?
Here is a code I have been using on c#. I have Imported the dll to powershell and used it to retrieve different parts of a message. The dll I used is Imapx2 which is an open source. I understand that you don't want to use a third party .NET assemblies but this might help other people trying to reach to this content.
### Import the dll
[Reflection.Assembly]::LoadFile(“YourDirectory\imapx.dll”)
### Create a client object
$client = New-Object ImapX.ImapClient
###set the fetching mode to retrieve the part of message you want to retrieve,
###the less the better
$client.Behavior.MessageFetchMode = "Full"
$client.Host = "imap.gmail.com"
$client.Port = 993
$client.UseSsl = $true
$client.Connect()
$user = "User"
$password = "Password"
$client.Login($user,$password)
$messages = $client.Folders.Inbox.Search("ALL", $client.Behavior.MessageFetchMode, 1000)
foreach($m in $messages){
$m.Subject
foreach($r in $m.Attachments){
$r | Out-File "Directory"
}
}
I hope this was helpful
I used the suggestion of Falah Abu Hassan and it worked very well for my requirements for receiving mails via IMAP!
How to get the IMAPX.DLL
The Github Repository for imapx is found here:
https://github.com/azanov/imapx
Unfortunably you have to compile it yourself with "Visual Studio" to get the imapx.dll.
Creation of an sample Powershell Script
The Script and the DLL should be placed side and can integrated with this:
$path = Split-path $script:MyInvocation.MyCommand.Path
[Reflection.Assembly]::LoadFile(“$path\imapx.dll”)
The following example script, inspired by the answer from Falah Abu Hassan worked very well for me:
$path = Split-path $script:MyInvocation.MyCommand.Path
[Reflection.Assembly]::LoadFile(“$path\imapx.dll”)
### Create a client object
$client = New-Object ImapX.ImapClient
$client.Behavior.MessageFetchMode = "Full"
$client.Host = "Servername"
$client.Port = 993
$client.UseSsl = $true
$client.IsDebug = $true
$client.ValidateServerCertificate = $true
$client.Connect()
$user = "login#domain"
$pass = 'password'
$client.Login($user, $pass)
$messages = $client.Folders.Inbox.Search("ALL", $client.Behavior.MessageFetchMode, 100)
write-host "Count found: $($messages.count)"
foreach($m in $messages){
write-host "Processing Subject: $($m.Subject)"
}

How to make an authenticated web request in Powershell?

In C#, I might do something like this:
System.Net.WebClient w = new System.Net.WebClient();
w.Credentials = new System.Net.NetworkCredential(username, auth, domain);
string webpage = w.DownloadString(url);
Is there a Powershell version of this, or should I just call through to the CLR?
The PowerShell is almost exactly the same.
$webclient = new-object System.Net.WebClient
$webclient.Credentials = new-object System.Net.NetworkCredential($username, $password, $domain)
$webpage = $webclient.DownloadString($url)
For those that need Powershell to return additional information like the Http StatusCode, here's an example. Included are the two most likely ways to pass in credentials.
Its a slightly modified version of this SO answer:
How to obtain numeric HTTP status codes in PowerShell
$req = [system.Net.WebRequest]::Create($url)
# method 1 $req.UseDefaultCredentials = $true
# method 2 $req.Credentials = New-Object System.Net.NetworkCredential($username, $pwd, $domain);
try
{
$res = $req.GetResponse()
}
catch [System.Net.WebException]
{
$res = $_.Exception.Response
}
$int = [int]$res.StatusCode
$status = $res.StatusCode
return "$int $status"
In some case NTLM authentication still won't work if given the correct credential.
There's a mechanism which will void NTLM auth within WebClient, see here for more information: System.Net.WebClient doesn't work with Windows Authentication
If you're trying above answer and it's still not working, follow the above link to add registry to make the domain whitelisted.
Post this here to save other's time ;)