Или как я сделал недо-sudo для Windows 7
У меня для работы понаписана куча батников для всяких мелких задач: перенастройки сетевых соединений, включения/отключения устройств и т.д. Некоторые команды требуют повышения уровня доступа до администратора, потому батники отказались на семерке работать.
Поскольку работаю я в основном в консоли, да и рабочий стол захламлять не охота, то от создания кучи ярлыков на нужные батники я отказался. Про штатный runas
в Windows я знаю, но он меня тоже не устроил. Хотелось, чтоб как в новом Far Manager’е — при необходимости выполнить операцию от имени администратора, выскакивало стандартное окошко виндового UAC, запрашивалось подтверждение и выполнялась нужная команда.
В общем решил я написать быстренько свой недо-sudo на C#, благо действительно получилось быстро и удобно.
Способ, вполне штатный, произвести такое дело с помощью C# есть, но о нем ближе к концу. Пока скажу, что для запуска внешнего процесса нужен будет полный путь к исполняемому файлу, а прописывать его каждый раз очень сильно влом, потому батники пусть лежат в каталоге, доступном в PATH
, а нам придется немного «прикинуться операционкой» и вести себя как она. А операционка действует просто. Если просто введена команда без расширения, то она ищет сначала в текущем каталоге, а потом в каталогах из переменной PATH
файл с расширением .com, .exe, .bat, .cmd
— нашла, значит выполняет.
Так и будем делать.
1. Заводим два массива, со списком расширений и для хранения списка директорий, в которых будем искать файл:
private static string[] FindDirs = null;
private static string[] Extensions = new string[] {"com","exe","bat","cmd"};
2. Функцию для получения списка каталогов из PATH
Копия
3. Функцию, которая будет собирать список каталогов, в которых будет производиться поиск. Не буду здесь ее приводить, она просто добавляет текущую директорию (с помощью Directory.GetCurrentDirectory()
) и список, полученный на предыдущем шаге в массив. См. в классе FindApp
функцию GetFindDirs()
4. Понадобится функция, определяющая по расширению, является ли файл исполняемым. Она тоже довольно проста. См. ссылку выше private static bool IsExecutable(FileInfo fi)
. Структуру FileInfo
сформируем на шаге поиска далее. Она в цикле сравнивает расширение файла, если оно указано, со списком расширений исполняемых файлов.
5. Функцию, которая ищет файл, если расширение не задано private static string FindNoExt(string path, string FileName)
Она проверяет, заканчивается ли путь к директории символом \, в цикле подставляет расширения и проверяет наличие файла по указанному пути с помощью File.Exists()
. Если файл найден — возвращает полный путь, если нет — null
.
Функция Find (string Command)
в классе FindApp
1. Получаем список каталогов, в которых будем искать, с помощью ранее описанной функции GetFindDirs()
2. Создаем класс FileInfo
:
FileInfo fi = new FileInfo(Command);
3. Проверяем, был ли задан путь к исполняемому файлу. Тут надо остановиться немного подробнее. Если в команде Command
путь задан не был, то свойство DirectoryName
класса FileInfo
будет содержать текущий каталог, что никак нам не поможет. Поэтому, надо проверить, был ли задан полный путь. Проще всего это сделать, проверив, содержала ли команда Command символ \:
if (Command.Contains("\\"))
...
4. Если каталог указан, то проверяем, указано ли расширение. Тут можно воспользоваться свойством Extension
структуры FileInfo
. Оно будет пустым, если расширение не задано. Если расширение задано, то проверяем, является ли файл исполняемым, и в случае, если да — возвращаем его полный путь. Если расширение не указано, пытаемся найти в каталоге исполняемый файл с помощью ранее созданной функции FindNoExt
.
5. Если каталог не задан в команде, то выполняем шаг 4 для каждого каталога из списка поиска, пока не найдем файл. Если файл так и не будет найден, значит возвращаем null
.
Выполнение программы организовано в отдельном классе RunApp
Сначала мы должны проверить, а нет ли прав администратора у нас уже. Для этого надо будет подключить пространство имен using System.Security.Principal;
Сама проверка вынесена в отдельную функцию:
public static bool IsAdmin() { WindowsPrincipal pricipal = new WindowsPrincipal( WindowsIdentity.GetCurrent()); return pricipal.IsInRole( WindowsBuiltInRole.Administrator); }
Подключаем пространство имен using System.Diagnostics;
public static bool Excecute(string path, string parameters) { ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = path; psi.Arguments = parameters; bool admin = IsAdmin(); if (!admin) { psi.Verb = "runas"; } try { Process.Start(psi); } catch (Exception ex) { if (admin) //админские права уже были, что-то испортилось { ErrorMessage = ex.Message; return false; } //иначе может быть просто нажали отмену в UAC } return true; }
Сначала формируем структуру ProcessStartInfo
из пути к программе и параметров. Далее проверяем наличие админских прав, если их нет, то указываем системе, что процесс-программу нужно запустить с правами администратора с помощью psi.Verb = "runas";
Далее запускаем процесс.
Проверки, правда, минимальные. И наверняка, кривые.
Ну тут вообще все элементарно. Это консольное приложение, при запуске которого ему передаются в командной строке параметры. Первый — имя вызываемой команды, остальные — ее параметры. См. здесь
Pingback: Глюк с текущим рабочим каталогом в wsudo | Персональный блог Толика Панкова