Tôi đang làm việc với một nhóm đối tác tại Microsoft và họ giải thích rằng họ muốn phân tích các tập lệnh PowerShell từ Python. Cách tiếp cận tự nhiên của họ là gọi tệp thực thi PowerShell và xây dựng một dòng lệnh thực hiện những gì họ cần. Tôi nghĩ rằng có thể có một cách tốt hơn vì việc tạo một quy trình PowerShell mới mỗi lần rất tốn kém, vì vậy tôi bắt đầu thực hiện một số nghiên cứu để xem có thể thực hiện được điều gì đó. Tôi đã biết về IronPython [Python tích hợp chặt chẽ. NET] trong một thời gian dài và chúng tôi đã gặp Jim Hugunin ngay sau khi anh ấy đến Microsoft và PowerShell mới được triển khai, nhưng nhóm đang sử dụng cPython nên tôi đã tìm kiếm các mô-đun Python lưu trữ. NET và tìm thấy mô-đun
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
2Gói pythonnet cung cấp cho các nhà phát triển Python quyền truy cập cực kỳ dễ dàng vào thời gian chạy dotnet từ Python. Tôi nghĩ rằng gói này có thể là chìa khóa để truy cập PowerShell, sau một số điều tra, tôi thấy rằng nó có chính xác thứ tôi cần để lưu trữ PowerShell trong tập lệnh Python
ruột
Tôi cần tìm ra cách tải công cụ PowerShell. Đầu tiên, có một số yêu cầu để làm cho tất cả điều này hoạt động. Dotnet phải có sẵn, cũng như PowerShell và
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
2 cung cấp một cách để chỉ định nơi tìm kiếm dotnet. Đặt biến môi trường {
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
4 thành vị trí cài đặt, cho phép {
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
2 cách tìm các tập hợp và các tệp hỗ trợ khác để lưu trữ. NETimport os
os.environ["DOTNET_ROOT"] = "/root/.dotnet"
Bây giờ chúng ta đã biết dotnet ở đâu, chúng ta cần tải CLR lên và thiết lập cấu hình thời gian chạy. Cấu hình thời gian chạy mô tả các khía cạnh khác nhau về cách chúng tôi sẽ chạy. Chúng ta có thể tạo một
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
6 rất đơn giản{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
Sự kết hợp của
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
4 và cấu hình thời gian chạy cho phép tải CLR bằng các hàm {
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
8 và {
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
9# load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
Bây giờ chúng tôi đã tải CLR, chúng tôi cần tải công cụ PowerShell. Đây là một chút không rõ ràng. Ban đầu, tôi chỉ cố tải
# load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
0 nhưng không thành công do lỗi xác thực tên mạnh. Tuy nhiên, nếu tôi tải # load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
1 trước, tôi có thể tránh được lỗi đó. Tôi vẫn chưa chắc tại sao tôi cần tải assembly này trước, đó vẫn là điều tôi cần xác địnhimport clr
import sys
import System
from System import Environment
from System import Reflection
psHome = r'/opt/microsoft/powershell/7/'
mmi = psHome + r'Microsoft.Management.Infrastructure.dll'
clr.AddReference[mmi]
from Microsoft.Management.Infrastructure import *
full_filename = psHome + r'System.Management.Automation.dll'
clr.AddReference[full_filename]
from System.Management.Automation import *
from System.Management.Automation.Language import Parser
Cuối cùng, tôi muốn đặt các vị trí của dotnet và
# load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
2 có thể định cấu hình được, nhưng hiện tại, tôi có thứ mình cầnGiờ đây, công cụ PowerShell đã có sẵn cho tôi, tôi đã tạo một số hàm trợ giúp để xử lý kết quả dễ dàng hơn từ Python. Tôi cũng đã tạo một đối tượng PowerShell [_______10_______3] mà tôi sẽ sử dụng trong một số chức năng của mình
ps = PowerShell.Create[]
def PsRunScript[script]:
ps.Commands.Clear[]
ps.Commands.AddScript[script]
result = ps.Invoke[]
rlist = []
for r in result:
rlist.append[r]
return rlist
class ParseResult:
def __init__[self, scriptDefinition, tupleResult]:
self.ScriptDefinition = scriptDefinition
self.Ast = tupleResult[0]
self.Tokens = tupleResult[1]
self.Errors = tupleResult[2]
def PrintAst[self]:
print[self.ast.Extent.Text]
def PrintErrors[self]:
for e in self.Errors:
print[str[e]]
def PrintTokens[self]:
for t in self.Tokens:
print[str[t]]
def FindAst[self, astname]:
Func = getattr[System, "Func`2"]
func = Func[System.Management.Automation.Language.Ast, bool][lambda a : type[a].__name__ == astname]
asts = self.Ast.FindAll[func, True]
return asts
def ParseScript[scriptDefinition]:
token = None
error = None
# this returns a tuple of ast, tokens, and errors rather than the c# out parameter
ast = Parser.ParseInput[scriptDefinition, token, error]
# ParseResult will bundle the 3 parts into something more easily consumed.
pr = ParseResult[scriptDefinition, ast]
return pr
def ParseFile[filePath]:
token = None
error = None
# this returns a tuple of ast, tokens, and errors rather than the c# out parameter
ast = Parser.ParseFile[filePath, token, error]
# ParseResult will bundle the 3 parts into something more easily consumed.
pr = ParseResult[filePath, ast]
return pr
def PrintResults[result]:
for r in result:
print[r]
Tôi thực sự muốn bắt chước các phương thức PowerShell AST với một số hàm Python thân thiện hơn. Để tạo hàm FindAst[], tôi cần kết hợp ủy nhiệm trong c# với tính năng lambda trong Python. Thông thường, trong PowerShell, điều này sẽ giống như
$ast.FindAll[{$args[0] -is [System.Management.Automation.Language.CommandAst]}, $true]
Nhưng tôi nghĩ từ một tập lệnh Python, việc sử dụng tên của loại sẽ dễ dàng hơn. Bạn vẫn cần biết tên của loại, nhưng bing là tuyệt vời cho loại điều đó. Như tôi đã nói, tôi thực sự không biết ngôn ngữ Python, vì vậy tôi hy vọng có nhiều cách tốt hơn để xử lý
# load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
4 mà # load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
5 trả về. Tôi thấy rằng tôi phải lặp lại kết quả cho dù thế nào đi chăng nữa, vì vậy tôi đã tích hợp nó vào chức năng tiện lợi. Bất cứ ai có đề xuất đều được chào đón để cải thiện điều nàySự vinh quang
Bây giờ chúng ta đã có mô-đun cơ sở cùng nhau, chúng ta có thể viết một số Python khá đơn giản để thực thi các tập lệnh PowerShell của mình. Gọi tập lệnh PowerShell giờ đây dễ dàng như
#!/usr/bin/python3
from pspython import *
scriptDefinition = 'Get-ChildItem'
print[f"Run the script: '{scriptDefinition}"]
result = PsRunScript[scriptDefinition]
PrintResults[result]
/root/__pycache__
/root/dotnet-install.sh
/root/get-pip.py
/root/grr.py
/root/hosted.runtimeconfig.json
/root/pspar.py
/root/pspython.py
/root/psrun.py
Bạn sẽ nhận thấy rằng đầu ra không được định dạng bởi PowerShell. Điều này là do Python chỉ lấy. NET và [về cơ bản] gọi
# load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
6 trên chúngCũng có thể truy xuất các đối tượng và sau đó quản lý định dạng qua PowerShell. Ví dụ này truy xuất các đối tượng qua
# load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
7, chọn những tệp bắt đầu bằng “ps” trong Python, sau đó tạo kết quả chuỗi ở định dạng bảngscriptDefinition = 'Get-ChildItem'
result = list[filter[lambda r: r.BaseObject.Name.startswith['ps'], PsRunScript[scriptDefinition]]]
ps.Commands.Clear[]
ps.Commands.AddCommand["Out-String"].AddParameter["Stream", True].AddParameter["InputObject", result]
strResult = ps.Invoke[]
# print results
PrintResults[strResult]
Directory: /root
UnixMode User Group LastWriteTime Size Name
-------- ---- ----- ------------- ---- ----
-rwxr-xr-x root dialout 6/17/2022 01:30 1117 pspar.py
-rwxr-xr-x root dialout 6/16/2022 18:55 2474 pspython.py
-rwxr-xr-x root dialout 6/16/2022 21:43 684 psrun.py
Nhưng đó không phải là tất cả
Chúng ta cũng có thể gọi các phương thức tĩnh trên các loại PowerShell. Các bạn để ý trong module của mình có một số chức năng liên quan đến ngôn ngữ. Các hàm
# load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
8 và # load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
9 cho phép chúng tôi gọi trình phân tích cú pháp ngôn ngữ PowerShell để kích hoạt một số tình huống rất thú vịHãy tưởng tượng tôi muốn xác định những lệnh mà tập lệnh đang gọi. PowerShell AST làm cho điều đó trở nên dễ dàng, nhưng trước tiên chúng ta phải sử dụng trình phân tích cú pháp. Trong PowerShell, điều đó sẽ được thực hiện như thế này
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
0AST kết quả được lưu trữ trong
import clr
import sys
import System
from System import Environment
from System import Reflection
psHome = r'/opt/microsoft/powershell/7/'
mmi = psHome + r'Microsoft.Management.Infrastructure.dll'
clr.AddReference[mmi]
from Microsoft.Management.Infrastructure import *
full_filename = psHome + r'System.Management.Automation.dll'
clr.AddReference[full_filename]
from System.Management.Automation import *
from System.Management.Automation.Language import Parser
0, mã thông báo trong import clr
import sys
import System
from System import Environment
from System import Reflection
psHome = r'/opt/microsoft/powershell/7/'
mmi = psHome + r'Microsoft.Management.Infrastructure.dll'
clr.AddReference[mmi]
from Microsoft.Management.Infrastructure import *
full_filename = psHome + r'System.Management.Automation.dll'
clr.AddReference[full_filename]
from System.Management.Automation import *
from System.Management.Automation.Language import Parser
1 và lỗi trong import clr
import sys
import System
from System import Environment
from System import Reflection
psHome = r'/opt/microsoft/powershell/7/'
mmi = psHome + r'Microsoft.Management.Infrastructure.dll'
clr.AddReference[mmi]
from Microsoft.Management.Infrastructure import *
full_filename = psHome + r'System.Management.Automation.dll'
clr.AddReference[full_filename]
from System.Management.Automation import *
from System.Management.Automation.Language import Parser
2. Với mô-đun Python này, tôi gói gọn nó vào hàm Python # load up the clr
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr["/root/pspython.runtimeconfig.json"]
set_runtime[rt]
9, hàm này trả về một đối tượng chứa cả ba kết quả đó trong một phần tử. Tôi cũng đã tạo một vài hàm trợ giúp để in mã thông báo và lỗi dễ dàng hơn. Ngoài ra, tôi đã tạo một hàm cho phép tôi tìm bất kỳ loại AST nào [hoặc AST phụ] trong bất kỳ AST tùy ý nào{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
1Lưu ý rằng có một kiểm tra cho commandName không phải là null. Điều này là do khi sử dụng
import clr
import sys
import System
from System import Environment
from System import Reflection
psHome = r'/opt/microsoft/powershell/7/'
mmi = psHome + r'Microsoft.Management.Infrastructure.dll'
clr.AddReference[mmi]
from Microsoft.Management.Infrastructure import *
full_filename = psHome + r'System.Management.Automation.dll'
clr.AddReference[full_filename]
from System.Management.Automation import *
from System.Management.Automation.Language import Parser
4, tên lệnh không thể được xác định thông qua phân tích tĩnh do tên lệnh được xác định trong thời gian chạy…một số, uh, điều kiện, uh, một vài pro quo
Trước tiên, bạn phải cài đặt dotnet [thông qua install-dotnet], cũng như cài đặt đầy đủ PowerShell.
{
"runtimeOptions": {
"tfm": "net6.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
}
}
}
2 không chạy trên tất cả các phiên bản Python, tôi chỉ thử nghiệm nó trên Python 3. 8 và Trăn 3. 9 trên Ubuntu20. 04. Vào thời điểm tôi viết bài này, tôi không thể chạy nó trên Python 3. 10. Có thêm thông tin về pythonnet tại trang web pythonnet. Ngoài ra, đây là phiên bản lưu trữ của PowerShell. Một số thứ, chẳng hạn như tiến độ, dài dòng và lỗi có thể hoạt động hơi khác so với những gì bạn thấy từ import clr
import sys
import System
from System import Environment
from System import Reflection
psHome = r'/opt/microsoft/powershell/7/'
mmi = psHome + r'Microsoft.Management.Infrastructure.dll'
clr.AddReference[mmi]
from Microsoft.Management.Infrastructure import *
full_filename = psHome + r'System.Management.Automation.dll'
clr.AddReference[full_filename]
from System.Management.Automation import *
from System.Management.Automation.Language import Parser
6. Theo thời gian, tôi có thể sẽ thêm các hàm trợ giúp bổ sung để truy xuất thêm thông tin thời gian chạy từ phiên bản công cụ. Nếu bạn muốn tham gia, tôi rất sẵn lòng nhận Yêu cầu kéo hoặc hiểu đơn giản là các trường hợp sử dụng của bạn tích hợp PowerShell và PythonLấy nó ra để quay
Tôi đã kết thúc tất cả những thứ này và thêm một Dockerfile [chạy trên Ubuntu 20. 04] trên github. Để tạo hình ảnh docker, chỉ cần chạy
import clr
import sys
import System
from System import Environment
from System import Reflection
psHome = r'/opt/microsoft/powershell/7/'
mmi = psHome + r'Microsoft.Management.Infrastructure.dll'
clr.AddReference[mmi]
from Microsoft.Management.Infrastructure import *
full_filename = psHome + r'System.Management.Automation.dll'
clr.AddReference[full_filename]
from System.Management.Automation import *
from System.Management.Automation.Language import Parser
7 từ thư mục gốc của kho lưu trữ