Office – Check out our new look

Hey Microsoft QA, you might want to check out your new look:

animated GIF of Office's horrible new 'Check out our new look' popup

It looks less “modern, coherent and familiar”, and more “Unreadable” and “lost the Title Bar”.

This has popped up on many systems recently, so Consider it Checked out and extremely Not now.

Update 2022-02-25 It just popped up again where it was previously dismissed
(did they realize it was garbled and wanted another chance to persuade?)

Comparing key frames…


Their fixed comparison seems to offer :

  • LOSS of support for Windows’ Title Bar accent colors
  • LOSS of the Quick Access Toolbar from the Title Bar
    …and of those, add just “Undo” back to the Ribbon (Customize the Ribbon could already do this)
  • LOSS of usable vertical space to 15% increased Ribbon sprawl
  • LOSS of usable horizontal space, reducing Style choices from 4 to 3.

So “modern, coherent and familiar” means: form over function!, set the designers loose!, dumb it down!
…aka a typical “Fresh New Look”.

Now, you can do stuff without clicking buttons, ’cause they’re annoying!

RMM Check: Unifi Health

At Slingshot, we’ve moved our Managed clients over to Unifi networking systems, and I wanted to use our RMM to directly monitor the Unifi Controller. The API isn’t officially documented, but I did find other resources: the community’s API documentation, CyberDrain’s examples, and the Unifi API browser. Add tons of other research and trial/error, and I finally accomplished a Powershell RMM script that monitors Device connections, resources/ports, and Alerts, and reports on a ton more.

Enough with the intros. Here’s an instance currently alerting in Solarwinds RMM:

…and More Info gives the full report (looks better in console — I wish SWRMM preserved whitespace):

Before I forget, some quick notes:

  • Needs a local account (limited admin/readonly) on controller
  • For UDMPs with firmware 1.6 or greater, use port 443; For older controllers, use port 8443
  • It defaults the Controller IP to the detected Gateway IP (we do a lot of UDMPs).
  • Several of the Device Status codes are documented nowhere, so this script might have the only public record of them (for posterity, I’ve figured out 2=pending adoption, 9=inform error, and 11=isolated).

And finally the Powershell — (self-consciously) still in progress with plenty of debug stubs, BUT with lots of useful production miles already under its belt:

<#	checkHealth-UnifiController.ps1
Purpose: for all sites on a controller, checks device connections, resources, ports, alerts
Author: 	Slingshot Solutions,
Params:		$IP (or hostname) of controller (default: detected gateway), [int]$PortNum (default:443), Username, PASSWORD
* needs a local account (limited admin/readonly) on controller
* For UDMPs with firmware 1.6 or greater, use port 443;  For older controllers, use port 8443

  $IP = (Get-wmiObject Win32_networkAdapterConfiguration |where-object{$_.IPEnabled -and $_.DefaultIPGateway}).DefaultIPGateway[0],
  $PortNum = 443, # or 8443 depending on controller version
