Comments 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
могли быть придуманы только тем, кому насрать на людей, пишущих скрипты.
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'ом.
Я по своему опыту знаю, то если какой-то инструмент имеет вырвиглазный синтаксис с самого начала, то и вся остальная работа с ним такая же — через ненависть и боль.
Потому что в 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).
Может реализация не самая удачная, да и выглядит как обертка над .net, но тем не менее это гигантский шаг вперед со времен дос и юникс
А насчет ситаксиса… Я вот, к примеру, очень мало знаю perl, и скрипты на нем обычно выглядят для меня «перловой кашей», но я понимаю, что это не дает мне никаких оснований объявлять perl плохим, негодным языком — просто этим инструментом я не владею. Почему в случае с PS не происходит то же самое?
Недостаток «архаичных систем» по сравнению с PS, что в них заметно сложнее манипулировать проходящим по конвейеру потоком символов в случае, если этот поток имеет нетривиальную структуру: ему надо устраивать грамматический разбор перед применением, чтобы структурировать. А по конвейеру PS уже идет структурированный поток объектов, имеющих свойства, к которым можно легко и просто обратиться по их имени, чтобы использовать для фильтрации или обработки.
$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.
А вообще-то, для полного доступа к конфигурации локальной системы в Windows gwmi (т.е. Get-WmiObject) есть. И Set-WMIInstance.
PS Да, методы администрирования Windows и Linux — они таки отличаются.
PPS На этом соревнование предлагаю считать законченным и, если хотите — признать вас победителем: я на приз в любой дисциплине соревнований типа Windows vs Linux традиционно не претендую. Но, надеюсь, я вас убедил, что Powerhell — он не такой страшный как вам казалось раньше?
Он не страшный. Он уродливый. Я этот поинт с самого начала вёл. Есть языки, которые пишутся с представлением о красоте, а есть языки, в которых "как-то получилось и сойдёт".
То есть понятие красоты — оно сугубо субъективно.
На этом обсуждение Powershell с вами предлагаю закончить.
Надеюсь, вам никогда не придется администрировать MS Exchange: там Powershell без альтернатив.
Ну я бы отметил, что java и c# и не были изначально скриптовыми языками, чем является python изначально. Да, по моим ощущениям они конечно пытаются и в скриптовые языки войти в последнее время многими упрощениями, но это все равно не то.
Это как сравнивать теплое с мягким, натягивать сову на глобус, ну и другие аналогии придумайте. Очень странно предъявы кидать языкам, которые и не были именно для этого предназначены
Я кидаю предъявы не языку, а человеку, который пытается эту монстросити притащить в администрирование и считает, что так и надо.
ровно так же мы можем обсуждать код для автоматического провиза виртуалок в CI, написанный на boost'е в C++. Неподобающий инструмент, провоцирующий невыносимые условия работы.
Я ж показал чем. Ужасный синтаксис, постоянные отсылки объектную модель .net.
Как, например, скриптом создать подключение к VPN не через Powershell?
А от .NET тут только Win.forms, который лишь объединяет несколько скриптов в один с выбором действий через «окошко».
Я последний раз видел винды всерьёз в 2008. В принципе, тот кусок, который мне надо было автоматизировать, мы сделали на winrm, но он оставил примерно такое же ощущение брезгливости и уныния.
Я не знаю ответа "как хорошо и красиво администрировать Windows", и это было одним из ключевых моих мотивов для перехода на Linux. Тогда Ансибла ещё не было. Наверное, сейчас я бы попытался использовать Ансибл.
Иногда это неизбежно: например, для одновременного доступа к содержимому п/я и к средствам администрирования Exchange нет другого выхода, кроме как использовать Powershell (доступ к администрированию Exchаnge, альтернатив тут нет) и EWS Manged API из .NET (в средствах администрирования Exhange крайне ограничены возможности доступа к содержимому п/я).
Но чаще всего альтернатива есть.
данные для подключению к клиентам с логинами\паролями в облаке гугл? Окей, думаю они в восторге были-бы, если-б узнали.
PS: вообще удивляет, что люди осуществляющую L3 поддержку, не в состоянии автоматизировать свой труд. На данном уровне, руководитель должен решать только административные вопросы.
Блин ну не делайте так. Случайно нажмете на не ту ссылку и ваша таблица будет видна всему интернету
Скрипт, естественно, не стоит распространять за пределы собственного использования с оставлением в нем частных данных.
Он предназначен для персонального использования.
С тем же успехом, можно просто передать все имена/пароли/приватные ключи.
Никто не мешает хранить не в google, а локально, или на своих закрытых ресурсах. Всего-то чутка поправить скрипт.
Данная статья не предназначена для использования as is, а преследует цель показать некоторые приемы работы в powershell
Каждый волен использовать приведенный здесь текст по своему усмотрению.
Писать такое надо, причем — в начале статьи — ибо редкий гуглящий читает нагугленное до конца. У меня был пример — статья в личном блоге про создание кластера DNS в MS Windows.
Статья — наполовину шуточная: отказоустойчивость в системе DNS отлично обеспечивается другими средствами. И шуточная она именно наполовину, ибо вообще-то иллюстрирует, как можно добавить в кластер MS FT произвольный сервис, вместе с его конфигурацией в файловой системе и в реестре (собственно, для этого она и была написана). А сервис DNS был выбран в качестве примера только потому, что немногим ранее на мой любимый админский форум приперся некий оригинал (то ли неадекват, то ли, типа, тонкий тролль), который требовал, просил и умолял, чтобы его научили созданию кластера DNS — притом, что ему сразу объяснили, как надо делать DNS отказоустойчивым штатными методами.
Так вот, несмотря на примечание в конце статьи о шуточном характере выбранного примера, я регулярно наблюдал попытки использовать эту статью в качестве руководства по развертыванию DNS в кластере — пока, наконец, не написал предупреждение крупными буквами в самом начале статьи.
Скриншот работающего приложения с затертыми данными:Все бы ничего, но если вы тестовый гуглодок предоставляете, то и скриншот можно было бы с него сделать. И выглядело бы прилично. А то показывать скриншоты, с затертыми ластиком данными, это прям неуважение к читателям в наше время. Смотрится очень очень плохо.
Да и код под спойлер спрятать неплохо, было бы :)
Это моя первая статья, возможно, что-то не красиво оформил.
Но, расшифруйте, пожалуйста, причём тут текстовый гуглодок?
Скриншоты работы рабочего скрипта, как-то неправильно было бы светить выводимые там данные
Заполнить его, и на его основе сделать скриншот для статьи. Будет просто и наглядно.
Ластик и фильтры в скриншотах делаются в тех редких случаях, когда нужно скрыть логины/пароли/токены/ипы в скриншотах, которые сделаны обычно в рамках траблшутинга/исследования. Делать это нужно очень точечно и что бы было явно видно, что замазано. Иначе получится как у Вас, вроде и интерфейс программы, но на выходе какая не понятная хрень в которой непонятно как отображаются данные, потому что широкими мазками ластиком белому по белому орудовали.
upd.
Увидел исправленный скриншот, спасибо! Теперь сильно нагляднее :)
ps: И работает оно даже на xp.
ЕМНИП во врмена XP это было нетривиальной задачей, примерно такой же по сложности, как код с SO от amarao выше.
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
Совсем не по теме. Vbscript ну совсем другое.
Как в нем создать и управлять vpn-соединениями? Как передавать параметры в winbox, например?
Не читал, но осуждаю?
Довольно красиво.
Например, удалить все снапшоты виртуальных машин старше 5 дней и создать ежедневный снапшот можно всего двумя строчками, причем очень понятными
Get-VMSnapshot -VMName *| Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-5) } | Remove-VMSnapshot
Get-VM * | Checkpoint-VM -SnapshotName "Daily Snapshot $((Get-Date).toshortdatestring())"
Сдается мне, что мы на разных языках говорим
Get-Help Get-Date -online
Или
Get-Help Get-Date -full |more
Раз это это для вас сложно, имеет смысл прекратить никуда не ведущую дискуссию
Точно так же как в 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 сделал проверку на вирусы передаваемых файлов и передачу отчета во внешнюю программу. Очень неплохо получилось!
В Вашем случае — отличное решение. Что называется, дешево и сердито! Экономия телодвижений сотрудников при минимальных затратах выливается в существенный прирост эффективности предприятия в целом. ))
<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 сложнее.
PS Прикручивать к PS формы я не пробовал (хотя в WinForms на C# вполне умею).
Во времена господства ActiveScript в администрировании Windows я для таких надобностей (была, к примеру, задача — дать девочкам-операторам простой интерфейс для заполнения нужных атрибутов пользователей в AD, чтобы они в адресной книге видны были, на то время, пока программисты интеграцию с кадровой БД не прикрутят) использовал Delphi: из нее объекты COM Automation тоже вызывались легко и непринужденно, а с тех пор подобных задач мне не встречалось.
PPS Сравнивать администрирование Windows с помощью PS и Unix/Linux с помощью shell и стандартного набора команд не берусь (у меня очень мало опыта второго: несколько лет поддержки пары серверов, настроенных, к тому же, другими людьми — это дает слишком мало матриала для сравнения).
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-туннелей для админских подключений.
Powershell настоящий язык программирования. Скрипт оптимизации рутины в техподдержке