Created
January 18, 2014 13:14
-
-
Save p0w3rsh3ll/8490370 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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