Главная

Friday, 15 June 2018

PowerShell и другие языки программирования.

Привет всем.

Технический писатель Коробко Иван Викторович в своей книге "PowerShell как средство автоматического администрирования" 2012-го года издания еще раз показал нам насколько PowerShell является универсальным инструментом. Я имею ввиду его главу про "PowerShell и другие языки программирования". Просто передам слово автору.

Довольно часто возникает потребность использовать вставки VB.NET или C# в листинге PowerShell. Это обусловливается невозможностью реализовать тот или иной функционал в PowerShell. Как правило, любую манипуляцию с любым объектом можно выполнить с помощью API-функции, вызываемой на низком уровне. Ярким примером является служба DFS, программное управление которой возможно только с помощью API-функций. Чтобы упростить изложение материала  приведем пример вывода обычного окна сообщения – MessageBox(). Реализуем вызов сообщения с помощью вставки листинга программного кода, написанного на VB.NET, в тело сценария на PowerShell и с помощью вызова соответствующей API-функции, описанной в VB.NET.

Компиляция кода на DOT.NET в PowerShell

Интеграция в PowerShell кода компилируемых языков, например C# или VB.NET, осуществляется несколько иным механизмом. Вставка программного кода также компилируется, однако вместо файла записывается в оперативную память. Успешная интеграция программного кода на DOT.NET обеспечивается с помощью двух объектов: с помощью первого объекта – CompilerParameters – осуществляется настройка параметров компиляции указанного кода, идентификация языка программирования. Второй объект изменяется в зависимости от используемого языка программирования в ставке. Для C# – Microsoft.CSharp.CSharp-CodeProvider, а для Visual Basic - Microsoft.VisualBasic.VBCodePro-
vider.