# tweaks:
trap { $_; exit 1 }	# force RMM to treat unhandled runtime errors as ERROR!
#widen host buffer for better output on old PS versions:
$newsize=$pswindow.BufferSize; if($newsize.width -lt 100){$newsize.width=100}; $pswindow.BufferSize=$newsize
$newsize=$pswindow.WindowSize; if($newsize.width -lt 100){$newsize.width=100;$newsize.height=20}; $pswindow.WindowSize=$newsize
function short([string]$str,[int]$size){if($str.length -gt $size){return ($str.substring(0,$size-3)+"...")}else{ return $str}}
# vars:
$exitcode = 0
$report = ""
$FullRpt = ""
$StopWatch = [system.diagnostics.stopwatch]::startNew()

	write-host "PARAMETERS:"
	foreach ( $key in ((Get-Command -Name $MyInvocation.InvocationName).Parameters).Keys ) {
		$val = ((Get-Variable $key -ea SilentlyContinue).Value) -join ", "
		Write-Host "  $($key): $val" 
	write-error "Hey dummy, set your params!"
	exit 1000

$Credential = @{  username="$Username"; password="$Password"; remember=$True; strict=$True; } |ConvertTo-Json
if($PortNum -eq 443){ # UnifiOS 1.6 or newer:
	$BaseURI = "https://$($IP):$($PortNum)/proxy/network"
	$LoginURI = "https://$($IP):$($PortNum)/api/auth/login"
}elseif($PortNum -eq 8443){ # EdgeOS 1.5 firmware or older:
  $BaseURI = "https://$($IP):$($PortNum)"
	$LoginURI = "https://$($IP):$($PortNum)/api/login"

[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
[Net.ServicePointManager]::ServerCertificateValidationCallback = { $True }
Try {
	$login = Invoke-RestMethod -uri $LoginURI -Method POST -Body $Credential -ContentType "application/json" -SessionVariable UniFiSession | out-null
}catch{	#wrong username/password = "The remote server returned an error: (400) Bad Request"
	write-error "* ERROR - Api Connection Error: $($_.Exception.Message)"    
	$exitcode = 1010
if($exitcode -eq 0){
	#write-host "CONNECTED`r`n"

if($exitcode -eq 0){
	try {
		$urlSites = "$($BaseURI)/api/stat/sites"
		$sites = Invoke-Restmethod -Uri $urlSites -Method GET -WebSession $UniFiSession
		#$report += "* ERROR - Sites Query Failed: $($_.Exception.Message)`r`n"
		write-error "* ERROR - Sites Query Failed: $($_.Exception.Message)`r`n"
		$exitcode = 1011

if($exitcode -eq 0){
	# DIRTY HACK: UDMPs lose their auth on the second call (Something ServerCertificateValidationCallback related), so just pound it back every time:
	Invoke-RestMethod -uri $LoginURI -Method POST -Body $Credential -ContentType "application/json" -SessionVariable UniFiSession | out-null

	$rptDevices = ""
	$rptAlarms = ""
	Foreach ($site in ${  # SITE
		try {
			$urlDevices = "$($BaseURI)/api/s/$($"
			$devices = Invoke-Restmethod -Uri $urlDevices -Method GET -ContentType "application/json" -Headers @{"Accept"="application/json"} -WebSession $UniFiSession
			write-error "* ERROR - Device Query Failed: $($_.Exception.Message)`r`n"
		$shortsitename = short $site.desc 7

		$FullRpt += "`r`nSITE '$($site.desc)' - $urlDevices :`r`n"

		$DeviceStateNames = @{0="disconnected"; 1="connected"; 2="pending adoption"; 3="3(?)"; 4="upgrading"; 5="provisioning"; 6="heartbeat missed"; 9="inform error"; 11="isolated" }
		$DeviceModelNames = @{"BZ2"="UniFi AP"; "BZ2LR"="UniFi AP-LR"; "U2HSR"="UniFi AP-Outdoor+"; "U2IW"="UniFi AP-In Wall"; "U2L48"="UniFi AP-LR"; "U2Lv2"="UniFi AP-LR v2"; "U2M"="UniFi AP-Mini"; "U2O"="UniFi AP-Outdoor"; "U2S48"="UniFi AP"; "U2Sv2"="UniFi AP v2"; "U5O"="UniFi AP-Outdoor 5G"; "U7E"="UniFi AP-AC"; "U7EDU"="UniFi AP-AC-EDU"; "U7Ev2"="UniFi AP-AC v2"; "U7HD"="UniFi AP-HD"; "U7SHD"="UniFi AP-SHD"; "U7NHD"="UniFi AP-nanoHD"; "UFLHD"="UniFi AP-Flex-HD"; "UHDIW"="UniFi AP-HD-In Wall"; "UCXG"="UniFi AP-XG"; "UXSDM"="UniFi AP-BaseStationXG"; "UCMSH"="UniFi AP-MeshXG"; "U7IW"="UniFi AP-AC-In Wall"; "U7IWP"="UniFi AP-AC-In Wall Pro"; "U7MP"="UniFi AP-AC-Mesh-Pro"; "U7LR"="UniFi AP-AC-LR"; "U7LT"="UniFi AP-AC-Lite"; "U7O"="UniFi AP-AC Outdoor"; "U7P"="UniFi AP-Pro"; "U7MSH"="UniFi AP-AC-Mesh"; "U7PG2"="UniFi AP-AC-Pro"; "p2N"="PicoStation M2"; "US48PRO"="UniFi Switch Pro 48"; "US8"="UniFi Switch 8"; "US8P60"="UniFi Switch 8 POE-60W"; "US8P150"="UniFi Switch 8 POE-150W"; "S28150"="UniFi Switch 8 AT-150W"; "USC8"="UniFi Switch 8"; "US16P150"="UniFi Switch 16 POE-150W"; "S216150"="UniFi Switch 16 AT-150W"; "US24"="UniFi Switch 24"; "US24P250"="UniFi Switch 24 POE-250W"; "US24PL2"="UniFi Switch 24 L2 POE"; "US24P500"="UniFi Switch 24 POE-500W"; "S224250"="UniFi Switch 24 AT-250W"; "S224500"="UniFi Switch 24 AT-500W"; "US48"="UniFi Switch 48"; "US48P500"="UniFi Switch 48 POE-500W"; "US48PL2"="UniFi Switch 48 L2 POE"; "US48P750"="UniFi Switch 48 POE-750W"; "S248500"="UniFi Switch 48 AT-500W"; "S248750"="UniFi Switch 48 AT-750W"; "US6XG150"="UniFi Switch 6XG POE-150W"; "USXG"="UniFi Switch 16XG"; "UGW3"="UniFi Security Gateway 3P"; "UGW4"="UniFi Security Gateway 4P"; "UGWHD4"="UniFi Security Gateway HD"; "UGWXG"="UniFi Security Gateway XG-8"; "UP4"="UniFi Phone-X"; "UP5"="UniFi Phone"; "UP5t"="UniFi Phone-Pro"; "UP7"="UniFi Phone-Executive"; "UP5c"="UniFi Phone"; "UP5tc"="UniFi Phone-Pro"; "UP7c"="UniFi Phone-Executive";
		"UDMPRO"="UniFi Dream Machine Pro"}

		Foreach ($device in (${
			$DeviceModelName = $DeviceModelNames[$($device.model)]
			$DeviceStateName = $DeviceStateNames[$device.state]

			if( $device.default -eq $True){	# PENDING ADOPTION:
				$vwireEnabled = ($device.vwireEnabled -eq $True)
				$discovered_via = $device.discovered_via	#scan or l2
				$FullRpt += "* $($device.type) $DeviceModelName, ip:$($device.ip), mac:$($device.mac), state:$DeviceStateName $($device.state), discovered_via:$discovered_via, wireless:$vwireEnabled`r`n"				
				$rptDevices += "* PENDING ADOPTION$(if($vwireEnabled){" (WIRELESS)"}): $shortsitename > ($DeviceModelName)`r`n"
				$exitcode = 1010

			}elseif ($device.adopted -eq $True){
				if($device.state -eq 0 -or $device.state -eq 9 -or $device.state -eq 11){	# DISCONNECTED, INFORM ERROR, ISOLATED:
					$FullRpt += "* '$($device.NAME)' - $($device.type) $DeviceModelName, ip:$($device.ip), mac:$($device.mac),`r`n    state:$($device.state) $DeviceStateName, adopted:$($device.adopted), disabled:$($device.disabled -eq $True)`r`n"				
					if($device.disabled -ne $True){	# don't care if it's disabled
						$rptDevices += "* $($DeviceStateName.toUpper()): $shortsitename > '$($'`r`n"
						$exitcode = 1011
				}else{	# OTHERWISE:					
					$uptime = new-TimeSpan -Seconds (0+ $device.'system-stats'.uptime)

					$FullRpt += "* '$($device.NAME)' - $($device.type) $DeviceModelName, ip:$($device.ip), mac:$($device.mac),`r`n    state:$($device.state) $DeviceStateName, uptime:$uptime, cpu:$([int]$device.'system-stats'.cpu)%, mem:$([int]$device.'system-stats'.mem)%, current:$(!$device.upgradable) (FW v$($device.version))`r`n"

					if( [math]::Round($device.'system-stats'.uptime) -lt "300") { 
						$rptDevices += "* $shortsitename > $($ : Disconnected `r`n"
						$exitcode = 1010
					if( [math]::Round($device.'system-stats'.cpu) -gt "90.0") { 
						$rptDevices += "* $shortsitename > $($ : CPU usage of $($device.'system-stats'.cpu)% `r`n"
						$exitcode = 1012
					if( [math]::Round($device.'system-stats'.mem) -gt "90.0") { 
						$rptDevices += "* $shortsitename > $($ : Memory usage of $($device.'system-stats'.mem)% `r`n"
						$exitcode = 1013
					if( $device.upgradable -eq $true ) {
	#					$rptDevices += "* $shortsitename > $($ : Firmware upgrade available <-- IGNORING til QA recovers`r`n"
	#					$exitcode = 1014

					#if($device.port_table.count -gt 0){	#don't need to see AP Pros' secondary ports
					if($device.type -eq 'usw'){
						$FullRpt += "  "+ ($device.port_table |ft port_idx,name,enable,up,is_uplink,port_poe,autoneg,speed,full_duplex,network_name -AutoSize |out-string).trim().replace("`n", "`n  ") +"`r`n"
					Foreach ($port in ${
						if($port.stp_state -eq "discard"){
							$rptDevices += "* $shortsitename > $($device.desc) > PORT $($ : blocked due to STP issues `r`n" 
							$exitcode = 1017


		Foreach ($device in $ |where-object {$}){	#weirdly duplicates with blanks otherwise
			$FullRpt += "* FW WAN1 '$($' - is_uplink:$($device.is_uplink), up:$($device.up), ip:$($device.ip), netmask:$($device.netmask), gateway:$($device.gateway)  `r`n"
			if($device.is_uplink -and $device.up -ne $True) { 
				$rptDevices += "* $shortsitename > WAN1 $($ : link down `r`n" 
				$exitcode = 1015
		Foreach ($device in $ |where-object {$}){#weirdly duplicates with blanks otherwise
			$FullRpt += "* FW WAN2 '$($' - is_uplink:$($device.is_uplink), up:$($device.up), ip:$($device.ip), netmask:$($device.netmask), gateway:$($device.gateway)  `r`n"
			if($device.is_uplink -and $device.up -ne $True) { 
				$rptDevices += "* $shortsitename > WAN2 $($ : link down`r`n" 
				$exitcode = 1016

		# DIRTY HACK: UDMPs lose their auth on the second call (Something ServerCertificateValidationCallback related), so just pound it back every time:
		Invoke-RestMethod -uri $LoginURI -Method POST -Body $Credential -ContentType "application/json" -SessionVariable UniFiSession | out-null

		try {
			$urlAlarms = "$($BaseURI)/api/s/$($"
			$alarms = Invoke-Restmethod -Uri $urlAlarms -Method GET -ContentType "application/json" -Headers @{"Accept"="application/json"} -WebSession $UniFiSession
			$report += "* ERROR - Alarm Query Failed: $($_.Exception.Message)"
			write-error "* ERROR - Alarm Query Failed: $($_.Exception.Message)"
		Foreach ($alarm in (${
			if(! $($alarm.handled_time)) {	# ???
				$rptAlarms += "* ALERT: $shortsitename > '$($alarm.ap_name)' : $($alarm.msg) @$([datetime]$alarm.datetime -f "yyyy-MM-dd-Hmmss") `r`n" 
				$exitcode = 1018


	$report += "$rptDevices `r`n"
	$report += "$rptAlarms `r`n"

if($exitcode -gt 0){
	write-host "FAIL - problems found:"
	write-host "OK - no problems found!"

 write-host "CHECKED DATA:"
 write-host " "($FullRpt.replace("`n", "`n  ")).trim() #format

write-host "PARAMETERS:"
foreach ( $key in ((Get-Command -Name $MyInvocation.InvocationName).Parameters).Keys ) {
	$val = ((Get-Variable $key -ea SilentlyContinue).Value) -join ", "
	Write-Host "  $($key): $val" 
write-host "CONTEXT:"
write-host "  Script Path:" (get-item $MyInvocation.InvocationName)
write-host "  Script Last Updated:" (get-item $MyInvocation.InvocationName).LastWriteTime " (try -5hrs [SW saves as UTC])"
write-host "  Execution Time: Total $($elapsed_Total)sec"

write-host "exitcode: $exitcode" 
exit $exitcode

NOTE: updates since publishing this have so far added:
* proper detection of the “pending adoption” state
* awareness of the undocumented “adopting” state
* awareness of the undocumented UBB, USP and USW-Flex-Mini models
If anyone’s dying to see the latest version, let me know in the comments. RSS feeds

Are you an ExcelMicro partner who needs to stay in the loop on what they’re doing?  

They’ve got some great services and folks, but it sounds like they’re swamped with a lot of internal changes over the last couple years.  Unfortunately, that leaves them a bit weak on partner communication…

Their ONLY official way to not get surprised by changes is to manually/constantly check their support portal web pages.  After extended nagging for them to publish ANY info on Proofpoint releases, they did finally add that a few months ago.  But still no mailing lists, no RSS feeds, no carrier pigeons — just keep clicking refresh til something shows up…

So I took matters into my own hands: Using Feed43’s fantastic service, I wrote custom regular expressions to scrape EM’s content, which I’ve published into my own RSS feeds.  If you’re looking to stay in the ExcelMicro loop, feel free to subscribe to these feeds:

I expect EM will eventually get official feeds so these aren’t needed, but til then, enjoy!

Behold! The white first fuse…

The white first fuse,
Potential Bound.
Watch the fiery light as it ignites,
Prometheus is released.

Witness white grow green
soon the fuse, the unseen
not shorter but stronger.
More imminent but longer
is the time when finally,
after the lively sparks have pushed (burned?) their way through the hard outer shell the explosion happens showering the landscape with itself,
living shrapnel,
until at last,
it is again
buried in the soil.

-Rob Eberhardt, ~1997