Dieses etwas aufwendigere Skript sucht in der Registry, der angegebenen Netzwerkrechner, nach dem Eintrag einer bestimmten installierten Software.
Ich verwende das Skript um zu prüfen, ob alle Rechner einer bestimmten Gruppe, die per GPO eine Softwareinstallation erfahren sollten, diese auch erhalten haben.
Code:
<#
.Synopsis
Dieses Skript findet heraus auf welchem Rechner in der Domain eine bestimmte Software installiert ist und wo diese fehlt.
.DESCRIPTION
Es wird in der Registrierung jedes Rechners der Domain nach dem Softwareeintrag gesucht, wird dieser gefunden, ist die Software installiert.
Kann der Eintrag nicht gefunden werden, ist die gesuchte Software auf dem Rechner nicht vorhanden.
Durchsucht werden können nur Rechner, die zum Zeitpunkt der Suche Online sind.
.EXAMPLE
Ein Beispiel um auf allen Rechnern auf denen Symantec Endpoint Installiert sein sollte, nachzusehen ob dem so ist:
Search-Software -ComputerArray (Get-ADGroup -Filter "Name -like '*SEP*'" | sort Name | Get-ADGroupMember | select Name) -SoftwareTitel "Symantec Endpoint Protection" -OutHTMLPath "\\Intranetserver\Intranet\IT\Auswertung\Symantec-Auswertung.html"
In diesem Beispiel wird das Ergebnis auch direkt als HTML ins Intranet auf die IT-Seite gestellt.
.EXAMPLE
Ein weiteres Beispiel mit der Verwendung von Aliassen:
ss -ca (Get-ADComputer -Filter *) -st "Docuware"
In diesem Beispiel werden alle Rechner der Domain durchsucht nach dem Begriff Docuware.
Die Ausgabe erfolgt hierbei nur über die Konsole.
.INPUTS
-ComputerArray - Alias -ca - Ein Array von Computern die durchsucht werden sollen.
-SoftwareTitel - Alias -st - Der Name der zu suchenden Anwendung oder ein Teil davon.
.OUTPUTS
-OutHTMLPath - Alias -op - Der Dateipfad der zu erstellenden HTML Datei für die Ausgabe.
.NOTES
Geschrieben von Ulrich Wiedholz am 19.09.2017 für den Zweck in der Domain nachzusehen ob überall der korrekte Antivirenclient (etc.) installiert ist und wenn ja wann und in welcher Version.
.FUNCTIONALITY
Die Registrierung jeden Rechners, der im Parameter -ComputerArray übergeben wurde, wird nach installierter Software durchsucht.
Der Name der zu suchenden Software (oder ein Teil des Namens) wird im Parameter -SoftwareTitel angegeben.
Die Ausgabe erfolgt in der Konsole, kann aber auch mit dem Parameter -OutHTMLPath an eine HTML Seite umgeleitet werden.
#>
function Search-Software
{
[CmdletBinding(DefaultParameterSetName='Computer Array',
SupportsShouldProcess=$true,
PositionalBinding=$false,
HelpUri = 'http://www.bing.de/',
ConfirmImpact='Medium')]
[Alias("ss")]
[OutputType([String])]
Param
(
# Array der Computer die geprüft werden sollen
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$true,
Position=0,
ParameterSetName='Computer Array')]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[Alias("ca")]
$ComputerArray,
# Titel oder Teil des Titels der Software nach der gesucht werden soll
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$true,
Position=1)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidatePattern("[a-z]*")]
[Alias("st")]
[string]
$SoftwareTitel,
# Dateipfad der auszugebenden HTML-Datei
[Parameter(ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$true,
Position=2)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidatePattern("[a-z]*")]
[Alias("op")]
[string]
$OutHTMLPath
)
Begin
{
$script:ErrorActionPreference = "silentlyContinue"
}
Process
{
$Global:SoftwareInformationArr = New-Object system.Collections.ArrayList
foreach ($Computer in $ComputerArray | sort Name)
{
$SoftwareObj = New-Object PsObject
$Gefunden = $false
$cn = $Computer.Name
$Software = icm $cn {Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty}
Write-Verbose "Software wird vom Rechner $cn ausgelesen."
if (!$Software)
{
Write-Verbose "Vom Rechner $cn konnte nicht gelesen werden."
"Rechner $cn war nicht für die Auswertung bereit."
$SoftwareObj | Add-Member -MemberType NoteProperty "Status" -Value "nicht Bereit"
$SoftwareObj | Add-Member -MemberType NoteProperty "Computer" -Value $cn
$SoftwareObj | Add-Member -MemberType NoteProperty "Software" -Value "-"
$SoftwareObj | Add-Member -MemberType NoteProperty "Version" -Value "-"
$SoftwareObj | Add-Member -MemberType NoteProperty "Inst. am" -Value "-"
$Global:SoftwareInformationArr.add($SoftwareObj) | out-null
continue
}
$Software | % {if (($_.DisplayName -like "*" + $SoftwareTitel +"*")-eq $true)
{
Write-Verbose "Software wurde gefunden."
$Gefunden = $true
$sn = $_.DisplayName
$sv = $_.DisplayVersion
$si = $_.InstallDate.ToString()
$si = $si.insert(4,".")
$si = $si.insert(7,".")
$si = (Get-Date $si).ToShortDateString()
"Rechner $cn hat Software ""$sn"" gefunden. Installierte Version $sv."
$SoftwareObj | Add-Member -MemberType NoteProperty "Status" -Value "gefunden"
$SoftwareObj | Add-Member -MemberType NoteProperty "Computer" -Value $cn
$SoftwareObj | Add-Member -MemberType NoteProperty "Software" -Value $sn
$SoftwareObj | Add-Member -MemberType NoteProperty "Version" -Value $sv
$SoftwareObj | Add-Member -MemberType NoteProperty "Inst. am" -Value $si
$Global:SoftwareInformationArr.add($SoftwareObj) | out-null
}
}
if ($Gefunden -eq $false)
{
Write-Verbose "Rechner ohne die Software lokalisiert."
"Rechner $cn hat die gesuchte Software nicht installiert."
$SoftwareObj | Add-Member -MemberType NoteProperty "Status" -Value "fehlt"
$SoftwareObj | Add-Member -MemberType NoteProperty "Computer" -Value $cn
$SoftwareObj | Add-Member -MemberType NoteProperty "Software" -Value "-"
$SoftwareObj | Add-Member -MemberType NoteProperty "Version" -Value "-"
$SoftwareObj | Add-Member -MemberType NoteProperty "Inst. am" -Value "-"
$Global:SoftwareInformationArr.add($SoftwareObj) | out-null
}
}
}
End
{
if ($OutHTMLPath)
{
Write-Verbose "Output als HTML-Datei."
#$Global:SoftwareInformationArr | sort Status, Computer | ogv # <- Ausgabe im Grid
$Global:SoftwareInformationArr | sort Status, Computer | ConvertTo-Html | Out-File -FilePath $OutHTMLPath
}
}
}
# Automatischer Start fürs Intranet, wenn das Skript mit Startparameter "SEP" gestartet wurde.
# Es werden dann alle AD-Gruppen die für die Installation von SEP verantwortlich sind durchsucht. Dort müsste überall SEP zu finden sein. Das Ergebnis wird im IT-Intranet veröffentlicht.
if ([System.String]$Args[0] -eq "SEP"){Search-Software -ca (Get-ADGroup -Filter "Name -like '*SEP*'" | sort Name | Get-ADGroupMember | select Name) -st "Symantec Endpoint Protection" -op "\\Intranetserver\Intranet\IT\Auswertungen\Symantec-Auswertung.html"}
Wie die letzte Zeile zeigt, kann das Skript auch direkt unter Angabe eines entsprechenden Parameters automatisiert ausgeführt werden.
So behält man auch den Überblick über installierte Versionen und wann diese installiert wurden.
Natürlich ist das ganze beliebig erweiterbar und soll nur als Beispiel und Anregung dienen.