Skip to content

Instantly share code, notes, and snippets.

@p0w3rsh3ll
Created January 18, 2014 13:14
Show Gist options
  • Save p0w3rsh3ll/8490370 to your computer and use it in GitHub Desktop.
Save p0w3rsh3ll/8490370 to your computer and use it in GitHub Desktop.
#Requires -Version 3.0
#Requires -Module DnsClient,ActiveDirectory
<#
.SYNOPSIS
Practice Event of Powershell Winter Scripting 2014
.DESCRIPTION
Practice Event of Powershell Winter Scripting 2014
.PARAMETER Path
Specifies the folder where to save data.
Default location is your temp directory.
The directoty must exist.
.PARAMETER CIDR
Specify an array of subnets passed in CIDR format notation.
.EXAMPLE
.\Practice.Event.ps1 -CIDR "10.10.10.0/24"
.EXAMPLE
.\Practice.Event.ps1 -Path C:\temp -CIDR ("10.15.2.163/32","10.10.10.0/24") -Verbose
.EXAMPLE
"10.15.2.163/32","10.10.10.0/24" | .\Practice.Event.ps1 -Path C:\temp
.EXAMPLE
.\Practice.Event.ps1 -CIDR "10.10.10.0/24" -Path C:\temp -EnablePowerPoint
.NOTES
For fun and learning...
.LINK
http://p0w3rsh3ll.wordpress.com
#>
[CmdletBinding(DefaultParameterSetName='All')]
Param(
[Parameter()]
[ValidateScript({
Test-Path -Path $_ -PathType Container
})]
[string]$Path = $env:TEMP,
[Parameter(Mandatory,ValueFromPipeline)]
[Alias("Subnet","Network")]
[ValidatePattern("(\d{1,3}\.){3}\d{1,3}\/\d{1,2}")]
[string[]]$CIDR,
[Parameter(ParameterSetName='Office',Mandatory)]
[switch]$EnablePowerPoint,
[parameter()]
[Alias('RunAs')]
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty
)
Begin {
#region Validation
if (-not(([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(544))) {
Write-Warning "Must run powerShell as Administrator to perform these actions"
break
}
#endregion Validation
#region VariableInit
$results = @()
#endregion VariableInit
#region Network
Function New-IPv4Range {
<#
.SYNOPSIS
Generates a list of IPv4 IP Addresses given a Start and End IP.
.DESCRIPTION
Generates a list of IPv4 IP Addresses given a Start and End IP.
.PARAMETER Start
Specify the first IPv4 address in the range in dotted format.
.PARAMETER End
Specify the last IPv4 address in the range in dotted format.
.EXAMPLE
New-IPv4Range -Start 192.168.1.1 -End 192.168.1.5
Returns an array of IPv4 addresses as string
.NOTES
Based on the work made by Tobias Weltner https://twitter.com/TobiasPSP
.OUTPUTS
String[]
.LINK
http://powershell.com/cs/blogs/tobias/archive/2011/02/20/creating-ip-ranges-and-other-type-magic.aspx
.INPUTS
String
#>
[CmdletBinding()]
[OutputType([String[]])]
Param(
[Parameter(Mandatory)]
[ValidateScript({
if ([bool]($_ -as [IPAddress])) {
$true
} else {
Throw (New-Object System.ArgumentException -ArgumentList "Invalid IPAddress")
}
})]
[String]$Start,
[Parameter(Mandatory)]
[ValidateScript({
if ([bool]($_ -as [IPAddress])) {
$true
} else {
Throw (New-Object System.ArgumentException -ArgumentList "Invalid IPAddress")
}
})]
[String]$End
)
Process {
# Created by PowerShell MVP Dr. Tobias Weltner
$ip1 = ([IPAddress]$Start).GetAddressBytes()
[Array]::Reverse($ip1)
$ip1 = ([IPAddress]($ip1 -join '.')).Address
$ip2 = ([IPAddress]$End).GetAddressBytes()
[Array]::Reverse($ip2)
$ip2 = ([IPAddress]($ip2 -join '.')).Address
for ($x=$ip1; $x -le $ip2; $x++) {
$ip = ([IPAddress]$x).GetAddressBytes()
[Array]::Reverse($ip)
$ip -join '.'
}
}
} # endof function
Function New-IPv4RangeFromCIDR {
<#
.SYNOPSIS
Generates a list of IPv4 Addresses given a subnet in CIDR format
.DESCRIPTION
Generates a list of IPv4 Addresses given a subnet in CIDR format
.PARAMETER CIDR
Array of subnet string in CIDR format
.EXAMPLE
New-IPv4RangeFromCIDR 10.10.10.0/24
Returns an array of IPv4 addresses as string
.EXAMPLE
"10.10.10.0/24" | New-IPv4RangeFromCIDR
Returns an array of IPv4 addresses as string based on the CIDR passed through the pipeline
.NOTES
Based on the work made by Carlos Perez https://twitter.com/Carlos_Perez
.OUTPUTS
String[]
.LINK
https://github.com/darkoperator/Posh-SecMod/blob/master/Discovery/Discovery.psm1
.INPUTS
String[]
#>
[CmdletBinding()]
[OutputType([String[]])]
Param(
[Parameter(Mandatory,ValueFromPipeline)]
[Alias("Subnet","Network")]
[ValidatePattern("(\d{1,3}\.){3}\d{1,3}\/\d{1,2}")]
[string]$CIDR
)
Begin{
$IP,$Mask = $CIDR.Split("/")
if (-not([bool]($IP -as [IPAddress]))) {
Write-Warning -Message "An invalid IP address was entered"
break
}
if ($Mask -notin 0..32) {
Write-Warning -Message "An invalid CIDR mask was entered"
break
}
}
Process{
$NumberOfIPs = [Math]::Pow(2,(32-$Mask)) - 1
$NetworkIP = ([IPAddress]$IP).GetAddressBytes()
[Array]::Reverse($NetworkIP)
$NetworkIP = ([IPAddress]($NetworkIP -join ".")).Address
$StartIP = $NetworkIP # + 1
$EndIP = $NetworkIP + $NumberOfIPs
# We make sure they are of type Double before conversion
If ($EndIP -isnot [double]) {
$EndIP = $EndIP -as [double]
}
If ($StartIP -isnot [double]) {
$StartIP = $StartIP -as [double]
}
# We turn the start IP and end IP in to strings so they can be used.
$StartIP = ([IPAddress]$StartIP).IPAddressToString
$EndIP = ([IPAddress]$EndIP).IPAddressToString
New-IPv4Range -Start $StartIP -End $EndIP
}
End{}
} #endof function
Workflow Get-ActiveComputer {
Param(
[parameter(mandatory)]
[string[]]$ComputerName
)
ForEach -parallel ($Computer in $ComputerName){
Sequence {
Inlinescript {
$Env:ADPS_LoadDefaultDrive=0
New-Object -TypeName PSObject -Property @{
IPAddress = $using:Computer ;
ComputerName = try {
(Resolve-DnsName -Name $using:Computer -Type PTR -DnsOnly:$true -ErrorAction Stop | Where-Object -FilterScript { $PSitem.Section -eq "Answer"}).Namehost
} catch {
[string]::Empty
} ;
Active = try {
if (Test-WSMan -ComputerName $using:Computer -ErrorAction Stop) { $true}
} Catch {
$false
};
} | Add-Member -MemberType ScriptProperty -Name OSVersion -Value {
try {
(Get-ADComputer -Identity ($this.ComputerName -split '\.')[0] -Properties OperatingSystemVersion -ErrorAction Stop).OperatingSystemVersion -replace "(\d{1}\.\d{1})\s\((\d{4})\)",'$1.$2'
} Catch {
[string]::Empty
}
} -PassThru
}
}
}
} #endof workflow
#endregion Network
}
Process {
$CIDR | ForEach-Object -Process {
Write-Verbose "Getting active computers for CIDR $_"
$IPs = New-IPv4RangeFromCIDR -CIDR $_
if ($IPs) {
if (-not($PSCmdlet.ParameterSetName -eq 'Office')) {
$results += Get-ActiveComputer -ComputerName $IPs
}
}
}
}
End {
if ($PSCmdlet.ParameterSetName -eq 'Office') {
#region Visualisation
Function ConvertTo-Pie {
[CmdletBinding()]
Param(
[Parameter(Mandatory)]
[PSObject]$InputObject,
[Parameter(Mandatory)]
[ValidateScript({
Test-Path -Path $_ -PathType Container
})]
[string]$Path,
[Parameter()]
[ValidateSet('Pie','Cylinder')]
[string]$Type = 'Pie'
)
Begin {
"System.Windows.Forms","System.Windows.Forms.DataVisualization" | ForEach-Object -Process {
if(-not([Reflection.Assembly]::LoadWithPartialName($PSItem))) {
Write-Warning -Message "Failed to load the required assembly: $PSItem"
$Problem = $true
}
}
if ($Problem) { break }
# create chart object
$Chart = New-object System.Windows.Forms.DataVisualization.Charting.Chart
$Chart.Width = 500
$Chart.Height = 400
$Chart.Left = 40
$Chart.Top = 30
# create a chartarea to draw on and add to chart
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$Chart.ChartAreas.Add($ChartArea)
$X = ($InputObject | Get-Member -MemberType NoteProperty | Select -First 2 | Where Definition -match "System.String").Name
$Y = ($InputObject | Get-Member -MemberType NoteProperty | Select -First 2 | Where Definition -notmatch "System.String").Name
# add data to chart
[void]$Chart.Series.Add("Data")
$Chart.Series["Data"].Points.DataBindXY(
($InputObject.$X -as [string[]]),
($InputObject.$Y -as [int[]])
)
}
Process {
}
End{
Switch ($Type) {
'Pie' {
# set chart type
$Chart.Series["Data"].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Pie
# set chart options
$Chart.Series["Data"]["PieLabelStyle"] = "Outside"
$Chart.Series["Data"]["PieLineColor"] = "Black"
$Chart.Series["Data"]["PieDrawingStyle"] = "Concave"
($Chart.Series["Data"].Points.FindMaxByValue())["Exploded"] = $true
}
'Cylinder' {
$ChartArea.AxisX.Title = $X
$ChartArea.AxisY.Title = $Y
# Find point with max/min values and change their colour
$maxValuePoint = $Chart.Series["Data"].Points.FindMaxByValue()
$maxValuePoint.Color = [System.Drawing.Color]::Red
$minValuePoint = $Chart.Series["Data"].Points.FindMinByValue()
$minValuePoint.Color = [System.Drawing.Color]::Green
# change chart area colour
$Chart.BackColor = [System.Drawing.Color]::Transparent
# make bars into 3d cylinders
$Chart.Series["Data"]["DrawingStyle"] = "Cylinder"
$Chart.Series["Data"].Sort([System.Windows.Forms.DataVisualization.Charting.PointSortOrder]::Descending, "Y")
}
}
# save chart to file
$Chart.SaveImage($Path + "\Chart_$($X).$($Y).png", "PNG")
Join-Path -Path $Path -ChildPath "\Chart_$($X).$($Y).png"
}
} #endof function
Function New-PPTXFile {
[CmdletBinding()]
Param(
[Parameter(Mandatory)]
[ValidateScript({
Test-Path -Path $_ -PathType Container
})]
[string]$Path,
[Parameter()]
[ValidateScript({
Test-Path -Path $_ -PathType Container
})]
[string]$TemplatePath='C:\Program Files (x86)\Microsoft Office\Templates\1033\ProjectStatusReport.potx',
[Parameter(Mandatory)]
[string[]]$Images
)
Begin {
Try {
Add-Type -AssemblyName Office -ErrorAction Stop
Add-Type -AssemblyName Microsoft.Office.Interop.PowerPoint -ErrorAction Stop
} Catch {
Write-Warning -Message "Failed to load required assembly"
break
}
$MSOfalse = [Microsoft.Office.Core.MsoTriState]::msoFalse
$MSOtrue = [Microsoft.Office.Core.MsoTriState]::msoTrue
$Count = 1
$Application = New-Object -ComObject Powerpoint.Application
$Application.visible = $MSOtrue
$Presentation = $Application.Presentations.add($MSOtrue)
# Apply a template
if (Test-Path $TemplatePath) {
$Presentation.ApplyTemplate($TemplatePath) | Out-Null
}
}
Process {
$Images | ForEach-Object -Process {
Write-Verbose -Message "Adding image $PSItem"
if (Test-Path $PSItem -PathType Leaf) {
# Add a slide
$Slide = $Presentation.Slides.Add($Count,[microsoft.office.interop.powerpoint.ppSlideLayout]::ppLayoutCustom)
$Count++
# Add the image
$Slide.Shapes.AddPicture($PSItem,$msoFalse,$msoTrue,100,150,540,380) | Out-Null
# Add the title
if ($PSItem -match "Chart_(.+)\.(.+)\.png") {
($Slide.Shapes | Where Name -eq 'Title 1').TextFrame.TextRange.Text = (Split-Path -Path $PSItem -Leaf) -replace "Chart_(.+)\.(.+)\.png",'$1 vs. $2'
}
# Add a footer
$Slide.HeadersFooters.Footer.Visible= 1
$Slide.HeadersFooters.Footer.Text = (Get-Date).ToString()
[void][System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($Slide)
} else {
Write-Warning -Message "Failed to find the file $PSItem"
}
}
}
End {
#Save the presentation
$Presentation.SaveAs("$Path\Results.pptx",[microsoft.office.interop.powerpoint.PpSaveAsFileType]::ppSaveAsDefault,$MSOtrue)
$Presentation.Close()
[void][System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($Presentation)
$Application.Quit()
[void][System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($Application)
# Force any remaining Powerpoint process related to our COM object to stop
Get-WmiObject -Class Win32_Process | Where {
$PSItem.Commandline -match 'POWERPNT.EXE" /AUTOMATION -Embedding'
} | Select-Object -Property CommandLine,ProcessId |
ForEach-Object -Process {
try {
Stop-Process -Id $PSItem.ProcessId -ErrorAction Stop
} catch {
Write-Warning -Message "Failed to stop Powerpoint because $($_.Exception.Message)"
}
}
}
} #endof function
Get-ChildItem -Path "$($Path)\*" -Include "Servers.list.*.csv" -ErrorAction SilentlyContinue |
Sort -Property LastWriteTime | Select -Last 1 |
ForEach-Object -Process {
Write-Verbose -Message "Importing Data from file $($_.FullName)"
$Data += Import-Csv -Path $_.FullName
}
Write-Verbose -Message "Creating powerpoint presentation"
if ($Data) {
New-PPTXFile -Path $Path -Images @(
# Active vs. Inactive
(ConvertTo-Pie -Path $Path -InputObject (
$Data |
Group-Object -Property Active -NoElement |
Select @{l='Active';e={($_.Name)}},@{l='Sum';e={$_.Count}}
)),
# Active > OS versions pie
(ConvertTo-Pie -Path $Path -Type Cylinder -InputObject (
$Data | Where Active |
Group-Object -Property OSVersion -NoElement |
Select @{l='OSVersion';e={($_.Name)}},@{l='Sum';e={$_.Count}}
))
)
} else {
Write-Warning -Message "Something went wrong while gathering data"
}
#endregion Visualisation
} else {
Write-Verbose "Exporting active computers results"
$results | Select -Property IPAddress,ComputerName,Active,OSVersion,@{l='OS Desc' ; e={
Switch -Regex ($_.OSVersion) {
'^5\.2\.3790' { 'Windows Server 2003' ; break }
'^6\.0\.6001' { 'Windows Server 2008 SP1' ; break }
'^6\.0\.6002' { 'Windows Server 2003 SP2' ; break }
'^6\.1\.7600' { 'Windows Server 2008 R2' ; break }
'^6\.1\.7601' { 'Windows Server 2008 R2 SP1' ; break }
'^6\.2\.9200' { 'Windows Server 2012' ; break }
'^6\.3\.9600' { 'Windows Server 2012 R2' ; break }
default {
'Unknown or older'
}
}
}} |
Export-Csv -Path (
Join-Path -Path $Path -ChildPath ("Servers.list.{0}.csv" -f (Get-Date).ToString('s')-replace "\:","")
)
#region Inventory
Write-Verbose "Begining inventory of active computers"
$Count=0
Get-Job | Where Name -match 'InvScan_' | Remove-Job
$results | Where Active | ForEach-Object -Process {
$IP = $PSItem.IPAddress
$Computer = $PSItem.ComputerName
$Count++
$WPHT = @{
Activity = "Scanning active IP {0} with computername {1}" -f $IP,$Computer;
Status = '{0} over {1}' -f $Count,($results).Count ;
PercentComplete = $Count/(($results).Count)*100;
}
Write-Progress @WPHT
Switch -regex ($_.OSVersion) {
"^6\.3\.9600" {
# 2012 R2
$SB = {
$HT = @{ ErrorAction = "Stop"}
TRY {
$SrvmgrData = (Get-CimClass -Namespace root\microsoft\windows\servermanager -Class MSFT_ServerManagerTasks @HT |
Invoke-CimMethod -MethodName GetServerInventory -Arguments @{
SMServerId="$env:COMPUTERNAME"
} -WarningAction SilentlyContinue @HT).ServerInventory |
Select -Property CbsTimestamp,Manufacturer,ProcessorNames,TotalPhysicalMemory
$Roles = (Get-CimClass -Namespace root\microsoft\windows\servermanager -Class MSFT_ServerManagerTasks |
Invoke-CimMethod -MethodName GetServerFeature -Arguments @{BatchSize=512}).ItemValue |
Where State -eq 1 | Select @{l='Component';e={$_.DisplayName}},@{l='Type';e={
Switch ($_.Type) {
0 { 'Role'}
1 { 'Role service'}
2 { 'Feature'}
default { 'Unknown'}
}
}}
$hasExchange = if (Get-Service -Name MSExchange* @HT) {$true} else {$false }
$hasSharePoint = if (Get-Service @HT| Where DisplayName -match "SharePoint") { $true } else {$false }
$hasSQL = if (Get-Service -Name MSSQLSERVER* @HT) { $true } else {$false }
$hasIIS = if (Get-Service -Name W3SVC* @HT){ $true } else {$false }
[PSCustomObject]@{
ComputerName = "$env:COMPUTERNAME"
OSversion = [Environment]::OSVersion.Version
TotalDiskSpace = ((Get-Disk @HT).Size | Measure -Sum).Sum/1GB -as [int]
Processors = $SrvmgrData | Select -ExpandProperty ProcessorNames
InstalledRAM = ($SrvmgrData.TotalPhysicalMemory/1GB -as [int])
Manufacturer = $SrvmgrData.Manufacturer
LastInstalledUpdates = ($SrvmgrData.CbsTimestamp).ToUniversalTime()
Model = (Get-CimInstance Win32_ComputerSystem -Property Model @HT).Model
LastBootTime = (Get-CimInstance Win32_OperatingSystem -Property LastBootUpTime @HT).LastBootUpTime.ToUniversalTime()
Roles = $Roles
HasExchange = $hasExchange
HasSQL = $hasSQL
HasIIS = $hasIIS
HasSharePoint = $hasSharePoint
}
} CATCH {
Write-Warning -Message "Failed to scan $($env:COMPUTERNAME) because $($_.Exception.Message)"
}
} #endof SB
break;
} #endof 2012R2
"^6\.2\.9200" {
# 2012
$SB = {
$HT = @{ ErrorAction = "Stop"}
TRY {
$OS = Get-CimInstance -ClassName Win32_OperatingSystem -Property LastBootUpTime @HT
$CS = Get-CimInstance -ClassName Win32_ComputerSystem -Property Model,Manufacturer @HT
$RAM = (Get-CimInstance -ClassName Win32_PhysicalMemory -Property Capacity | Measure-Object -Property Capacity -Sum | Select -ExpandProperty Sum)
$Proc = Get-CimInstance -ClassName Win32_Processor -Property Name @HT
$Roles = Get-WindowsFeature @HT | Where Installed | Select @{l='Component';e={$_.DisplayName}},@{l='Type';e={$_.FeatureType}}
$hasExchange = if (Get-Service -Name MSExchange* @HT) {$true} else {$false }
$hasSharePoint = if ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")) { $true } else { $false }
$hasSQL = if ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")) { $true } else {$false }
$hasIIS = if ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")){ $true } else {$false }
[PSCustomObject]@{
ComputerName = "$env:COMPUTERNAME"
OSversion = [Environment]::OSVersion.Version
TotalDiskSpace = ((Get-Disk @HT).Size | Measure -Sum).Sum/1GB -as [int]
Processors = ($Proc).Name | Select -First 1
InstalledRAM = ($RAM/1MB -as [int])
Manufacturer = $CS.Manufacturer
LastInstalledUpdates = (New-Object -ComObject Microsoft.Update.Session).CreateUpdateSearcher().QueryHistory(0,1) | Select -ExpandProperty Date
Model = $CS.Model
LastBootTime = $OS.LastBootUpTime.ToUniversalTime()
Roles = $Roles
HasExchange = $hasExchange
HasSQL = $hasSQL
HasIIS = $hasIIS
HasSharePoint = $hasSharePoint
}
} CATCH {
Write-Warning -Message "Failed to scan $($env:COMPUTERNAME) because $($_.Exception.Message)"
}
} #endof SB
break;
} #endof 2012
"^6\.[1|0]\.[7|6][6|0]0[0|1|2]" {
# 2018 R2
$SB = {
$HT = @{ ErrorAction = "Stop"}
TRY {
Switch ($PSVersionTable.PSVersion.Major) {
3 {
$OS = Get-CimInstance -ClassName Win32_OperatingSystem -Property LastBootUpTime,BuildNumber @HT
$BootTime = ($OS | Select -Property LastBootUpTime).LastBootUpTime
$CS = Get-CimInstance -ClassName Win32_ComputerSystem -Property Model,Manufacturer @HT
$Proc = Get-CimInstance -ClassName Win32_Processor -Property Name @HT
$RAM = (Get-CimInstance -ClassName Win32_PhysicalMemory @HT | Measure-Object -Property Capacity -Sum | Select -ExpandProperty Sum) /1MB -as [int]
$Roles = Get-CimInstance -ClassName Win32_ServerFeature @HT | Select -Property @{l='Component';e={$_.Name}}
$DiskSpace = (Get-CimInstance -Query "SELECT Size FROM Win32_LogicalDisk WHERE DriveType = '3'" @HT | Measure -Property Size -Sum | Select -ExpandProperty Sum)/1GB -as [int]
}
2 {
$OS = Get-WmiObject -Class Win32_OperatingSystem @HT
$BootTime = [System.Management.ManagementDateTimeConverter]::ToDateTime($OS.LastBootUpTime)
$CS = $OS.GetRelated('Win32_ComputerSystem')
$RAM = (Get-WmiObject -Class Win32_PhysicalMemory @HT | Measure-Object -Property Capacity -Sum | Select -ExpandProperty Sum) /1MB -as [int]
$Roles = Get-WmiObject -Class Win32_ServerFeature @HT | Select -Property @{l='Component';e={$_.Name}}
$Proc = Get-WmiObject -Class Win32_Processor @HT | Select -First 1 -ExpandProperty Name
$DiskSpace = (Get-WmiObject -Query "SELECT Size FROM Win32_LogicalDisk WHERE DriveType = '3'" @HT | Measure -Property Size -Sum | Select -ExpandProperty Sum)/1GB -as [int]
}
default {}
} #endof switch
$hasExchange = if (
$null,"Wow6432Node" | ForEach-Object -Process {
Get-ChildItem "HKLM:\SOFTWARE\$($_)\Microsoft\ExchangeServer\v*" -ErrorAction SilentlyContinue
}
) {$true} else {$false }
$hasSharePoint = if (
$null,"Wow6432Node" | ForEach-Object -Process {
Get-ChildItem "HKLM:\SOFTWARE\$($_)\Microsoft\Shared Tools\Web Server Extensions\*\WSS" -ErrorAction SilentlyContinue
}
) { $true } else { $false}
$hasSQL = if (
$null,"Wow6432Node" | ForEach-Object -Process {
Get-ChildItem "HKLM:\SOFTWARE\$($_)\Microsoft\Microsoft SQL Server" -ErrorAction SilentlyContinue
}
) { $true } else { $false}
$hasIIS = if (
Get-ChildItem "HKLM:\System\CurrentControlSet\Services\W3SVC" -ErrorAction SilentlyContinue
) { $true } else { $false}
New-Object -TypeName psobject -Property @{
ComputerName = "$($env:COMPUTERNAME)"
OSversion = ([Version]('6.1.{0}' -f $OS.BuildNumber))
TotalDiskSpace = $DiskSpace
Processors = $Proc
InstalledRAM =$RAM
Manufacturer = ($CS | Select Manufacturer).Manufacturer
LastInstalledUpdates = (New-Object -ComObject Microsoft.Update.Session).CreateUpdateSearcher().QueryHistory(0,1) | Select -ExpandProperty Date
Model = ($CS | Select Model).Model
LastBootTime = $BootTime
Roles = $Roles
HasExchange = $hasExchange
HasSQL = $hasSQL
HasIIS = $hasIIS
HasSharePoint = $hasSharePoint
}
} CATCH {
Write-Warning -Message "Failed to scan $($env:COMPUTERNAME) because $($_.Exception.Message)"
}
} #endof SB
break;
} #endof 2008R2
default {
$SB = {
# Source: Tobias Weltner http://powershell.com/cs/blogs/tobias/archive/2011/10/27/regular-expressions-are-your-friend-part-1.aspx
Function Get-Matches {
Param(
[Parameter(Mandatory=$true)]
$Pattern,
[Parameter(ValueFromPipeline=$true)]
$InputObject
)
Begin {
try {
$regex = New-Object Regex($pattern)
} catch {
Throw "Get-Matches: Pattern not correct. '$Pattern' is no valid regular expression."
}
$groups = @($regex.GetGroupNames() | Where-Object { ($_ -as [Int32]) -eq $null } | ForEach-Object { $_.toString() })
}
Process {
foreach ($line in $InputObject) {
foreach ($match in ($regex.Matches($line))) {
if ($groups.Count -eq 0) {
([Object[]]$match.Groups)[-1].Value
} else {
$rv = 1 | Select-Object -Property $groups
$groups | ForEach-Object { $rv.$_ = $match.Groups[$_].Value }
$rv
}
}
}
}
} #endof function
# Define our pattern to parse the output
$pattern = '(?<property>(?i)([a-z\(\)]+(\s[a-z\(\)]+)*:)|(\w+\s\w+:\s\w+(:|\s\w+:)))\s{2,}(?<value>.+)'
if (Test-Path "$($env:systemroot)\system32\systeminfo.exe") {
& (Get-Command "$($env:systemroot)\system32\systeminfo.exe") | Get-Matches $pattern
}
} #endof $SB
} #endof default
} #endof switch
# Add creds to hastable...
$InvHT = @{ ErrorAction = 'Stop'}
if ($PSBoundParameters.ContainsKey('Credential')) {
Write-Verbose "Adding Credentials to hashtable"
$InvHT += @{ Credential = $Credential}
}
Write-Verbose -Message "Scanning computer $Computer with IP $IP"
Try {
Invoke-Command -ComputerName $Computer -ScriptBlock $SB -AsJob -JobName ("InvScan_{0}" -f $IP) @InvHT | Out-Null
} Catch {
Write-Warning -Message "Failed to scan computer $Computer"
}
} #endof Foreach
While (Get-Job | Where Name -match 'InvScan_' | Where State -eq 'Running') {
$Total = (Get-Job | Where Name -match 'InvScan_') ;
$completed = (Get-Job | Where Name -match 'InvScan_' | Where State -eq 'Completed') ;
$WPHT = @{
Activity = 'Waiting for scan inventory to complete' ;
Status = ('{0} over {1}' -f $Completed.Count,$Total.Count) ;
PercentComplete = (($Completed.Count)/($Total.Count)*100) ;
}
Write-Progress @WPHT
Start-Sleep -Seconds 1
}
Write-Verbose "Exporting inventory data of active computers"
Get-Job | Where Name -match 'InvScan_' | ForEach-Object -Process {
Receive-Job -Job $PSItem | Export-Clixml -Depth 2 -Path (Join-Path -Path $Path -ChildPath "$(($PSItem.Name -split '_')[1]).csv") -Encoding UTF8 -Force
}
#endregion Inventory
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment