The post-fix capture from 579C144 reported three entries as unknown(0x04) - SecurityHealth, RtkAudUService, WavesSvc. The decoder only knew 02/06 enabled and 03/07 disabled. 04 is also enabled and 05 also disabled; without them the report says 'unknown' for entries that are perfectly ordinary.
410 lines
19 KiB
PowerShell
410 lines
19 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Collect everything needed to diagnose an imaged bay, into one zip.
|
|
|
|
.DESCRIPTION
|
|
Read-only. Changes nothing on the machine.
|
|
|
|
Written because every imaging investigation so far has meant walking to a bay
|
|
and hand-copying files, and each time we discovered another thing we wished
|
|
we had grabbed at the same moment. This takes the lot in one pass.
|
|
|
|
Run it on a freshly imaged bay BEFORE lockdown.
|
|
|
|
This captures KNOWN-CURRENT, not known-good. A bay straight off the line has
|
|
applications on it that should not be there - preinstall.json entries without
|
|
a PCTypes filter install everywhere, so a Display bay picks up Adobe,
|
|
OpenText and Defect Tracker. The point of collecting is to have an exact
|
|
record of what imaging really produces, so the unnecessary items can be
|
|
identified and filtered out.
|
|
|
|
Before lockdown specifically, because afterwards you cannot tell whether
|
|
something is absent because lockdown removed it or because imaging never
|
|
installed it.
|
|
|
|
.PARAMETER Destination
|
|
Where to drop the zip. Defaults to C:\Logs. Point it at a share to collect
|
|
centrally, e.g. -Destination \\172.16.9.1\enrollment\imaging-logs
|
|
(only reachable while the bay is still on the imaging LAN).
|
|
|
|
.PARAMETER Label
|
|
Optional tag folded into the filename, e.g. -Label pre-lockdown.
|
|
|
|
.EXAMPLE
|
|
.\Collect-ImagingDiagnostics.ps1 -Label pre-lockdown
|
|
|
|
.EXAMPLE
|
|
.\Collect-ImagingDiagnostics.ps1 -Destination \\172.16.9.1\enrollment\imaging-logs
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$Destination = 'C:\Logs',
|
|
[string]$Label = ''
|
|
)
|
|
|
|
$ErrorActionPreference = 'Continue'
|
|
$ProgressPreference = 'SilentlyContinue'
|
|
|
|
$serial = try { (Get-CimInstance Win32_BIOS).SerialNumber.Trim() } catch { 'unknown' }
|
|
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
|
$name = if ($Label) { "$serial-$Label-$stamp" } else { "$serial-$stamp" }
|
|
$work = Join-Path $env:TEMP "imgdiag-$name"
|
|
New-Item -ItemType Directory -Path $work -Force | Out-Null
|
|
|
|
function Section { param([string]$File, [scriptblock]$Body)
|
|
$p = Join-Path $work $File
|
|
try { & $Body 2>&1 | Out-File -FilePath $p -Encoding utf8 -Width 500 }
|
|
catch { "COLLECTION ERROR: $_" | Out-File -FilePath $p -Encoding utf8 }
|
|
Write-Host (" {0}" -f $File)
|
|
}
|
|
|
|
function CopyTree { param([string]$Src, [string]$Dst)
|
|
# /XF *.ppkg and /MAX are not optional. run-enrollment harvests
|
|
# C:\ProgramData\Microsoft\Provisioning into C:\Logs\PPKG, so the 8 GB
|
|
# provisioning package exists TWICE under the trees we copy. Without these
|
|
# the collection is 16 GB and Compress-Archive dies with "stream was too
|
|
# long" - it cannot exceed 2 GB.
|
|
if (Test-Path $Src) {
|
|
$d = Join-Path $work $Dst
|
|
New-Item -ItemType Directory -Path $d -Force | Out-Null
|
|
robocopy $Src $d /E /R:0 /W:0 /NFL /NDL /NJH /NJS /XF *.ppkg *.wim *.iso /MAX:104857600 | Out-Null
|
|
Write-Host (" {0}\ <- {1}" -f $Dst, $Src)
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Collecting imaging diagnostics for $serial ..."
|
|
Write-Host ""
|
|
|
|
# --- 1. Identity ---------------------------------------------------------
|
|
# ActiveComputerName is the name in use; ComputerName is the PENDING one. They
|
|
# differ when a rename is queued for the next reboot - which is exactly how the
|
|
# H<serial> -> F<serial> transition works, so capturing both tells you whether
|
|
# the package's rename landed or is still waiting.
|
|
Section 'identity.txt' {
|
|
'== computer names =='
|
|
'Active (in use): ' + (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName' -EA SilentlyContinue).ComputerName
|
|
'Pending (next boot): ' + (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName' -EA SilentlyContinue).ComputerName
|
|
'NV Hostname: ' + (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters' -EA SilentlyContinue).'NV Hostname'
|
|
''
|
|
'== hardware =='
|
|
Get-CimInstance Win32_ComputerSystem | Select-Object Manufacturer, Model, Domain, PartOfDomain, TotalPhysicalMemory | Format-List
|
|
Get-CimInstance Win32_BIOS | Select-Object SerialNumber, SMBIOSBIOSVersion, ReleaseDate | Format-List
|
|
Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, BuildNumber, InstallDate, LastBootUpTime | Format-List
|
|
''
|
|
'== uptime / install =='
|
|
'Windows installed: ' + (Get-CimInstance Win32_OperatingSystem).InstallDate
|
|
}
|
|
|
|
# --- 2. Enrollment state -------------------------------------------------
|
|
# dsregcmd is the authority on whether the Entra join actually happened.
|
|
# criticalChecks.json is the package's own self-assessment and the two can
|
|
# disagree - "Entra ID Joined: false" right after imaging is normal because the
|
|
# bay has not reached the production network yet.
|
|
Section 'enrollment.txt' {
|
|
'== dsregcmd /status =='
|
|
& dsregcmd /status
|
|
''
|
|
'== package self-checks =='
|
|
foreach ($f in 'C:\Logs\BPRT\criticalChecks.json','C:\Logs\BPRT\packageInfo.json',
|
|
'C:\Logs\BPRT\Orchestrator\TokenMatch.json') {
|
|
if (Test-Path $f) { "--- $f ---"; Get-Content $f -Raw }
|
|
}
|
|
''
|
|
'== staged selections =='
|
|
foreach ($f in 'C:\Enrollment\pc-type.txt','C:\Enrollment\display-type.txt',
|
|
'C:\Enrollment\pc-config.txt','C:\Enrollment\machine-number.txt',
|
|
'C:\Enrollment\fetch-source.txt') {
|
|
if (Test-Path $f) { "$f = " + ((Get-Content $f -First 1) -replace 'pxe$','<redacted>') }
|
|
}
|
|
}
|
|
|
|
# --- 3. Installed applications ------------------------------------------
|
|
# Registry Uninstall keys, both views. Deliberately NOT Win32_Product: querying
|
|
# it triggers an MSI reconfigure of every installed product, which is slow and
|
|
# can actually change the machine.
|
|
Section 'installed-apps.txt' {
|
|
$paths = @(
|
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
|
|
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
|
|
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
|
)
|
|
Get-ItemProperty $paths -EA SilentlyContinue |
|
|
Where-Object { $_.DisplayName } |
|
|
Sort-Object DisplayName |
|
|
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate, InstallLocation |
|
|
Format-Table -AutoSize
|
|
}
|
|
|
|
# --- 4. Everything that starts by itself --------------------------------
|
|
# THE section for "why did this app launch". Installers plant their own startup
|
|
# entries, so an app being installed IS an app being started - there is no
|
|
# separate switch. Capturing all four surfaces shows which app planted what.
|
|
# Note both registry views: a 32-bit installer's Run key lands under
|
|
# Wow6432Node and 64-bit tooling never sees it.
|
|
Section 'autostart.txt' {
|
|
'== HKLM Run / RunOnce (native + WOW64) =='
|
|
foreach ($k in 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
|
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',
|
|
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run',
|
|
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\RunOnce') {
|
|
if (Test-Path $k) { "--- $k ---"; Get-ItemProperty $k | Format-List }
|
|
}
|
|
''
|
|
'== HKCU Run / RunOnce (current user) =='
|
|
foreach ($k in 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
|
|
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce') {
|
|
if (Test-Path $k) { "--- $k ---"; Get-ItemProperty $k | Format-List }
|
|
}
|
|
''
|
|
'== Startup folders =='
|
|
foreach ($d in "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp",
|
|
"$env:AppData\Microsoft\Windows\Start Menu\Programs\StartUp") {
|
|
if (Test-Path $d) { "--- $d ---"; Get-ChildItem $d | Select-Object Name, Length, LastWriteTime | Format-Table -AutoSize }
|
|
}
|
|
''
|
|
'== per-user Startup folders (all profiles) =='
|
|
Get-ChildItem 'C:\Users' -Directory -EA SilentlyContinue | ForEach-Object {
|
|
$d = Join-Path $_.FullName 'AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup'
|
|
if (Test-Path $d) { "--- $d ---"; Get-ChildItem $d | Select-Object Name | Format-Table -AutoSize }
|
|
}
|
|
''
|
|
'== enabled/disabled state (StartupApproved) =='
|
|
# Disabling a startup item via Task Manager or Settings does NOT remove the
|
|
# Run key or the Startup shortcut - it writes a flag here. So an entry can
|
|
# appear above and still be switched off. First byte 02/06 = enabled,
|
|
# 03/07 = disabled. Capturing this is what tells "imaging installed it and
|
|
# it runs" apart from "imaging installed it and somebody turned it off",
|
|
# which matters because the fix is not to install it at all.
|
|
foreach ($k in 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run',
|
|
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\StartupFolder',
|
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run',
|
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run32',
|
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\StartupFolder') {
|
|
if (Test-Path $k) {
|
|
"--- $k ---"
|
|
$props = Get-Item $k
|
|
foreach ($n in $props.Property) {
|
|
$v = (Get-ItemProperty $k -Name $n).$n
|
|
$state = if ($v -is [byte[]] -and $v.Length -ge 1) {
|
|
switch ($v[0]) { 2 {'ENABLED'} 4 {'ENABLED'} 6 {'ENABLED'} 3 {'disabled'} 5 {'disabled'} 7 {'disabled'} default {"unknown(0x{0:X2})" -f $v[0]} }
|
|
} else { 'unknown' }
|
|
"{0,-10} {1}" -f $state, $n
|
|
}
|
|
}
|
|
}
|
|
''
|
|
'== scheduled tasks (non-Microsoft) =='
|
|
Get-ScheduledTask -EA SilentlyContinue |
|
|
Where-Object { $_.TaskPath -notlike '\Microsoft\*' } |
|
|
Select-Object TaskPath, TaskName, State,
|
|
@{n='Triggers';e={ ($_.Triggers | ForEach-Object { $_.CimClass.CimClassName }) -join ',' }},
|
|
@{n='Action';e={ ($_.Actions | ForEach-Object { $_.Execute }) -join ',' }} |
|
|
Sort-Object TaskPath, TaskName | Format-Table -AutoSize -Wrap
|
|
''
|
|
'== services set to auto-start (non-Microsoft paths) =='
|
|
Get-CimInstance Win32_Service -EA SilentlyContinue |
|
|
Where-Object { $_.StartMode -eq 'Auto' -and $_.PathName -notmatch 'C:\\Windows\\' } |
|
|
Select-Object Name, DisplayName, State, StartMode, PathName |
|
|
Sort-Object Name | Format-Table -AutoSize -Wrap
|
|
}
|
|
|
|
# --- 5. Kiosk / display specifics ---------------------------------------
|
|
Section 'display-kiosk.txt' {
|
|
'== kiosk shortcuts anywhere in Startup =='
|
|
Get-ChildItem 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp' -EA SilentlyContinue |
|
|
ForEach-Object {
|
|
$sh = (New-Object -ComObject WScript.Shell).CreateShortcut($_.FullName)
|
|
"{0}`n target: {1}`n args: {2}" -f $_.Name, $sh.TargetPath, $sh.Arguments
|
|
}
|
|
''
|
|
'== Edge policies =='
|
|
foreach ($k in 'HKLM:\SOFTWARE\Policies\Microsoft\Edge',
|
|
'HKLM:\SOFTWARE\Policies\Microsoft\Windows\System') {
|
|
if (Test-Path $k) { "--- $k ---"; Get-ItemProperty $k | Format-List }
|
|
}
|
|
}
|
|
|
|
# --- 6. GE-Enforce -------------------------------------------------------
|
|
Section 'ge-enforce.txt' {
|
|
'== registry config =='
|
|
foreach ($k in 'HKLM:\SOFTWARE\GE\SFLD\Credentials','HKLM:\SOFTWARE\GE\SFLD\DSC',
|
|
'HKLM:\SOFTWARE\GE\ShopDB') {
|
|
# values only - do not dump anything that looks like a secret
|
|
if (Test-Path $k) {
|
|
"--- $k ---"
|
|
Get-Item $k | Select-Object -ExpandProperty Property | ForEach-Object {
|
|
$v = (Get-ItemProperty $k -Name $_).$_
|
|
if ($_ -match '(?i)key|token|secret|password|sas') { "$_ = <redacted, length $($v.ToString().Length)>" }
|
|
else { "$_ = $v" }
|
|
}
|
|
}
|
|
}
|
|
''
|
|
'== enforce client / DSC on disk =='
|
|
foreach ($d in 'C:\ProgramData\SFLD','C:\Deploy\Applications\BPRT') {
|
|
if (Test-Path $d) { "--- $d ---"; Get-ChildItem $d -Recurse -Depth 1 | Select-Object FullName, Length, LastWriteTime | Format-Table -AutoSize }
|
|
}
|
|
}
|
|
|
|
# --- 6b. IS IT ACTUALLY TALKING TO THE SHOPDB GE-ENFORCE API? -----------
|
|
# Config on disk proves nothing - the client can be present, configured, and
|
|
# never once succeed. This answers the actual question: is there a client, is it
|
|
# scheduled, has it run, and can this bay reach the endpoint right now.
|
|
#
|
|
# A 401 from the manifest endpoint is a GOOD result here: it proves DNS, routing
|
|
# and TLS all work and the service answered. Only a timeout or DNS failure means
|
|
# genuinely unreachable. No token is sent, so nothing here can enrol or change
|
|
# anything.
|
|
Section 'geenforce-api.txt' {
|
|
'== is the client installed? =='
|
|
$clientPaths = @(
|
|
'C:\Program Files\ShopDB', 'C:\ProgramData\ShopDB',
|
|
'C:\Deploy\Applications\BPRT\ShopdbEnforceClient.psm1',
|
|
'C:\Enrollment\ShopdbEnforceClient.psm1'
|
|
)
|
|
$found = $false
|
|
foreach ($p in $clientPaths) {
|
|
if (Test-Path $p) { $found = $true; "FOUND: $p"
|
|
Get-ChildItem $p -Recurse -EA SilentlyContinue |
|
|
Select-Object FullName, Length, LastWriteTime | Format-Table -AutoSize }
|
|
}
|
|
if (-not $found) { 'NOT FOUND - no ShopDB enforce client on this machine.' }
|
|
''
|
|
'== scheduled tasks that would run it =='
|
|
$tasks = Get-ScheduledTask -EA SilentlyContinue |
|
|
Where-Object { $_.TaskName -match '(?i)shopdb|ge-?enforce|asset report' }
|
|
if ($tasks) {
|
|
foreach ($t in $tasks) {
|
|
$i = $t | Get-ScheduledTaskInfo -EA SilentlyContinue
|
|
"{0}\{1} State={2} LastRun={3} LastResult={4} NextRun={5}" -f `
|
|
$t.TaskPath, $t.TaskName, $t.State, $i.LastRunTime, $i.LastTaskResult, $i.NextRunTime
|
|
($t.Actions | ForEach-Object { " action: $($_.Execute) $($_.Arguments)" })
|
|
}
|
|
} else { 'NONE - nothing scheduled to call the API.' }
|
|
''
|
|
'== configured base URL =='
|
|
$base = $null
|
|
foreach ($k in 'HKLM:\SOFTWARE\GE\ShopDB','HKLM:\SOFTWARE\GE\SFLD\Credentials') {
|
|
if (Test-Path $k) {
|
|
$p = Get-ItemProperty $k
|
|
foreach ($n in $p.PSObject.Properties.Name) {
|
|
# Match the NAME tightly and validate the VALUE looks like a URL.
|
|
# A loose "base" match picked up baseVersion=2.0.2 and the probe
|
|
# then tried to fetch "2.0.2/api/docs".
|
|
if ($n -match '(?i)^(baseurl|serverurl|shopdburl|endpoint|url)$') {
|
|
"$k\$n = $($p.$n)"
|
|
if (-not $base -and "$($p.$n)" -match '^https?://') { $base = $p.$n }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (-not $base) { '(no BaseUrl configured - falling back to the known prod URL for the reachability test)' }
|
|
if (-not $base) { $base = 'https://tsgwp00525.wjs.geaerospace.net/shopdb' }
|
|
''
|
|
"== can this bay reach it right now? (base: $base) =="
|
|
$targets = @(
|
|
@{ Name = 'API docs'; Url = "$base/api/docs" },
|
|
@{ Name = 'GE-Enforce manifest'; Url = "$base/api/geenforce/manifest?pctype=gea-shopfloor-display" }
|
|
)
|
|
foreach ($t in $targets) {
|
|
try {
|
|
$sw = [Diagnostics.Stopwatch]::StartNew()
|
|
$r = Invoke-WebRequest -Uri $t.Url -UseBasicParsing -TimeoutSec 20 -EA Stop
|
|
$sw.Stop()
|
|
"{0,-22} HTTP {1} in {2} ms <- reachable" -f $t.Name, $r.StatusCode, $sw.ElapsedMilliseconds
|
|
} catch {
|
|
$code = try { $_.Exception.Response.StatusCode.value__ } catch { $null }
|
|
if ($code) {
|
|
"{0,-22} HTTP {1} <- REACHABLE (service answered; 401/403 just means no token was sent)" -f $t.Name, $code
|
|
} else {
|
|
"{0,-22} UNREACHABLE: {1}" -f $t.Name, $_.Exception.Message
|
|
' NOTE: ShopDB is only reachable once the bay has joined the AESFMA wifi SSID.'
|
|
' On the imaging LAN or plain wired, unreachable here is EXPECTED, not a fault.'
|
|
}
|
|
}
|
|
}
|
|
''
|
|
'== name resolution / route =='
|
|
try {
|
|
$h = ([uri]$base).Host
|
|
"host: $h"
|
|
Resolve-DnsName $h -EA Stop | Select-Object Name, Type, IPAddress | Format-Table -AutoSize
|
|
Test-NetConnection -ComputerName $h -Port 443 -InformationLevel Detailed -WarningAction SilentlyContinue |
|
|
Select-Object ComputerName, RemoteAddress, TcpTestSucceeded, PingSucceeded | Format-List
|
|
} catch { "DNS/route check failed: $_" }
|
|
''
|
|
'== client logs, if any =='
|
|
foreach ($d in 'C:\Logs\ShopDB','C:\Logs\GE-Enforce','C:\ProgramData\ShopDB\Logs') {
|
|
if (Test-Path $d) { "--- $d ---"; Get-ChildItem $d -Recurse | Select-Object FullName, Length, LastWriteTime | Format-Table -AutoSize }
|
|
}
|
|
}
|
|
|
|
# --- 7. Drivers, disk, network ------------------------------------------
|
|
Section 'drivers-disk-network.txt' {
|
|
'== third-party drivers =='
|
|
& pnputil /enum-drivers
|
|
''
|
|
'== disk layout =='
|
|
Get-Disk -EA SilentlyContinue | Format-Table -AutoSize
|
|
Get-Partition -EA SilentlyContinue | Format-Table -AutoSize
|
|
Get-Volume -EA SilentlyContinue | Format-Table -AutoSize
|
|
''
|
|
'== network =='
|
|
Get-NetAdapter -EA SilentlyContinue | Select-Object Name, InterfaceDescription, Status, LinkSpeed, MacAddress | Format-Table -AutoSize
|
|
Get-NetIPAddress -AddressFamily IPv4 -EA SilentlyContinue | Select-Object InterfaceAlias, IPAddress, PrefixOrigin | Format-Table -AutoSize
|
|
Get-DnsClientServerAddress -AddressFamily IPv4 -EA SilentlyContinue | Format-Table -AutoSize
|
|
}
|
|
|
|
# --- 8. Provisioning session state --------------------------------------
|
|
Section 'provisioning-sessions.txt' {
|
|
'== sessions =='
|
|
$k = 'HKLM:\SOFTWARE\Microsoft\Provisioning\Sessions'
|
|
if (Test-Path $k) {
|
|
Get-ChildItem $k | ForEach-Object {
|
|
$p = Get-ItemProperty $_.PSPath
|
|
"{0} State={1} RebootCount={2}" -f $_.PSChildName, $p.State, $p.RebootCount
|
|
}
|
|
} else { '(no provisioning sessions key)' }
|
|
}
|
|
|
|
# --- 9. Log trees --------------------------------------------------------
|
|
CopyTree 'C:\Logs' 'Logs'
|
|
CopyTree 'C:\Windows\Panther' 'Panther'
|
|
CopyTree 'C:\ProgramData\Microsoft\Provisioning' 'ProvisioningData'
|
|
foreach ($f in 'C:\Enrollment\winpe-staging.log','C:\Enrollment\setupcomplete.log') {
|
|
if (Test-Path $f) { Copy-Item $f $work -Force -EA SilentlyContinue }
|
|
}
|
|
|
|
# Enrollment dir listing only - it holds an 8 GB package we do not want.
|
|
Section 'enrollment-dir-listing.txt' {
|
|
if (Test-Path 'C:\Enrollment') {
|
|
Get-ChildItem 'C:\Enrollment' -Recurse -EA SilentlyContinue |
|
|
Select-Object FullName, Length, LastWriteTime | Format-Table -AutoSize
|
|
}
|
|
}
|
|
|
|
# --- 10. Provisioning event log -----------------------------------------
|
|
try {
|
|
$evtx = Join-Path $work 'Provisioning-Diagnostics-Admin.evtx'
|
|
& wevtutil epl 'Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin' $evtx /ow:true 2>$null
|
|
if (Test-Path $evtx) { Write-Host ' Provisioning-Diagnostics-Admin.evtx' }
|
|
} catch { }
|
|
|
|
# --- zip -----------------------------------------------------------------
|
|
New-Item -ItemType Directory -Path $Destination -Force -EA SilentlyContinue | Out-Null
|
|
$zip = Join-Path $Destination "imgdiag-$name.zip"
|
|
try {
|
|
Compress-Archive -Path (Join-Path $work '*') -DestinationPath $zip -Force -EA Stop
|
|
Remove-Item $work -Recurse -Force -EA SilentlyContinue
|
|
Write-Host ""
|
|
Write-Host "Wrote $zip"
|
|
Write-Host ("Size: {0:N1} MB" -f ((Get-Item $zip).Length / 1MB))
|
|
} catch {
|
|
Write-Host ""
|
|
Write-Host "Could not zip to $Destination : $_"
|
|
Write-Host "Raw collection left at: $work"
|
|
}
|
|
Write-Host ""
|