Как стать автором
Обновить

Комментарии 68

Powershell — настоящий язык программирования, и он обладает потрясающим свойством — стоит только хоть чуть-чуть задуматься о происхождении магических заклинаний с SO, как тебя в полный рост макают в .net. Вместо того, чтобы думать про админские задачи, обнаруживаешь себя в мире волшебных уродливых классов, интерфейсов и монстросити, которая на тебя смотрит со дна .net.


При том, что есть много админских инструментов, которые уводят в недра языка программирования (тот же питон), только .net с C# обладает настолько ярко выраженной ненавистью к красивому и простому.

Э-э-э, а что такого уродливого в классах .NET?

То же, что и в java.


class ReadFromFile
{
    static void Main()
    {
        string text = System.IO.File.ReadAllText(@"C:\Users\Public\TestFolder\WriteText.txt");
        System.Console.WriteLine("Contents of WriteText.txt = {0}", text);
        string[] lines = System.IO.File.ReadAllLines(@"C:\Users\Public\TestFolder\WriteLines2.txt");
        System.Console.WriteLine("Contents of WriteLines2.txt = ");
        foreach (string line in lines)
        {
            Console.WriteLine("\t" + line);
        }
        Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}

(рандомный пример из интернетов).


Я считаю, что оно антигуманно. Сравните с эквивалентом на питоне:


with open("WriteText.txt") as f:
    print(f.read())

with open("WriteText2.txt") as f:
  for line in f.readlines():
     print(line)

Все вот эти class и static void могли быть придуманы только тем, кому насрать на людей, пишущих скрипты.

Так у вас не эквивалент, вот эквивалент на C#

WriteLine(File.ReadAllText("WriteText.txt"));

foreach (var line in File.ReadAllLines("WriteLines2.txt"))
  WriteLine(line);
Все вот эти class и static void могли быть придуманы только тем, кому насрать на людей, пишущих скрипты.
Ну так они и не обязательны. Можно писать без всего этого.

Конечно, можно без этого. Тем паче, что это C#. А сам powershell ещё более ужасающий.


