ps/Modules/Alkami.DevOps.Inventory/Public/Get-MachineInventory.ps1
2023-05-30 22:51:22 -07:00

245 lines
10 KiB
PowerShell

function Get-MachineInventory {
<#
.SYNOPSIS
Returns an Object that Represents the State of a Machine
.DESCRIPTION
Executes multiple collectors which describe the state of a machine. Can execute on an array of
machine names or PSSessions and allows for an optional filter to be included. May be returned as a PSObject, JSON, or XML
.PARAMETER TargetComputerNames
[string[]] One or more remote computers to profile
.PARAMETER PsSessions
[PSSession[]] One or more PSSessions to Use
.PARAMETER Filter
[string[]] A filter which limits the number of profilers to execute
.PARAMETER JsonOutput
[switch] Specifies to return the result as JSON
.PARAMETER XmlOutput
[switch] Specifies to return the result as XML
.INPUTS
None
.OUTPUTS
An object with details about the machine state. May be a PSObject (default), JSON, or XML depending on arguments
.EXAMPLE
Get-MachineInventory
[Get-MachineInventory] : Collecting data from 1 target(s)
WARNING: [ALKA01VMA167] : Function Get-AppSettingsInventory Took 00:00:02.2702503 to Execute
[Get-MachineInventory] : Received 1 result(s)
[Get-MachineInventory] : Adding Results for ALKA01VMA167
[Get-MachineInventory] : Inventory Collection Complete After 00:00:07.9261976
Name Value
---- -----
ALKA01VMA167 {OS, Version, Architecture, GenerationTime...}
.EXAMPLE
Get-MachineInventory -Filter Uptime, FileSystem
[Get-MachineInventory] : Collecting data from 1 target(s)
[Get-MachineInventory] : Received 1 result(s)
[Get-MachineInventory] : Adding Results for ALK-DELL1323
Name Value
---- -----
ALK-DELL1323 {OS, Version, Architecture, GenerationTime...}
.EXAMPLE
Get-MachineInventory -Filter Uptime -MachineNames @("localhost", "ALKA01VMA163.fh.local")
[Get-MachineInventory] : Collecting data from 2 target(s)
[Get-MachineInventory] : Received 2 result(s)
[Get-MachineInventory] : Adding Results for ALKA01VMA163
[Get-MachineInventory] : Adding Results for ALK-DELL1323
Name Value
---- -----
ALKA01VMA163 {OS, Version, Architecture, GenerationTime...}
ALK-DELL1323 {OS, Version, Architecture, GenerationTime...}
#>
[CmdletBinding(DefaultParameterSetName = 'FilterOnlyParameterSet')]
[OutputType([string], ParameterSetName=("MachineNameParameterJson","SessionParameterJson","FilterParameterSetJson"))]
[OutputType([System.Xml.XmlDocument], ParameterSetName=("MachineNameParameterXml","SessionParameterXml","FilterParameterSetXml"))]
[OutputType([System.Collections.Specialized.OrderedDictionary], ParameterSetName=("MachineNameParameterSet","SessionParameterSet"))]
param(
[Parameter(ParameterSetName = 'MachineNameParameterSet', Mandatory = $true)]
[Parameter(ParameterSetName = 'MachineNameParameterJson', Mandatory = $true)]
[Parameter(ParameterSetName = 'MachineNameParameterXml', Mandatory = $true)]
[Alias("ComputerNames", "Servers", "MachineNames")]
[string[]]$TargetComputerNames,
[Parameter(ParameterSetName='SessionParameterSet', Mandatory=$true)]
[Parameter(ParameterSetName='SessionParameterJson', Mandatory=$true)]
[Parameter(ParameterSetName='SessionParameterXml', Mandatory=$true)]
[Alias("Sessions")]
[System.Management.Automation.Runspaces.PSSession[]]$PsSessions,
[Parameter(ParameterSetName = 'MachineNameParameterJson', Mandatory = $true)]
[Parameter(ParameterSetName = 'SessionParameterJson', Mandatory = $true)]
[Parameter(ParameterSetName = 'FilterParameterSetJson', Mandatory = $false)]
[Alias("JsonOutput")]
[switch]$AsJson,
[Parameter(ParameterSetName = 'MachineNameParameterXml', Mandatory = $true)]
[Parameter(ParameterSetName = 'SessionParameterXml', Mandatory = $true)]
[Parameter(ParameterSetName = 'FilterParameterSetXml', Mandatory = $false)]
[Alias("XMLOutput")]
[switch]$AsXML
)
DynamicParam {
# Define the Paramater Attributes
$ParameterName = "Filter"
$RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
$ParameterAttribute.Mandatory = $false
$ParameterAttribute.ParameterSetName = "__AllParameterSets"
$AttributeCollection.Add($ParameterAttribute)
# Generate and add the ValidateSet
$arrSet = $inventoryFilterSetOptions | ForEach-Object { $_.FilterName }
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
$AttributeCollection.Add($ValidateSetAttribute)
# Create the dynamic parameter
$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string[]], $AttributeCollection)
$RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
return $RuntimeParameterDictionary
}
begin {
# Bind the Filter dynamic parameter to a variable
$logLead = Get-LogLeadName
Write-Host "$logLead : Executing using ParameterSet: [$($PSCmdlet.ParameterSetName)]"
$filterCollection = $PsBoundParameters[$ParameterName]
Write-Host "$logLead : Executing with filters: [$filterCollection]"
# We'll Silently Continue for Any Provider Errors -- They Get Added to the Results
$originalErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = "SilentlyContinue"
$functionStopWatch = [System.Diagnostics.StopWatch]::StartNew()
$inventoryResult = New-Object System.Collections.Specialized.OrderedDictionary
}
process {
try {
$clearSessions = $true
if ($null -eq $PsSessions -or $PsSessions.Count -eq 0) {
$sessions = @()
foreach ($target in $TargetComputerNames) {
Write-Host "$logLead : Creating Session for $target"
$sessions += New-PSSession -ComputerName $target -ErrorVariable err -ErrorAction SilentlyContinue
if($err.Count -gt 0) {
Write-Warning "$logLead : New-PSSession encountered an error : $err"
}
}
} else {
$clearSessions = $false
$sessions = $PsSessions
}
$scriptBlock = {
$logLead = "[$env:COMPUTERNAME]"
$ErrorActionPreference = "Continue"
$machineData = New-Object System.Collections.Specialized.OrderedDictionary
$uniqueSections = $Using:inventoryFilterSetOptions | ForEach-Object { $_.SectionVariable } | Sort-Object | Select-Object -Unique
$VerbosePreference=$Using:VerbosePreference;
foreach ($section in $uniqueSections) {
Write-Verbose "$logLead : Creating Variable for $section Data"
New-Variable -Name $section -Value (New-Object System.Collections.Specialized.OrderedDictionary)
}
# Always include Platform Inventory as Top Level Properties
$machineData += Get-PlatformInventory
# Use the entire filter set if no filter was set as a parameter
[array]$filteredInventories = Test-IsNull $Using:filterCollection ($Using:inventoryFilterSetOptions | ForEach-Object { $_.FilterName }) -Strict
Write-Verbose "$logLead : Using Final Inventory Filter: [$filteredInventories]"
foreach ($inventory in ($filteredInventories | Sort-Object)) {
$matchingFilter = $Using:inventoryFilterSetOptions | Where-Object {$_.FilterName -eq $inventory}
$masterProviderStopWatch = [System.Diagnostics.StopWatch]::StartNew()
Write-Host "$logLead : Executing FunctionName [$($matchingFilter.FunctionName)]"
$sb = [ScriptBlock]::Create($matchingFilter.FunctionName)
((Get-Variable -Name $matchingFilter.SectionVariable).Value) += (Invoke-Command $sb)
$masterProviderStopWatch.Stop()
if ($masterProviderStopWatch.ElapsedMilliseconds -ge 1000) {
Write-Warning "$logLead : Function $($matchingFilter.FunctionName) Took $($masterProviderStopWatch.Elapsed) to Execute"
}
}
foreach ($uniqueSection in $uniqueSections) {
$section = (Get-Variable -Name $uniqueSection -ValueOnly)
if ($section.Count -gt 0) {
Write-Verbose "$logLead : Adding $uniqueSection Section to Results"
$machineData.Add("$uniqueSection", $section)
}
}
return $machineData
}
Write-Host "$logLead : Collecting data from $($sessions.Count) target(s)"
[array]$results = Invoke-Command -ScriptBlock $scriptBlock -Session $sessions
Write-Host "$logLead : Received $($results.Count) result(s)"
# Add Result Sets
foreach ($result in $results) {
Write-Host "$logLead : Adding Results for $($result.Hostname)"
$inventoryResult.Add($result.Hostname, $result)
}
} finally {
Write-Host "$logLead : Setting ErrorActionPreference to $originalErrorActionPreference"
$ErrorActionPreference = $originalErrorActionPreference
if ($clearSessions) {
if ($sessions.Count -gt 0) {
Write-Host "$logLead : Cleaning Up PSSessions"
Remove-PSSession $sessions;
} else {
Write-Error "$logLead : WinRM cannot connect to any computers in the input list."
}
}
}
$functionStopWatch.Stop()
Write-Host "$logLead : Inventory Collection Complete After $($functionStopWatch.Elapsed)"
if ($AsJson) {
return ($inventoryResult | ConvertTo-Json -Depth 8)
}
if ($AsXml) {
return ($inventoryResult | ConvertTo-Xml -Depth 8 -As Document)
}
return $inventoryResult
}
}