How do I query saved wireless profiles? - c#

I have used both Batch and shell scripts to accomplish this, however, the fact that I have to go one by one through the saved xml files is a bit tedious.
I am trying to find a way to accomplish this through the NativeWifi API (found here here) However all I get are the available wireless access points and their signal strength.
Current goal for this question: retrieve saved wireless profiles in a folder if a physical wireless adapter exists.
BATCH FILE:
set wlanfld="WirelessProfiles"
if not exist %wlanfld% md %wlanfld%
echo off
netsh wlan export profile folder=%wlanfld% key=clear
setlocal enabledelayedexpansion
for /r %wlanfld% %%a in (*.xml) do (
set oldName=%%~xna
set newName=!oldName:~28!
ren "%%a" "!newName!"
)
Then here is a snippet of the code.
private void wifiButton_Click(object sender, EventArgs e)
{
textBox2.Text = "";
System.Diagnostics.Process.Start(#"c:\\Users\jpearson\Documents\Visual Studio 2013\Projects\ComplianceGuide\ComplianceGuide\wifi.bat");
Process.Start(#"c:\\Users\jpearson\Documents\Visual Studio 2013\Projects\ComplianceGuide\ComplianceGuide\bin\Debug\WirelessProfiles");
WlanClient client = new WlanClient();
foreach (WlanClient.WlanInterface wlanIFace in client.Interfaces)
{
Wlan.WlanAvailableNetwork[] networks = wlanIFace.GetAvailableNetworkList(0);
foreach (Wlan.WlanAvailableNetwork network in networks)
{
wifiBox.Text += String.Format("{0} Signal Quality {1}" + Environment.NewLine, GetString(network.dot11Ssid), network.wlanSignalQuality);
}
}
}

Related

C# multi-hop SSH (SSH through SSH)

I wrote a C# console program to connect from A (Windows 10, Console C# app) over SSH to B (Linux server) and from there on to C (Linux server), but I cannot connect from B to C (from A to B is ok).
When I connect from A over Windows terminal to B and from B's terminal to C, it works, so I proved that my credentials are fine.
I am using Renci.SshNet for C#
I created a class Server with a .Connect(), .Disconnect() and .Execute() extension methods and then the two class instances Broker and Destination
My code looks like:
if (Broker.Connect())
{
Broker.Execute("pwd");
if (Destination.Connect())
{
Destination.Execute("pwd");
Destination.Disconnect();
}
Broker.Disconnect();
}
The Ssh connection objets are created like var broker = new SftpClient("Ip", Port, "User", "Pass")
Then I am internally using broker.Connect() and broker.Disconnect() in Renci.Ssh.Net lib given methods
To broker.Execute("cmd") I basically do
var output = host.Ssh.RunCommand(str);
var res0 = output.ExitStatus;
var res1 = output.Result;
var res2 = output.Error;
My code works for the first part as I manage to get the output of Broker.Execute("pwd") but it does not connect on Destination.Connect() returning the message A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
My aim ist to multi-hop using an automated process from within C#: users must not interact with any console and I cannot modify nor store any files on the Linux sites
Any idea where the problem lies?
Thanks in advance,
I will like to summarize here how I ended solving this issue with the help of some valuable hints gathered over the net and from #jeb:
Open a cmd.exe console, type ssh userC#hostC -p portC-J userB#hostB - p portB (portB and portC can be ommited if they are the default port 22) and then you will be promped to enter passwordB and passwordC - in this order.
If the connection succeeded you will be then on the hostC console and will manage to do whatever you intend to do.
The code you'll need is:
static void RunSshHop(params string[] cmds)
{
try
{
using (Process p = new Process())
{
p.StartInfo = new ProcessStartInfo("cmd.exe")
{
RedirectStandardInput = true,
UseShellExecute = false,
//WorkingDirectory = #"d:\" // dir of your "cmd.exe"
};
p.OutputDataReceived += p_DataReceived;
p.ErrorDataReceived += p_DataReceived;
p.Start();
// way 1: works
foreach (var e in cmds)
p.StandardInput.Write($"{e}\n"); // cannot use 'WriteLine' because Windows is '\r' and Linux is '\n'
/* way 2: works as well
using (var sw = p.StandardInput)
{
foreach (var e in cmds)
if (sw.BaseStream.CanWrite)
sw.Write($"{e}\n"); // cannot use 'WriteLine' because Windows is '\r' and Linux is '\n'
}
//*/
p.WaitForExit();
if (p.HasExited)
{
Console.WriteLine($"ExitCode: {p.ExitCode}");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
And you can call it like this:
static void Main(string[] args)
{
RunSshHop(
"ssh userC#hostC -p portC-J userB#hostB - p portB",
"pwd",
//"...",
"ls"
);
}
To avoid having to enter the passwords for each host, you can also create an SSH key pair like this:
open cmd.exe console
type ssh-keygen -t rsa
choose path where to save the public and private keys that are to be generated (press enter to use the default destination)
copy the destination, you will need it later to get back yxour keys :-)
to manage an automated process, you have to leave the passphrase empty
-once the keys are generated, log onto the first host over ssh like ssh youruser#firsthost -p hostport (the -p hostport part can be ignored if port is the default 22)
type ssh-copy-id youruser#firsthost -p hostport
accept
repeat the process for the second host

Monitor FTP directory in ASP.NET/C#

I have FileSystem watcher for a local directory. It's working fine. I want same to implement for FTP. Is there any way I can achieve it? I have checked many solutions but it's not clear.
Logic: Want to get files from FTP later than some timestamp.
Problem faced: Getting all files from FTP and then filtering the result is hitting the performance (used FtpWebRequest).
Is there any right way to do this? (WinSCP is on hold. Cant use it now.)
FileSystemWatcher oFsWatcher = new FileSystemWatcher();
OFSWatchers.Add(oFsWatcher);
oFsWatcher.Path = sFilePath;
oFsWatcher.Filter = string.IsNullOrWhiteSpace(sFileFilter) ? "*.*" : sFileFilter;
oFsWatcher.NotifyFilter = NotifyFilters.FileName;
oFsWatcher.EnableRaisingEvents = true;
oFsWatcher.IncludeSubdirectories = bIncludeSubdirectories;
oFsWatcher.Created += new FileSystemEventHandler(OFsWatcher_Created);
You cannot use the FileSystemWatcher or any other way, because the FTP protocol does not have any API to notify a client about changes in the remote directory.
All you can do is to periodically iterate the remote tree and find changes.
It's actually rather easy to implement, if you use an FTP client library that supports recursive listing of a remote tree. Unfortunately, the built-in .NET FTP client, the FtpWebRequest does not. But for example with WinSCP .NET assembly, you can use the Session.EnumerateRemoteFiles method.
See the article Watching for changes in SFTP/FTP server:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "example.com",
UserName = "user",
Password = "password",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
List<string> prevFiles = null;
while (true)
{
// Collect file list
List<string> files =
session.EnumerateRemoteFiles(
"/remote/path", "*.*", EnumerationOptions.AllDirectories)
.Select(fileInfo => fileInfo.FullName)
.ToList();
if (prevFiles == null)
{
// In the first round, just print number of files found
Console.WriteLine("Found {0} files", files.Count);
}
else
{
// Then look for differences against the previous list
IEnumerable<string> added = files.Except(prevFiles);
if (added.Any())
{
Console.WriteLine("Added files:");
foreach (string path in added)
{
Console.WriteLine(path);
}
}
IEnumerable<string> removed = prevFiles.Except(files);
if (removed.Any())
{
Console.WriteLine("Removed files:");
foreach (string path in removed)
{
Console.WriteLine(path);
}
}
}
prevFiles = files;
Console.WriteLine("Sleeping 10s...");
Thread.Sleep(10000);
}
}
(I'm the author of WinSCP)
Though, if you actually want to just download the changes, it's a way easier. Just use the Session.SynchronizeDirectories in the loop.
while (true)
{
SynchronizationResult result =
session.SynchronizeDirectories(
SynchronizationMode.Local, "/remote/path", #"C:\local\path", true);
result.Check();
// You can inspect result.Downloads for a list for updated files
Console.WriteLine("Sleeping 10s...");
Thread.Sleep(10000);
}
This will update even modified files, not only new files.
Though using WinSCP .NET assembly from a web application might be problematic. If you do not want to use a 3rd party library, you have to do with limitations of the FtpWebRequest. For an example how to recursively list a remote directory tree with the FtpWebRequest, see my answer to List names of files in FTP directory and its subdirectories.
You have edited your question to say that you have performance problems with the solutions I've suggested. Though you have already asked a new question that covers this:
Get FTP file details based on datetime in C#
Unless you have access to the OS which hosts the service; it will be a bit harder.
FileSystemWatcher places a hook on the filesystem, which will notify your application as soon as something happened.
FTP command specifications does not have such a hook. Besides that it's always initiated by the client.
Therefor, to implement such logic you should periodical perform a NLST to list the FTP-directory contents and track the changes (or hashes, perhaps (MDTM)) yourself.
More info:
FTP return codes
FTP
I have got an alternative solution to do my functionality.
Explanation:
I am downloading the files from FTP (Read permission reqd.) with same folder structure.
So everytime the job/service runs I can check into the physical path same file(Full Path) exists or not If not exists then it can be consider as a new file. And Ii can do some action for the same and download as well.
Its just an alternative solution.
Code Changes:
private static void GetFiles()
{
using (FtpClient conn = new FtpClient())
{
string ftpPath = "ftp://myftp/";
string downloadFileName = #"C:\temp\FTPTest\";
downloadFileName += "\\";
conn.Host = ftpPath;
//conn.Credentials = new NetworkCredential("ftptest", "ftptest");
conn.Connect();
//Get all directories
foreach (FtpListItem item in conn.GetListing(conn.GetWorkingDirectory(),
FtpListOption.Modify | FtpListOption.Recursive))
{
// if this is a file
if (item.Type == FtpFileSystemObjectType.File)
{
string localFilePath = downloadFileName + item.FullName;
//Only newly created files will be downloaded.
if (!File.Exists(localFilePath))
{
conn.DownloadFile(localFilePath, item.FullName);
//Do any action here.
Console.WriteLine(item.FullName);
}
}
}
}
}

How to get notifications for File Changes on CD / DVD drive?

I am new to C# and have to develop a Windows Form application in C#. This application should track the following things.
Monitor the CD / DVD drives both external and internal.
Monitor the files which are created, modified and deleted on the CD/DVD drives.
I am able to get system notification for CD/DVD drive insertion by RegisterNotification and by tracking WM_DEVICECHANGE messages in the WndProc method.
The above implementation lets me know when a new device has been attached to the PC.
The problem I am facing is how track the file changes which happen on the CD/DVD (Writes / Modification). One option is to poll for the files in the CD / DVD as a background job. But, this will be as the last option.
I have found IMAPIthrough which we can write to CD/DVDs but I just need to monitor the file changes for audit purposes.
Kindly point me to right direction on how to receive file changes on the CD/DVD notification in my program ?
I have tried FileSystemWatcher but it doesn't seem to work with CD/DVD drives.
Updated on 07-Feb-2018:
The another approach I could find was via WMIqueries which are attached to WMI Events. I have found a question Best way to detect dvd insertion in drive c# which could also hold the answer. I wanted to know if the detection of DVD file system modification is feasible in WMI and if any experts can share the query for the same. I hope if Arshad would be able to help in this area.
Approach 1 : Using FileSystemWatcher
public void ListOpticalDiscDrivesAndWatchRootDirectory()
{
var drives = DriveInfo.GetDrives();
foreach (var drive in drives)
{
if (drive.IsReady && drive.DriveType == DriveType.CDRom)
{
var rootDirectory = drive.RootDirectory.ToString();
Console.WriteLine(rootDirectory);
Watch(rootDirectory);
}
}
}
private void Watch(string path)
{
var watcher = new FileSystemWatcher
{
Path = path,
NotifyFilter = NotifyFilters.Attributes |
NotifyFilters.CreationTime |
NotifyFilters.DirectoryName |
NotifyFilters.FileName |
NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.Security |
NotifyFilters.Size,
Filter = "*.*",
EnableRaisingEvents = true
};
watcher.Changed += new FileSystemEventHandler(OnChanged);
}
private void OnChanged(object source, FileSystemEventArgs e)
{
Console.WriteLine("Something changed!");
}
Approach 2 : Using WMI
There's a code project sample (VBScript) describing how to use WMI for file system monitoring. I used the query from that sample in the C# snippet below :
using System;
using System.Management;
public class OpticalDriveWatcher
{
private ManagementEventWatcher _wmiWatcher = new ManagementEventWatcher();
public ManagementEventWatcher WmiWatcher
{
get { return _wmiWatcher; }
}
private void OnWmiEventReceived(object sender, EventArrivedEventArgs e)
{
Console.WriteLine("WMI event!");
}
public void WatchWithWMI(string path)
{
string queryString = "Select * From __InstanceOperationEvent "
+ "WITHIN 2 "
+ "WHERE TargetInstance ISA 'CIM_DataFile' "
+ $"And TargetInstance.Drive='{path}'";
WqlEventQuery wmiQuery = new WqlEventQuery(queryString);
WmiWatcher.Query = wmiQuery;
WmiWatcher.Start();
}
}
The catch is that CIM_DataFile returns only instances of files on local fixed disks. You can call this as follows
var detector = new OpticalDriveDetector();
var drive = "I:"; //You could get the optical drive you want to watch with DriveInfo as described in approach 1
detector.WatchWithWMI(drive);
detector.WmiWatcher.EventArrived += detector.OnWmiEventReceived;
Both approaches worked fine for me when I tested with a DVD-RAM.

Hostname scanning in C#

Iv'e recently started a new job as an ICT Technician and im creating an Console application which will consists of stuff that will help our daily tools!
My first tool is a Network Scanner, Our system currently runs on Vanilla and Asset tags but the only way we can find the hostname / ip address is by going into the Windows Console tools and nslookup which to me can be improved
I want to create an application in which I enter a 6 digit number and the application will search the whole DNS for a possible match!
Our hostsnames are like so
ICTLN-D006609-edw.srv.internal the d 006609 would be the asset tag for that computer.
I wish to enter that into the Console Application and it search through every hostname and the ones that contain the entered asset tag within the string will be returned along with an ip and full computer name ready for VNC / Remote Desktop.
Firstly how would I go about building this, shall i start the project of as a console app or a WPF. can you provide an example of how I can scan the hostnames via C#, or if there's an opensource C# version can you provide a link.
Any information would be a great help as it will take out alot of issues in the workpalce as we have to ask the customer to go into there My Computer adn properties etc and then read the Computer name back to use which I find pointless.
Regards.
Updates:
*1 C# Version I made: http://pastebin.com/wBWxyyuh
I would actually go about this with PowerShell, since automating tasks is kinda its thing. In fact, here's a PowerShell script to list out all computers visible on the network. This is easily translatable into C# if you really want it there instead.
function Find-Computer( [string]$assetTag ) {
$searcher = New-Object System.DirectoryServices.DirectorySearcher;
$searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry;
$searcher.SearchScope = 'Subtree';
$searcher.PageSize = 1000;
$searcher.Filter = '(objectCategory=computer)';
$results = $searcher.FindAll();
$computers = #();
foreach($result in $results) {
$computers += $result.GetDirectoryEntry();
}
$results.Dispose(); #Explicitly needed to free resources.
$computers |? { $_.Name -match $assetTag }
}
Here's a way you can accomplish this, although it's not the best. You might consider hitting Active Directory to find the legitimate machines on your network. The code below shows how you might resolve a machine name, and shows how to ping it:
static void Main()
{
for (int index = 0; index < 999999; index++)
{
string computerName = string.Format("ICTLN-D{0:000000}-edw.srv.internal", index);
string fqdn = computerName;
try
{
fqdn = Dns.GetHostEntry(computerName).HostName;
}
catch (SocketException exception)
{
Console.WriteLine(">>Computer not found: " + computerName + " - " + exception.Message);
}
using (Ping ping = new Ping())
{
PingReply reply = ping.Send(fqdn);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine(">>Computer is alive: " + computerName);
}
else
{
Console.WriteLine(">>Computer did not respond to ping: " + computerName);
}
}
}
}
Hope that helps...

Get the list of all SSIDs and their mac address

Is there a way to get a list of all SSID's and their mac address of reachable signals in my area?
I tried the Nativ WlanApi in my c# code. What I get is the list of all ssid's, but for
getting their mac address, I don't have any idea.
This is the code I using for getting the list:
private void show_all_ssids_Click(object sender, EventArgs e)
{
WlanClient client = new WlanClient();
foreach ( WlanClient.WlanInterface wlanIface in client.Interfaces )
{
// Lists all available networks
Wlan.WlanAvailableNetwork[] networks = wlanIface.GetAvailableNetworkList( 0 );
this.ssidList.Text = "";
foreach ( Wlan.WlanAvailableNetwork network in networks )
{
//Trace.WriteLine( GetStringForSSID(network.dot11Ssid));
this.ssidList.Text += GetStringForSSID(network.dot11Ssid) + "\r\n";
}
}
}
static string GetStringForSSID(Wlan.Dot11Ssid ssid)
{
return Encoding.ASCII.GetString(ssid.SSID, 0, (int)ssid.SSIDLength);
}
I hope there is a way.
In order to get a MAC address you would need to connect to that wireless network. Once you are connected you should be able to get the MAC address of machines on the immediate network using the same methods that you might for traditional wired networks - I believe that the best way of doing that would be by parsing the output of the arp -a command.
this is the solution:
Dim networksBss As Wlan.WlanBssEntry() = SelectedWifiAdapter.GetNetworkBssList()
For car = 0 To networksBss(i).dot11Bssid.Length - 1
If Len(Hex(networksBss(i).dot11Bssid(car))) = 1 Then ThisScan(i).MAC = ThisScan(i).MAC & "0"
ThisScan(i).MAC = ThisScan(i).MAC & Hex(networksBss(i).dot11Bssid(car)) & ":"
Next
anyway i'm still looking for a way to find details (strenght) of networks with SSID="" associating it with the proper MAC.

Categories