PowerShell có thể xác định phần mềm đã cài đặt, dịch vụ ứng dụng và các tác vụ đã lên lịch, có thể giúp lập kế hoạch và quản lý.
Có thể nhanh chóng xác định phần mềm nào được cài đặt trên máy chủ của bạn có giá trị vì một loạt các lý do. Quản lý chi phí và quyền lợi cấp phép phần mềm, lập kế hoạch ngân sách nâng cấp, xác định ứng cử viên để hợp nhất máy chủ hoặc thậm chí phản ứng với các sự cố bảo mật là tất cả các lý do phổ biến để thực hiện kiểm kê phần mềm.
Tất nhiên có các công cụ doanh nghiệp để theo dõi hàng tồn kho phần mềm. Nhưng những công cụ này có thể đắt tiền và phức tạp, hoặc có thể bị giới hạn quyền truy cập đối với các nhóm hoặc cá nhân cụ thể trong tổ chức của bạn. May mắn thay, PowerShell có thể giúp bạn thực hiện một số công việc trong việc phân tích phần mềm trên hệ thống của bạn để giúp bạn lập kế hoạch và ứng phó sự cố.
Đôi khi bạn cũng cần phải tiến hành nhiều thứ hơn là chỉ liệt kê các phần mềm đã cài đặt. Có được thông tin chi tiết về những thứ như dịch vụ hoặc ứng dụng đang chạy, chia sẻ tệp hoặc thậm chí các cổng đang mở có thể rất quan trọng để trả lời đầy đủ các câu hỏi cho công việc của bạn.
Xác định phần mềm đã cài đặt
Về lý thuyết, truy xuất danh sách các phần mềm đã cài đặt là một đề xuất đơn giản. Sử dụng lệnh ghép ngắn Get-WmiObject để truy vấn lớp Win32_Product tạo ra danh sách các phần mềm đã cài đặt, nhưng trong nhiều trường hợp, bạn sẽ thấy danh sách này chưa đầy đủ. Một giải pháp thay thế tốt hơn là lệnh ghép ngắn Get-Package, cung cấp một số khả năng tiện dụng.
Về lý thuyết, truy xuất danh sách các phần mềm đã cài đặt là một đề xuất đơn giản. Sử dụng lệnh ghép ngắn Get-WmiObject để truy vấn lớp Win32_Product tạo ra danh sách các phần mềm đã cài đặt, nhưng trong nhiều trường hợp, bạn sẽ thấy danh sách này chưa đầy đủ. Một giải pháp thay thế tốt hơn là lệnh ghép ngắn Get-Package, cung cấp một số khả năng tiện dụng.
Get-Package cung cấp cho bạn tên và phiên bản phần mềm theo mặc định, cũng như một số trường khác mà bạn có thể không quan tâm, với các trường bổ sung bị ẩn theo mặc định. Các trường chính khác mà bạn có thể quan tâm bao gồm thuộc tính FullPath, biểu thị nơi ứng dụng được cài đặt và cờ From Trusted Source, cho biết liệu phần mềm có được cài đặt từ kho phần mềm được doanh nghiệp tin cậy hay không.
Không dễ dàng có được một số bit dữ liệu hữu ích khi sử dụng Get-Package, nhưng đôi khi chúng có thể truy cập được nếu bạn sẵn sàng tìm hiểu kỹ hơn một chút. Thuộc tính SwidTag Text chứa dữ liệu XML bao gồm thông tin như số điện thoại trợ giúp cho phần mềm, URL tham chiếu và thậm chí cả ngày cài đặt. Để truy cập các thuộc tính này, đây là cách bạn có thể làm cho nó hoạt động:
Get-Package -ProviderName Programs, MSI | ForEach-Object {
$xml = [xml]$_.SwidTagText
$meta = $xml.SoftwareIdentity.Meta
$_ | Add-Member -MemberType NoteProperty -Name HelpTelephone -Value $meta.HelpTelephone -PassThru
$_ | Add-Member -MemberType NoteProperty -Name UrlInfoAbout -Value $meta.UrlInfoAbout -PassThru
} | Format-Table Name, Version, HelpTelephone, UrlInfoAbout -AutoSize
Có khá nhiều lệnh ở đây, vì vậy hãy cùng tìm hiểu những gì đang xảy ra.
Dòng đầu tiên chạy lệnh ghép ngắn Get-Package và chuyển kết quả đến ForEach-Object, sau đó lặp qua từng phần tử và thực thi mã chứa trong dấu ngoặc nhọn.
Trong mã vòng lặp, bước đầu tiên là phân tích cú pháp chuỗi XML có trong thuộc tính SwidTag Text.
Làm ngược lại dòng đầu tiên đó trong vòng lặp, $_ tham chiếu đến phần tử hiện tại trong vòng lặp ForEach, vì vậy $_.SwidTagText sẽ tham chiếu đến văn bản XML đó, cho từng phần mềm đến từ Get-Package. Tiền tố $_.SwidTag Text là [xml] cho biết rằng chúng tôi không muốn coi nó như một chuỗi văn bản mà là một đối tượng XML. Khi chúng tôi đã hoàn thành công việc lấy đối tượng XML, chúng tôi sẽ gán đối tượng đó cho một biến để giúp việc tham chiếu trở nên dễ dàng hơn trong tương lai.
Sau khi có một đối tượng XML để làm việc, chúng tôi muốn điều hướng đối tượng đó xuống siêu dữ liệu với cú pháp $xml.Software Identity.Meta và chúng tôi gán thành phần đó của đối tượng XML cho biến $meta
Hai dòng tiếp theo gần giống hệt nhau, vì vậy chúng tôi sẽ chỉ đề cập đến khái niệm một lần. Bắt đầu với biến $_ tham chiếu đến phiên bản hiện tại từ Get-Package, chúng tôi chuyển nó vào lệnh ghép ngắn Add-Member. Add-Member cho phép chúng tôi thêm một thuộc tính mới bằng cách chỉ định loại thành viên, tên và giá trị. Cờ -PassThru chỉ đơn giản là giữ lại đầu ra của lệnh ghép ngắn Add-Member đó. Cuối cùng, chúng tôi chuyển kết quả có trong khối mã ForEach-Object vào lệnh ghép ngắn Format-Table,với Format-Table chỉ đơn giản là cung cấp cho chúng tôi chế độ xem dạng bảng của các cột được chỉ định. Trong thành phần cuối cùng này, chúng ta có thể dễ dàng sử dụng lệnh ghép ngắn Export-CSV để lưu kết quả đầu ra để phân tích thêm.
Xác định các dịch vụ ứng dụng và các tác vụ đã lên lịch
Không chỉ có thể xác định phần mềm nào được cài đặt trên máy chủ của bạn mà còn có thể biết những dịch vụ hoặc tác vụ theo lịch trình mà gói phần mềm đã bật trên hệ thống. Tất nhiên trong khi cả hai phương pháp được sử dụng để thực thi mã mà không cần sự can thiệp của người dùng, cả hai đều khác nhau rõ rệt về cách thức và thời điểm mã đó được thực thi cũng như cách chúng được quản lý.
Các dịch vụ tương đối dễ tìm hiểu với PowerShell vì có lệnh ghép ngắn Get-Service. Nhưng Get-Service cũng có một số hạn chế. Một lựa chọn tốt hơn là sử dụng lớp Win32_Service WMI(Windows Management Instrumentation) và lệnh ghép ngắn Get-WmiObject.
Thực thi một ví dụ như Get-WmiObject Win32_Service | Where-Object Name -like 'servicename*' | Select-Object * sẽ trả về tất cả các thuộc tính từ dịch vụ ('servicename*') bạn đã nhắm mục tiêu. Các thuộc tính này bao gồm những thứ như tên, mô tả và tên hiển thị, cũng như trạng thái hiện tại và kiểu khởi động. Hơn nữa, thuộc tính PathName xác định quy trình và các đối số được sử dụng để khởi tạo dịch vụ và thuộc tính ProcessId xác định quy trình hiện tại trong bộ nhớ nếu dịch vụ ở trạng thái đang chạy.
Các tác vụ đã lên lịch khó truy vấn hơn một chút. Lớp WMI của Win32_ScheduledJob sẽ cho phép bạn truy vấn các công việc được tạo bằng script hoặc AT.exe, nhưng không phải những công việc được tạo trong bảng điều khiển Scheduled Tasks (Tác vụ đã lên lịch). Bạn cũng có tùy chọn sử dụng toàn bộ tập hợp các lớp trong không gian tên TaskScheduler. Bạn có thể lấy danh sách các lớp đó bằng Get-WmiObject -List -Namespace Root/Microsoft/Windows/TaskScheduler. Một tùy chọn đơn giản hơn là lệnh ghép ngắn Get-ScheduledTask.
Đối với người mới bắt đầu, Get-ScheduledTask trả về TaskName, TaskPath và State mà không cần phải đào (digging). Các thuộc tính này cung cấp tên thân thiện mà bạn thấy trong bảng điều khiển Tác vụ đã lên lịch, đường dẫn đến tác vụ trong ngăn dẫn hướng và trạng thái của tác vụ.
Các chi tiết như ứng dụng hoặc lệnh đang được thực thi, yêu cầu đào sâu hơn một chút. Tác vụ đã lên lịch lưu trữ thông tin này dưới thuộc tính Actions trong thuộc tính Execute và Arguments. Đoạn mã sau truy vấn danh sách các tác vụ không ở trạng thái Disabled, trích xuất chi tiết Actions và kết hợp chúng thành một thuộc tính mới có tên là Command và đưa đầu ra vào console.
Get-ScheduledTask | Where-Object State -ne Disabled | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name Command -Value ($_.Actions.Execute + ' ' + $_.Actions.Arguments) -PassThru
} | Select-Object TaskName, State, Command, TaskPath
Đây là một khởi đầu tuyệt vời về mặt thông tin quan trọng cho các tác vụ đã lên lịch, nhưng nếu bạn muốn biết một số chi tiết về lịch trình thì sao. Trong bảng điều khiển Tác vụ đã lên lịch là Thời gian chạy tiếp theo và Thời gian chạy cuối cùng, rất lý tưởng cho các mục đích tóm tắt, nhưng Get-ScheduledTask không cung cấp trực tiếp các chi tiết này. Tin tốt là chúng ta không phải tìm hiểu quá xa để có được thông tin chi tiết về thời gian chạy, vì lệnh ghép ngắn Get-Scheduled Task Info cung cấp cho chúng ta.
Để thêm chi tiết thời gian chạy vào đoạn mã trên, chúng tôi cần lấy chi tiết thông tin tác vụ cho từng tác vụ khi chúng tôi lặp qua chúng với ForEach-Object. Cách dễ nhất để làm điều này là chỉ cần chuyển phiên bản tác vụ hiện tại đến lệnh ghép ngắn Get-Scheduled Task Info bằng cách sử dụng biến $_ được tích hợp sẵn. Sau khi hoàn thành việc đó, chúng tôi sẽ gán nó cho biến $taskInfo, sau đó thêm chi tiết thời gian chạy vào đầu ra.
Get-ScheduledTask | Where-Object State -ne Disabled | ForEach-Object {
$taskInfo = $_ | Get-ScheduledTaskInfo
$_ | Add-Member -MemberType NoteProperty -Name Command -Value ($_.Actions.Execute + ' ' + $_.Actions.Arguments) -PassThru
$_ | Add-Member -MemberType NoteProperty -Name LastStart -Value $taskInfo.LastRunTime -PassThru
$_ | Add-Member -MemberType NoteProperty -Name NextStart -Value $taskInfo.NextRunTime -PassThru
} | Select-Object TaskName, State, Command, TaskPath, LastStart, NextStart
Bây giờ chúng ta đã thiết lập cách đi đến các chi tiết chính cho các tác vụ của mình, hãy quay trở lại mục tiêu ban đầu là thu thập dữ liệu về các tác vụ liên quan đến các công cụ phần mềm cụ thể.
Có một số thuộc tính có thể chứa các chi tiết hữu ích cho việc liên quan đến ứng dụng. Một số thuộc tính này có sẵn dưới dạng tham số với Get-ScheduledTask, trong khi những thuộc tính khác chỉ có thể được sử dụng để lọc kết quả sau khi các tác vụ đã được truy vấn. Cả tham số -TaskName và -TaskPath có thể được tận dụng để truy vấn các thuộc tính đó và thậm chí có thể sử dụng các ký tự đại diện để tìm kiếm các kết quả phù hợp không chính xác.
Một chút thông tin khác có thể hữu ích cho việc tìm kiếm là giá trị Execute trong Actions, giá trị này có khả năng chứa một đường dẫn tệp hoặc ít nhất là một tệp thực thi. Để truy vấn dựa trên giá trị Execute, chúng ta có thể sử dụng Where-Object như sau:
Get-ScheduledTask | Where-Object { $_.Actions.Execute -like '*Adobe*'}
Từ đó, kết quả có thể được chuyển đến phần còn lại của đoạn mã mà chúng tôi đã phát triển ở trên, để phát triển đầy đủ tập dữ liệu và tạo ra kết quả có thể sử dụng được.