#Requires -Version 5.1 <# .SYNOPSIS Audyt dodatków Office zainstalowanych na lokalnym lub zdalnym komputerze. .DESCRIPTION Nowoczesna wersja Get-OfficeAddins.ps1. MIGRACJA — co zostało zmienione: STARE (deprecated): Get-WmiObject -List "StdRegProv" → WMI (gwmi) usunięte w PS 7 cross-platform Get-WmiObject -Class ... → Get-WmiObject deprecated od PS 3, usunięte z PS 7+ Invoke-WmiMethod → WMI method call NOWE (2026): Get-CimInstance → CIM (DCOM/WSMan), działa PS 5.1 i PS 7+ Invoke-CimMethod → CIM method call [Microsoft.Win32.RegistryKey] → natywny .NET dla rejestru (szybszy niż WMI StdRegProv) Skanuje rejestr pod kątem dodatków COM, VSTO i Web Add-in dla: - Word, Excel, PowerPoint, Outlook, Access, Project, Visio .PARAMETER ComputerName Komputer(y) do przeskanowania. Domyślnie: localhost. .PARAMETER ExportPath Ścieżka do pliku CSV z wynikami. Opcjonalne. .PARAMETER IncludeDisabled Uwzględnij też wyłączone dodatki (LoadBehavior = 0, 2). .EXAMPLE .\Get-OfficeAddins-Modern.ps1 .EXAMPLE .\Get-OfficeAddins-Modern.ps1 -ComputerName PC01,PC02 -ExportPath "C:\Raporty\addins.csv" .EXAMPLE .\Get-OfficeAddins-Modern.ps1 -ComputerName (Get-Content servers.txt) -IncludeDisabled .NOTES Wersja: 2.0.0 (2026) PS 7+: Pełna obsługa (CimInstance przez WSMan) PS 5.1: Obsługa lokalna i przez DCOM #> [CmdletBinding()] param( [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)] [string[]]$ComputerName = @($env:COMPUTERNAME), [string]$ExportPath = "", [switch]$IncludeDisabled ) begin { # Ścieżki rejestru dla dodatków Office (HKLM + HKCU) $addinRegistryPaths = @( "SOFTWARE\Microsoft\Office\Word\Addins", "SOFTWARE\Microsoft\Office\Excel\Addins", "SOFTWARE\Microsoft\Office\PowerPoint\Addins", "SOFTWARE\Microsoft\Office\Outlook\Addins", "SOFTWARE\Microsoft\Office\Access\Addins", "SOFTWARE\WOW6432Node\Microsoft\Office\Word\Addins", "SOFTWARE\WOW6432Node\Microsoft\Office\Excel\Addins", "SOFTWARE\WOW6432Node\Microsoft\Office\PowerPoint\Addins", "SOFTWARE\WOW6432Node\Microsoft\Office\Outlook\Addins" ) # LoadBehavior: 0=wyłączony, 2=wyłączony+autostart, 3=włączony+autostart $loadBehaviorMap = @{ 0 = "Disabled" 2 = "Disabled (Boot)" 3 = "Enabled (Boot)" 8 = "Demand Load" 9 = "Enabled (Demand)" 16 = "First Boot" } $allResults = [System.Collections.Generic.List[PSCustomObject]]::new() } process { foreach ($computer in $ComputerName) { Write-Host "Skanowanie: $computer" -ForegroundColor Cyan # ============================================================ # ODCZYT REJESTRU — .NET RegistryKey (zastępuje WMI StdRegProv) # Dla lokalnego komputera — bezpośredni dostęp przez .NET # Dla zdalnego — CimInstance (WSMan) lub PSSession # ============================================================ $isLocal = ($computer -eq $env:COMPUTERNAME -or $computer -eq "localhost" -or $computer -eq ".") if ($isLocal) { # Lokalny dostęp — Microsoft.Win32.RegistryKey foreach ($regPath in $addinRegistryPaths) { $application = ($regPath -split "\\") | Select-Object -Last 2 | Select-Object -First 1 foreach ($hive in @("LocalMachine", "CurrentUser")) { try { $baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey( [Microsoft.Win32.RegistryHive]::$hive, [Microsoft.Win32.RegistryView]::Default ) $key = $baseKey.OpenSubKey($regPath) if (-not $key) { continue } foreach ($addinName in $key.GetSubKeyNames()) { $addinKey = $key.OpenSubKey($addinName) if (-not $addinKey) { continue } $loadBehavior = $addinKey.GetValue("LoadBehavior") ?? 0 $loadStatus = $loadBehaviorMap[$loadBehavior] ?? "Unknown ($loadBehavior)" # Filtruj wyłączone jeśli nie podano -IncludeDisabled if (-not $IncludeDisabled -and $loadBehavior -in @(0, 2)) { continue } $allResults.Add([PSCustomObject]@{ ComputerName = $computer Application = $application AddinName = $addinName FriendlyName = $addinKey.GetValue("FriendlyName") ?? "" Description = $addinKey.GetValue("Description") ?? "" Manifest = $addinKey.GetValue("Manifest") ?? $addinKey.GetValue("InProcServer32") ?? "" LoadBehavior = $loadBehavior LoadStatus = $loadStatus Hive = $hive RegistryPath = "HKEY_$($hive.ToUpper())\$regPath\$addinName" }) $addinKey.Close() } $key.Close() $baseKey.Close() } catch { Write-Verbose "[$computer] Brak klucza: $hive\$regPath — $($_.Exception.Message)" } } } } else { # Zdalny komputer — CimInstance przez WSMan # (zastępuje: Get-WmiObject -ComputerName $computer) Write-Verbose "[$computer] Używam CimInstance (WSMan)..." try { # Sprawdź połączenie CIM $cimSession = New-CimSession -ComputerName $computer -ErrorAction Stop foreach ($regPath in $addinRegistryPaths) { $application = ($regPath -split "\\") | Select-Object -Last 2 | Select-Object -First 1 # Odczyt przez CIM — StdRegProv przez CimInstance # (Get-WmiObject -List "StdRegProv" → Get-CimClass) $hklm = [uint32]"0x80000002" $hkcu = [uint32]"0x80000001" foreach ($hiveVal in @($hklm, $hkcu)) { $hiveName = if ($hiveVal -eq $hklm) { "LocalMachine" } else { "CurrentUser" } # Enumerate subkeys przez CimInstance StdRegProv $enumParams = @{ ClassName = "StdRegProv" Namespace = "root\default" MethodName = "EnumKey" Arguments = @{ hDefKey = $hiveVal; sSubKeyName = $regPath } CimSession = $cimSession } try { $enumResult = Invoke-CimMethod @enumParams -ErrorAction Stop if ($enumResult.ReturnValue -ne 0 -or -not $enumResult.sNames) { continue } foreach ($addinName in $enumResult.sNames) { $addinPath = "$regPath\$addinName" # Pobierz wartości DWORD (LoadBehavior) $getDword = Invoke-CimMethod -ClassName "StdRegProv" -Namespace "root\default" ` -MethodName "GetDWORDValue" ` -Arguments @{ hDefKey = $hiveVal; sSubKeyName = $addinPath; sValueName = "LoadBehavior" } ` -CimSession $cimSession -ErrorAction SilentlyContinue $loadBehavior = $getDword.uValue ?? 0 $loadStatus = $loadBehaviorMap[$loadBehavior] ?? "Unknown ($loadBehavior)" if (-not $IncludeDisabled -and $loadBehavior -in @(0, 2)) { continue } # Pobierz FriendlyName (string) $getName = Invoke-CimMethod -ClassName "StdRegProv" -Namespace "root\default" ` -MethodName "GetStringValue" ` -Arguments @{ hDefKey = $hiveVal; sSubKeyName = $addinPath; sValueName = "FriendlyName" } ` -CimSession $cimSession -ErrorAction SilentlyContinue $allResults.Add([PSCustomObject]@{ ComputerName = $computer Application = $application AddinName = $addinName FriendlyName = $getName.sValue ?? "" LoadBehavior = $loadBehavior LoadStatus = $loadStatus Hive = $hiveName RegistryPath = "HKEY_$($hiveName.ToUpper())\$addinPath" }) } } catch { Write-Verbose "[$computer] Błąd CIM dla $regPath : $($_.Exception.Message)" } } } Remove-CimSession -CimSession $cimSession -ErrorAction SilentlyContinue } catch { Write-Warning "[$computer] Nie można nawiązać sesji CIM: $($_.Exception.Message)" Write-Warning " Sprawdź: WinRM (Enable-PSRemoting), firewall, uprawnienia." } } } } end { if ($allResults.Count -eq 0) { Write-Host "Nie znaleziono dodatków Office (spełniających kryteria)." -ForegroundColor Yellow return } Write-Host "`nZnaleziono $($allResults.Count) dodatków:" -ForegroundColor Green $allResults | Format-Table ComputerName, Application, FriendlyName, LoadStatus, AddinName -AutoSize if ($ExportPath) { $allResults | Export-Csv -Path $ExportPath -NoTypeInformation -Encoding UTF8 -Delimiter ";" Write-Host "Eksport: $ExportPath" -ForegroundColor Green } return $allResults }