Фрагмент исполняемого кода на DOT.NET представляет собой описание класса с произвольным именем и минимум одной функции, имя которой так же произвольно. Листинг является значением переменной, заключенной, помимо кавычек, в символы @ (листинги П4.1 (C#) и П4.2 (VB.NET). При переносе листинга из Visual Studio в PowerShell необходимо следить за тем, чтобы иерархический путь ко всем методам и функциям был указан целиком, так как импорт пространств имен не поддерживается. Таким образом, вывести окно с помощью MsgBox() невозможно, следует указать полный путь – Microsoft.VisualBasic.Interaction.MsgBox().

Листинг П4.1. Вызов VB.NET-вставки из PowerShell (C#)

$provider = New-Object Microsoft.CSharp.CSharpCodeProvider
$params = New-Object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","System.Windows.Forms.dll"
$params.ReferencedAssemblies.AddRange($refs)
$txtCode = @"
Class mBox
Sub Main()
Microsoft.VisualBasic.Interaction.MsgBox ("Тестовое сообщение")
End Sub
End class
“@
$results = $provider.CompileAssemblyFromSource($params, $txtCode)
$mAssembly = $results.CompiledAssembly
$i = $mAssembly.CreateInstance("mBox")
$r = $i.main()

Листинг П4.2. Вызов VB.NET-вставки из PowerShell (VB.NET)

$provider = New-Object Microsoft.VisualBasic.VBCodeProvider
$params = New-Object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"
$params.ReferencedAssemblies.AddRange($refs)
$txtCode = @"
Class mBox
Sub Main()
Microsoft.VisualBasic.Interaction.MsgBox ("Тестовое сообщение")
End Sub
End class
"@
$results = $provider.CompileAssemblyFromSource($params, $txtCode)
$mAssembly = $results.CompiledAssembly
$i = $mAssembly.CreateInstance("mBox")
$r = $i.main()

Компиляция вставки на DOT.NET осуществляется в оперативной памяти. За это отвечает свойство GenerateInMemory. После завершения компиляции осуществляется выполнение скомпилированного кода. Для обращения к нужной функции необходимо указать класс, в котором она находится, а затем и саму функцию.


Передача параметров из PowerShell в вставку DOT.NET

Достаточно часто требуется передать параметры из PoweShell в какую-либо функцию в DOT.NET-вставку. Для этого необходимо при вызове функции указать параметр, а в листинге DOT.NET описать его как параметр функции. Внутри VB.NET-вставки работа с параметром функции ведется в обычном режиме. В листинге П4.3 (С#) приведен пример передачи параметра строки Тестовое сообщение в функцию showString. Полученное значение выводится
на экран с помощью функции MsgBox().

Листинг П4.3. Передача параметров функции из PowerShell в DOT.NET (VB.NET)

$provider = New-Object Microsoft.VisualBasic.VBCodeProvider
$params = New-Object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"
$params.ReferencedAssemblies.AddRange($refs)
$txtCode = @"
Class mBox
Sub showString (str)
Microsoft.VisualBasic.Interaction.MsgBox (str)
End Sub
End class
"@
$results = $provider.CompileAssemblyFromSource($params, $txtCode)
$mAssembly = $results.CompiledAssembly
$i = $mAssembly.CreateInstance("mBox")
$r = $i.showString("Тестовое сообщение")

Для передачи параметра используется функция. В конце функции переменной, имя которой совпадает с названием функции, присваивается переменная, передаваемая в PowerShell. В качестве переменной может выступать любой объект, поддерживаемый DOT.NET - строка, объект, массив и т. д.

В листинге П4.4 приведен пример сложения двух чисел. Исходные два числа передаются из PowerShell в DOT.NET. В DOT.NET-сценарии осуществляется их сложение, затем результат обратно передается в PowerShell и выводится на экран.

Листинг П4.4. Обмен данными между DOT.NET и PowerShell (VB.NET)

$provider = New-Object Microsoft.VisualBasic.VBCodeProvider
$params = New-Object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"
$params.ReferencedAssemblies.AddRange($refs)
$txtCode = @"
Class Summ
Function Summa (x ,y )
Dim s As integer = x +y
Summa = s
End Function
End class
"@
$a=2
221
$b=5
$results = $provider.CompileAssemblyFromSource($params, $txtCode)
$mAssembly = $results.CompiledAssembly
$i = $mAssembly.CreateInstance("Summ")
$result = $i.Summa($a,$b)
Write-Host $result

Обратите внимание, что вопреки правилам синтаксиса DOT.NET при объявлении функции Summa() в классе Summ тип данных переменных не указан. Это сделано специально. В противном случае сценарий работать не будет.

Вызов API-функций из DOT.NET-вставки в PowerShell

API-функция – это низкоуровневая функция, описанная в наборе динамических библиотек ядра операционной системы Windows. Использование API значительно расширяет возможности программиста, позволяя создавать очень сложные приложения. Так, доступ к DFS программным способом осуществляется только с помощью API-функций. Даже Framework здесь бессилен. Приведем пример вызова простейшей API-функции (листинг П4.5), выводящей окно сообщений, – Message Box. Любая API-функция объявляется непосредственно в классе DOT.NEТ, как любая другая функция, например MyMessageBox. При объявлении функции обязательно указываются библиотека, в которой она описана, и псевдоним (alias), который назначается произвольно. После объявления функции она вызывается в одной из функций в DOT.NET-вставке.

Листинг П4.5. Вызов API-функции из DOT.NET-вставки в PowerShell (VB.NET)

$provider = New-Object Microsoft.VisualBasic.VBCodeProvider
$params = New-Object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"
$params.ReferencedAssemblies.AddRange($refs)
$txtCode = @"
Class mBox
Declare Auto Function MyMessageBox Lib “user32.dll” Alias
"MessageBox" _
(ByVal hWnd as Integer, ByVal msg as String, ByVal Caption as
String, ByVal Tpe as Integer) As Integer
Sub Main()
MyMessageBox(0, "Текстовое сообщение", "", 0)
End Sub
End class
"@
$results = $provider.CompileAssemblyFromSource($params, $txtCode)
$mAssembly = $results.CompiledAssembly
$i = $mAssembly.CreateInstance("mBox")
$r = $i.main()

No comments:

Post a Comment

А что вы думаете по этому поводу?