  Begin {
    # If we fail, stop the pipe...
    $ErrorActionPreference = "Stop"
    # Look for the command in PATH
    $cmdinfo = $(Get-Command $cmd)
    if (!$cmdinfo -or !$cmdinfo.Path) {
      throw  [System.IO.FileNotFoundException] "Failed to find $cmd..";
    }
    $fullpath = $cmdinfo.Path
    # Use of System.Diagnostics.Process to launch the command and redirect its STDIN/STDOUT
    $ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo 
    $ProcessInfo.FileName = $fullpath
    $ProcessInfo.RedirectStandardError = $False
    $ProcessInfo.RedirectStandardOutput = $True
    $ProcessInfo.RedirectStandardInput = $True
    $ProcessInfo.UseShellExecute = $False 
    $ProcessInfo.CreateNoWindow = $False;
    if ($cmdpar) {
      $ProcessInfo.Arguments = $cmdpar
    }
    $Process = New-Object System.Diagnostics.Process 
    $Process.StartInfo = $ProcessInfo 
    # Reference to the stream reader and writer for the command's STDOUT / STDIN processing
    $StdInStreamWriter = $null;
    $StdOutStreamReader = $null;
    # Sleep time for polling STDIN. To not slow too much the pipeline processing, 
    # we take 1ms. We have to avoid stressing the CPU with the polling.
    $SleepTime=1;
    # Control of input parameters if any
    if ($bufferedPipe -gt 8000) { $bufferedPipe = 8000; }
    if ($bufferedPipe -lt 0) { $bufferedPipe = 0; }
    # Launch the command 
    $ProcessStarted = $Process.Start()
    if ($ProcessStarted) {
      $StdInStreamWriter = $Process.StandardInput;
      $StdOutStreamReader = $Process.StandardOutput;
      $StdInStreamWriter.AutoFlush = $True;
    } else {
      throw  [System.Exception] "Failed to open $cmd..";
    }
    # We use two FIFO stacks to exchange STDIN and STDOUT stream data between
    # the PowerShell pipeline processing in the 'premise-style' context and the
    # process we have launched for the command. We will feed them in the
    # following two poll subprocesses for STDIN and STDOUT as no async operations
    # are allowed in a 'premise-style' context.
    $StdOutStack = new-object System.Collections.Queue;
    if (!$StdOutStack) {
      throw [System.Exception] "Can't get a stack..."
    }
    $StdInStack = new-object System.Collections.Queue;
    if (!$StdInStack) {
      throw [System.Exception] "Can't get a stack..."
    }
    # We create two poll subprocesses to read from STDOUT and write into STDIN 
    # of the process we have launched for the command. As theses subprocesses  
    # are started from the 'begin' pipeline part of the function, they can then 
    # makes STDOUT read that feed the STDOUT stack and STDIN write from the
    # STDIN stack. Theses operations are not directly doable into the 'process' 
    # pipeline part of the function as it is a 'premise-style' context.
    #
    # STDOUT poll subprocess
    #
    $OutProc = [powershell]::Create().AddScript({
      Param ([parameter(Mandatory=$True)]$args)
      $Process = $args[0]
      $StdOutStreamReader = $args[1]
      $SleepTime = $args[2]
      $cmd = $args[3]
      $StdOutStack = $args[4]
      $debugPipe = $args[5]
      while (!$StdOutStreamReader.EndOfStream) {
        $msgproc = $StdOutStreamReader.ReadLine()
        Write-Output ($cmd+": OUT_S: "+[String]$msgproc)
        try {
          $syncStdOutStack = [System.Collections.Queue]::Synchronized($StdOutStack);
          $syncStdOutStack.Enqueue($msgproc)
        } finally {
          $syncStdOutStack = $null
        }
      }
      if ($debugPipe) { Write-Output ($cmd+": OUT_S terminated.") }
    })
    $tmp = $OutProc.AddParameter("args", @($Process, $StdOutStreamReader, $SleepTime, $cmd, $StdOutStack, $debugPipe))
    $OutJob = $OutProc.BeginInvoke()
    #
    # STDIN poll subprocess
    #
    $InProc = [powershell]::Create().AddScript({
      Param ([parameter(Mandatory=$True)]$args)
      $Process = $args[0]
      $StdInStreamWriter = $args[1]
      $SleepTime = $args[2]
      $cmd = $args[3]
      $StdInStack = $args[4]
      $debugPipe = $args[5]
      $bufferedPipe = $args[6]
   ...

Из рандомного SO ответа про работу с pipe'ом.


Я по своему опыту знаю, то если какой-то инструмент имеет вырвиглазный синтаксис с самого начала, то и вся остальная работа с ним такая же — через ненависть и боль.

Ну что вам на это сказать? Я не знаю, почему ответ был написан так сложно. Может, автор решал какую-то специфичную задачу, требующую указать нестандартные параметры, передаваемые в CreateProcess. Или — чтобы скрипт можно было запустить внутри другого конвейера(pipe) — вложенные конвейеры в Powershell не поддерживаются. А может, он просто не знал как следует Powershell, потому что Powershell не был его основным рабочим языком.
Потому что в Powershell для того, чтобы просто запустить внешнюю команду (исполняемый файл) и перенаправить его стандартный вывод в конвейер (pipe) не нужно делать вообще ничего: достаточно просто набрать имя файла и нажать Enter.
Конвейер в Powershell отличается тем, что по нему передаются не байты, а объекты. Но вывод внешней команды автоматически преобразуется в последовательность объектов Powershell типа String (реализован как тип System.String в .NET). Можно эту последовательность присвоить переменной Powershell: она будет преобразована в массив String, можно — передать на вход другой команды Powershell — например вот эта связка команд отсортирует вывод внешней команды netstat (это — чисто для примера, практического смысла это не имеет):
netstat -n -p TCP | Sort-Object

Можно для дальнейшей обработки сделать разбор строк и преобразовать их в объекты. Например, эта связка команд преобразует все строки выдачи, показывающие соединение, в объект со свойствами LocalIP, LocalPort, RemoteIP, RemotePort, State (и отбросит все строки, не являющиеся соединениями):
netstat -n -p TCP `
 | ?{$_ -match '^\s+(.+?)\s+(.+?):(.+?)\s+(.+?):(.+?)\s+([^\s]+?)\s*$'}`
 | %{New-Object PSObject -Property @{LocalIP=$matches[2];LocalPort=`
 $matches[3]; RemoteIP=$matches[4];RemotePort=$matches[5];State=$matches[6]}}

(пояснение:? — это псевдоним команды Where-Object, % — Foreach-Object, мне так писать сподручнее, но незнающего это может сбить с толку).
Да, регулярка выглядит весьма не наглядно (и мне пришлось потратить минут 15 на ее написание и отладку), но после разбора вывода с ее помощью мы получаем объекты, с которыми дальше работать может быть сильно проще, чем с сырыми строками.
Результат этой последовательности можно присвоить переменной (получится массив объектов) или передать дальше по конвейеру для дальнейшей обработки, в том числе — способом, не слишком просто достижимым стандартными командами обработки строк (например, отбросить все объекты локальных соединений, у которых LocalIP=RemoteIP).
Спасибо, приму на вооружение
вот что меня восхищает в PowerShell, так это обмен не потоком как в архаичных системах, а объектами со всеми их свойствами. Можно и свои свойства и свои объекты динамически заводить.
Может реализация не самая удачная, да и выглядит как обертка над .net, но тем не менее это гигантский шаг вперед со времен дос и юникс
Даже если это и выглядит как плюс это скорее минус. В обычных архаичных системах вам ничто не мешает кидаться json-ом (например). При этом вы на любом этапе можете вклиниться в поток данных сохранить его в файл, или прочитать из файла, или преобразовать, при этом работая с одним потоком данных. Даже можете его посети послать или через UART. А тут куча дополнительных сущностный, причем весьма не тривиальных, которые еще могут и эволюционировать. Но главное это убогий синтаксис, тот же perl, gradle и даже pyton на порядки приятнее. Да лучше php написать чем на ps и работать будет на большем количестве платформ.
Так ведь вам ничто не мешает в современном PS полученный откуда-то JSON прогнать через ConvertFrom-Json и получить на выходе объект соответствующей структуры. Или, наоборот — сконвертировать объект в JSON с помощью ConvertTo-Json (или в один из множества других форматов с помощью команд с глаголом ConvertTo) либо просто перегнать объекты в поток символов банальным вызовом метода ToString().
А насчет ситаксиса… Я вот, к примеру, очень мало знаю perl, и скрипты на нем обычно выглядят для меня «перловой кашей», но я понимаю, что это не дает мне никаких оснований объявлять perl плохим, негодным языком — просто этим инструментом я не владею. Почему в случае с PS не происходит то же самое?
Недостаток «архаичных систем» по сравнению с PS, что в них заметно сложнее манипулировать проходящим по конвейеру потоком символов в случае, если этот поток имеет нетривиальную структуру: ему надо устраивать грамматический разбор перед применением, чтобы структурировать. А по конвейеру PS уже идет структурированный поток объектов, имеющих свойства, к которым можно легко и просто обратиться по их имени, чтобы использовать для фильтрации или обработки.
А эквивалент на Poweshell — он еще проще:
$File = 'имя.файла
Get-Content $File -ReadCount 0
Get-Content $File

Первая команда читает файл целиком в одну строку и кладет ее в конвейер (можно это проверить, передав ее результат в Measure-Object: свойство Count результата будет равно 1), вторая — построчно (в конвейер передаются по одной строки, содержащиеся в файле, проверить можно опять-таки с помощью Measure-Count).
Ну а выдача содержимого конвейера на экран после выполнения команды — это действие Powershell по умолчанию.

Ну давайте меряться.


cat "filename"

Ну, давайте :-):
cat "filename"

У Get-Content есть и такой псевдоним. И псевдоним type (родом из MS DOS) — тоже еcть.
PS С Get-ChildItem/ls/dir ситуация аналогичная.

Ага. Только пользы от него никакой, потому что ни /proc, ни /sys, ни /dev.

Ну, если посмотреть, что показывает Get-PSDrive, то в PS много разных «дисков» в пространстве имен есть, помимо файловой системы: HKLM+HKCU (это реестр), Env, WSMan. А еcли дополнительные компоненты ОС поставить да модули подключить, то может и кое-что дополнительное появиться. Например — AD: (т. е. — каталог Active Directory, DS или LDS). Или «диск» с конфигурацией службы Information Rights Management (это — одно из основных средств задания этой самой конфигурации).
А вообще-то, для полного доступа к конфигурации локальной системы в Windows gwmi (т.е. Get-WmiObject) есть. И Set-WMIInstance.

PS Да, методы администрирования Windows и Linux — они таки отличаются.
PPS На этом соревнование предлагаю считать законченным и, если хотите — признать вас победителем: я на приз в любой дисциплине соревнований типа Windows vs Linux традиционно не претендую. Но, надеюсь, я вас убедил, что Powerhell — он не такой страшный как вам казалось раньше?

Он не страшный. Он уродливый. Я этот поинт с самого начала вёл. Есть языки, которые пишутся с представлением о красоте, а есть языки, в которых "как-то получилось и сойдёт".

«Красота — в глазах смотрящего»((с), AFAIK — перевод с английского фразы О.Уайлда(но это неточно)).
То есть понятие красоты — оно сугубо субъективно.
На этом обсуждение Powershell с вами предлагаю закончить.
Надеюсь, вам никогда не придется администрировать MS Exchange: там Powershell без альтернатив.

Не придётся. Я покинул экосистему windows из-за этой "красоты", в том числе.

Ну я бы отметил, что java и c# и не были изначально скриптовыми языками, чем является python изначально. Да, по моим ощущениям они конечно пытаются и в скриптовые языки войти в последнее время многими упрощениями, но это все равно не то.

Это как сравнивать теплое с мягким, натягивать сову на глобус, ну и другие аналогии придумайте. Очень странно предъявы кидать языкам, которые и не были именно для этого предназначены

Я кидаю предъявы не языку, а человеку, который пытается эту монстросити притащить в администрирование и считает, что так и надо.


ровно так же мы можем обсуждать код для автоматического провиза виртуалок в CI, написанный на boost'е в C++. Неподобающий инструмент, провоцирующий невыносимые условия работы.

А чем Powershell монструозен? Да, считаю, что все, что упрощает мне жизнь в администрировании, имеет право на жизнь. Никого пользоваться не заставляю

Я ж показал чем. Ужасный синтаксис, постоянные отсылки объектную модель .net.

Принял. Но какая альтернатива скриптового администрирования Windows?
Как, например, скриптом создать подключение к VPN не через Powershell?
А от .NET тут только Win.forms, который лишь объединяет несколько скриптов в один с выбором действий через «окошко».

Я последний раз видел винды всерьёз в 2008. В принципе, тот кусок, который мне надо было автоматизировать, мы сделали на winrm, но он оставил примерно такое же ощущение брезгливости и уныния.


Я не знаю ответа "как хорошо и красиво администрировать Windows", и это было одним из ключевых моих мотивов для перехода на Linux. Тогда Ансибла ещё не было. Наверное, сейчас я бы попытался использовать Ансибл.

Если использовать Powershell исключительно как средство доступа к сборкам .NET, то так оно и будет.
Иногда это неизбежно: например, для одновременного доступа к содержимому п/я и к средствам администрирования Exchange нет другого выхода, кроме как использовать Powershell (доступ к администрированию Exchаnge, альтернатив тут нет) и EWS Manged API из .NET (в средствах администрирования Exhange крайне ограничены возможности доступа к содержимому п/я).
Но чаще всего альтернатива есть.

данные для подключению к клиентам с логинами\паролями в облаке гугл? Окей, думаю они в восторге были-бы, если-б узнали.

PS: вообще удивляет, что люди осуществляющую L3 поддержку, не в состоянии автоматизировать свой труд. На данном уровне, руководитель должен решать только административные вопросы.

У нас в конторе даже специально написано каким приложением пользоватся для обмена паролями.

Блин ну не делайте так. Случайно нажмете на не ту ссылку и ваша таблица будет видна всему интернету
А вы не боитесь, что у вас доступы утекут? Начиная с банальной недоработки со стороны Гугла, заканчивая утечкой самой ссылки? Декомпилировать .Net приложение и посмотреть откуда тянутся данные не составит труда, не говоря уже о распространении скрипта в чистом виде
Спасибо, поправил статью, указав, что GD выбран для примера.
Скрипт, естественно, не стоит распространять за пределы собственного использования с оставлением в нем частных данных.
Он предназначен для персонального использования.
С тем же успехом, можно просто передать все имена/пароли/приватные ключи.
Рабочие данные храню не в гугле, а в собственном облаке, но если описывать еще и его, одной статьи не хватит. Впрочем, спасибо за идею, следующая статья будет о быстром разворачивании Nextcloud с ONLYOFFICE
Никто не мешает хранить не в google, а локально, или на своих закрытых ресурсах. Всего-то чутка поправить скрипт.
Данная статья не предназначена для использования as is, а преследует цель показать некоторые приемы работы в powershell
Каждый волен использовать приведенный здесь текст по своему усмотрению.
Вы IMHO зря не написали об этом в статье — что Google Docs в качестве хранилища тут чисто для примера, что из соображений безопасности секретные данные, вроде логинов и паролей, там лучше бы не хранить, ибо можно нарваться.

Писать такое надо, причем — в начале статьи — ибо редкий гуглящий читает нагугленное до конца. У меня был пример — статья в личном блоге про создание кластера DNS в MS Windows.
Статья — наполовину шуточная: отказоустойчивость в системе DNS отлично обеспечивается другими средствами. И шуточная она именно наполовину, ибо вообще-то иллюстрирует, как можно добавить в кластер MS FT произвольный сервис, вместе с его конфигурацией в файловой системе и в реестре (собственно, для этого она и была написана). А сервис DNS был выбран в качестве примера только потому, что немногим ранее на мой любимый админский форум приперся некий оригинал (то ли неадекват, то ли, типа, тонкий тролль), который требовал, просил и умолял, чтобы его научили созданию кластера DNS — притом, что ему сразу объяснили, как надо делать DNS отказоустойчивым штатными методами.
Так вот, несмотря на примечание в конце статьи о шуточном характере выбранного примера, я регулярно наблюдал попытки использовать эту статью в качестве руководства по развертыванию DNS в кластере — пока, наконец, не написал предупреждение крупными буквами в самом начале статьи.

Спасибо, внес правки в статью.

Скриншот работающего приложения с затертыми данными:
Все бы ничего, но если вы тестовый гуглодок предоставляете, то и скриншот можно было бы с него сделать. И выглядело бы прилично. А то показывать скриншоты, с затертыми ластиком данными, это прям неуважение к читателям в наше время. Смотрится очень очень плохо.

Да и код под спойлер спрятать неплохо, было бы :)

Это моя первая статья, возможно, что-то не красиво оформил.

Но, расшифруйте, пожалуйста, причём тут текстовый гуглодок?

Скриншоты работы рабочего скрипта, как-то неправильно было бы светить выводимые там данные

Тестовый гуглодок.
Заполнить его, и на его основе сделать скриншот для статьи. Будет просто и наглядно.

Ластик и фильтры в скриншотах делаются в тех редких случаях, когда нужно скрыть логины/пароли/токены/ипы в скриншотах, которые сделаны обычно в рамках траблшутинга/исследования. Делать это нужно очень точечно и что бы было явно видно, что замазано. Иначе получится как у Вас, вроде и интерфейс программы, но на выходе какая не понятная хрень в которой непонятно как отображаются данные, потому что широкими мазками ластиком белому по белому орудовали.

upd.
Увидел исправленный скриншот, спасибо! Теперь сильно нагляднее :)
ОК, сделал
Хрень какая-то, есть же VBScript и редактор для админов www.vbsedit.com с готовыми шаблонами рутинных действий. Там же были и графические приложения hta.

ps: И работает оно даже на xp.
Вы давно в WSH обычный исполняемый файл запускали и его вывод в скрипт возвращали?
ЕМНИП во врмена XP это было нетривиальной задачей, примерно такой же по сложности, как код с SO от amarao выше.
А что есть какие-то проблемы?
Вот скрипт времён xp
Function TestSpeed(ip)
	Set sh=WScript.CreateObject("WScript.Shell")
	Set res=sh.Exec("iperf -c " & ip & " -P 5")
	out=res.StdOut.ReadAll
	Set re=New RegExp
	re.Pattern="\[SUM\].*\s([0-9\.]+) Mbits/sec"
	re.Global=True
	Set m = re.Execute(out)
	If m.Count>0 Then
		TestSpeed=eval(m(0).Submatches(0))
	Else
		TestSpeed=-1
		MsgBox res.StdErr.ReadAll,48,"Error " & ip
	End If
End Function

ip=InputBox("Specify iperf server address ip or hostname", _
	"Enter server address", _
	"192.168.1.2")
if ip<>"" then
	speed=TestSpeed(ip)
	if speed>=0 then
		MsgBox "Speed = " & speed & " MBits/s",0,"Testing " & ip
	end if 
end if

Помню, что были. Потому что самому приходилось их обходить. Но, возможно, это было в Win2K, в изначальной инкарнации WSH и его объектов. Честно говоря, когда появилось свойство, автоматически отслеживающее StdOut, я не помню, а смотреть сейчас — слишком трудоемко. Мне проще признать вашу правоту в данном вопросе.

Совсем не по теме. Vbscript ну совсем другое.

Как в нем создать и управлять vpn-соединениями? Как передавать параметры в winbox, например?

Не читал, но осуждаю?

Как в нем создать и управлять vpn-соединениями?

rasdial?

Не знаю как в winbox, но в линухе есть expect и там на чистом tcl-е можно общаться с сетевым оборудованием типа цисок вполне комфортно.
Какая разница? Точно так же как в ps можно дергать куски .net, которые дергают WinApi, в vbscript можно было дергать WinApi напрямую. Иногда так даже надежнее. Но согласен, с предыдущими коментариями. PowerShell как морская свинка — ни к свиньям не относится, ни к морю. Для shell переусложнен, для ЯП слишком примитивен, те же python/perl/lua позволяют создавать более продвинутые приложения.
Да что там сложного то?
Довольно красиво.
Например, удалить все снапшоты виртуальных машин старше 5 дней и создать ежедневный снапшот можно всего двумя строчками, причем очень понятными

Get-VMSnapshot -VMName *| Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-5) } | Remove-VMSnapshot

Get-VM * | Checkpoint-VM -SnapshotName "Daily Snapshot $((Get-Date).toshortdatestring())"
Ничего, что вы привели пример специфичного приложения для которого производитель написал командлеты облегчающие работу? С таким же успехомможно написать на C# небольшое приложение приложение удаляющее снапшоты, вызвать его из vbs или cmd и сказать смотрите как просто и коротко.
Опять ничего не понял, причем тут c#? Да, теперь для всего в Windows 10/Server есть командлеты. И этим Powershell очень удобен. Зачем что-то писать на C# и вызывать в cmd, если это уже реализовано и документировано?
Сдается мне, что мы на разных языках говорим
Затем что с shell, прочитав справку, разберется даже не подготовленный человек. А приведенный вами пример, для меня не работающего с ps выглядит не намного понятнее однострочника на perl или python. Т. е. для начала придется прочитать мануалы по Get-VMSnapshot, Get-Date, Remove-VMSnapshot,Checkpoint-VM. Потому и говорю, для shell слишком сложный. Vbscript никто shell не называл, хотя он на порядок проще.
По мне так нет ничего проще набрать
Get-Help Get-Date -online

Или
Get-Help Get-Date -full |more

Раз это это для вас сложно, имеет смысл прекратить никуда не ведущую дискуссию
Не говоря уже о переносимости. Что это за shell код для которого сильно зависит от версии? В приведенном вами примере Get-Date -AsUTC есть в current, но нет в LTS. Get-VMSnapshot так и совсем должен быть установлен и разные в разных версиях windows содержит разный набор параметров. Потому и говорю еще раз. PowerShell не shell, а полноценный скриптовый ЯП со специфичным синтаксисом похожим на shell. Но в этом качестве он уступает многим ЯП например в управлении потоками. Не говоря уже о том, что ни один shell не съедает 61 МБ памяти после пары вызовов Get-Help.
Точно так же как в ps можно дергать куски .net, которые дергают WinApi, в vbscript можно было дергать WinApi напрямую.

Утверждение неверное.
Напрямую скриптовые языки, реализованные на базе ActiveScript — кроме vbscript в стандартной поставке был еще JS(и я предпочитал именно его, ибо с юности не любил Basic), а третьи фирмы реализовали и другие языки, из коих мне помнятся Perl и REXX — умели работать только с COM Automation, т.е. объектами классов COM, реализующими интерфейс IDispatch. Для доступа к дргим классам COM из скриптов требовались обертки: например, из скриптов нельзя было напрямую работать с такими базирующимися на COM API, как OLE DB или MAPI, нужны были дополнительные прослойки (ADO и CDO, соответственно). Что касается .NET, то из скриптов ActiveScript доступны компоненты, которые написаны специально для взаимодействия с COM Automation (подробности я с вашего позволения опущу).
С Win32 API была ровно та же ситуация: для обращения к ним требовались обертки, реализующие IDispatch с методами, отображающимися, на функции Win32 API — как, например, здесь (обертка там сделана на VB)

В Powershell с этим сильно легче: из него доступны объекты очень многих (за «всех» не скажу) классов .NET, а также — все «родные»(Native) API, доступные через Interop: в частости — и объекты COM Automation, и функции Win32 API.

Другое дело, что Powershell как инструмент для создания приложений, в общем-то, не предназначен, он заточен для использования в другой сфере — адмистрировании (в том числе — автоматизации администрирования). Не скажу, что он для этого идеален (например, команды можно было бы сделать и покороче — впрочем, это вполне лечится псевдонимами), но — весьма удобен (лично мне, по крайней мере): это я вам как практик, довольно долго работавший с администрированием AD и MS Exchange говорю, со скриптами на базе ActiveScript (с использованием ADSI и CDOEXM, чем приходилось пользоваться до PS) — не сравнить.
Весьма познавательно. Спасибо

Это подключиться, а как создать? И как прописать для конкретного соединения маршруты?

В скриншоте имя клиента справа вверху Вы, видимо, забыли затереть? А в интернете ищется на раз.
P.S. Сам недавно на PowerShell сделал проверку на вирусы передаваемых файлов и передачу отчета во внешнюю программу. Очень неплохо получилось!
В Вашем случае — отличное решение. Что называется, дешево и сердито! Экономия телодвижений сотрудников при минимальных затратах выливается в существенный прирост эффективности предприятия в целом. ))

Попробуйте переписать GUI на WPF используя XAML, у вас будет два файла — один с кодом, второй с разметкой. На мой взгляд разметка XAML удобнее
<Button Name="ExitButton" Content="Выход" Click="ExitButton_OnClick" TabIndex="15"/>
 

чем WinForm
$buttonВыход.Location = '7, 125'
$buttonВыход.Name = 'buttonВыход'
$buttonВыход.Size = '133, 23'
$buttonВыход.TabIndex = 15
$buttonВыход.Text = 'Выход'
$buttonВыход.UseCompatibleTextRendering = $True
$buttonВыход.UseVisualStyleBackColor = $True
$buttonВыход.add_Click($buttonВыход_Click)

В качестве плюса вы получите относительное позиционирование элементов при разном размере окна и разрешений экрана.
Спасибо. Попробую
В качестве плюса вы получите относительное позиционирование элементов при разном размере окна и разрешений экрана.

Это и на вин-формах без проблем делается...

Плюс WPF гораздо гибче в плане дизайна, насколько я понимаю. Попробовал и то, и другое, остановился на WPF для GUI скриптов на PowerShell.

Я тоже пробовал прикручивать к PS интерфейс, но не нашел простого решения проблемы фриза формы при длительных вычислительных и сетевых операциях, пришлось переписать пару утилит на C# с async/await.
Все-таки, PS, не совсем для этого. Он больше скритовой язык.
Всё таки microsoft уже столько технологий для одного и того же выкатила и не одну довести до нормального состояния не может, постоянно что-то новое рожает.
Этот чудо скриптовый язык из той же оперы.
Не согласен. Я с PS по роду работы имел дела много и именно в области его применимости. И, в целом, вполне этим иснтрументом доволен. Надо только правильно понимать только эту самую область применимости: интерактивные ad hoc мини-программы и небольшие по объему скрипты. В этой области PS по сравнению с JS(в ActiveScript, в частности WSH)+COM Automation (это набор иснтрументов, закрывавший у MS примерно тот же круг задач до PS) — небо и земля по удобству использования.
А вот писать сколь-нибудь сложные программы — с этим на PS сложнее.

PS Прикручивать к PS формы я не пробовал (хотя в WinForms на C# вполне умею).
Во времена господства ActiveScript в администрировании Windows я для таких надобностей (была, к примеру, задача — дать девочкам-операторам простой интерфейс для заполнения нужных атрибутов пользователей в AD, чтобы они в адресной книге видны были, на то время, пока программисты интеграцию с кадровой БД не прикрутят) использовал Delphi: из нее объекты COM Automation тоже вызывались легко и непринужденно, а с тех пор подобных задач мне не встречалось.
PPS Сравнивать администрирование Windows с помощью PS и Unix/Linux с помощью shell и стандартного набора команд не берусь (у меня очень мало опыта второго: несколько лет поддержки пары серверов, настроенных, к тому же, другими людьми — это дает слишком мало матриала для сравнения).
В настоящее время PowerShell, на мой взгляд, закрывает процентов 90 задач администрирования в экосистеме MS. Кроме того, многие другие вендоры выпускают свои модули для PS: VMware, Citrix, Amazon и др. У MS далеко не все продукты получаются удачными, но PS вышел таким, если его рассматривать как инструмент администрирования и автоматизации, для чего он и предназначен.
да, там приходится либо форму в параллельный поток выносить, либо таски. И то и другой вариант неудобны. Тоже самое, только еще неудобнее если грузить XAML (WPF) вместо WinForms. Я попробовал все эти варианты.

Remote desktop manager. Умеет работать с облаками разными, можно натравить кучу пользователей на один файл скажем на сетевой шаре. Ну и кроме рдп много что умеет. В том числе умеет всякие vpn сам поднимать, вроде даже маршруты настраивать. В контексте пары пользователей вполне и freeшной версией пользоваться.

А это как по мне для 3 линии тп... Ну тока чтобы до завтра не умереть...

Хорошая программа. Не спорю.
Задача статьи была показать некие приемы работы в PS, и показать что PS не cmd, умеет не только dir c::)

Да нет, задача у вас стояла другая:
Работая в компании IT-аутсорса в качестве руководителя 3 линии поддержки, задумался, как автоматизировать подключение сотрудников по RDP, через VPN к серверам десятков клиентов.

Я не спорю, PS — крут (может знаете как через PS заполнить Имя запускаемой программы и рабочий каталог для пользователя в терминале (управление — пользователи — среда)). Но решать им подобные задачи, когда есть ворох готового… Хуже наверное только те кто в 2021 году делают java приложения для решения задач на всю страну (((
PS. Без обид. У меня ни каких претензий, я просто высказываю свое мнение.

Какие обиды :)
Задача статьи, я имел ввиду.
А рабочая задача - упростить себе работу.
Remote desktop manager, конечно крут, но слишком тяжел и дорог.
К тому же, у нас штат 1Сников, админов 1 и 3 линий и прочих, кому надо быстро подключиться к RDP через VPN или к Mikrotik клиента.
Плюс, вывод самой необходимой информации о клиенте в окошко (серверы, подсети, вебморды etc).
Вот и написал небольшой мультитул, практически не имея опыта в программировании, на основании таких же статей по PS, а уже потом решил поделиться с сообществом, поскольку мне PS для решения таких задач понравился.
Но в реалии, буду уходить от VPN в сторону SSH-туннелей для админских подключений.

молодец, сделал сложную работу

если среда доменная (да даже если не доменная можно сделать) то вы можете раскатывать настройки через ГПО или использовать более сложную технологию типа триггеров vpn, они есть с 10ки

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.