@@ -380,47 +380,87 @@ pub fn detect_system_brand() -> String {
380380
381381// --- Model name detection --------------------------------------------------
382382
383+ #[ cfg( windows) ]
384+ #[ derive( Deserialize , Debug , Default ) ]
385+ struct ModelNameInfo {
386+ #[ serde( rename = "cspVersion" ) ]
387+ csp_version : Option < String > ,
388+ #[ serde( rename = "cspName" ) ]
389+ csp_name : Option < String > ,
390+ #[ serde( rename = "csModel" ) ]
391+ cs_model : Option < String > ,
392+ }
393+
383394fn normalize_model_name ( raw : & str ) -> Option < String > {
384395 let trimmed = raw. trim ( ) ;
385396 if trimmed. is_empty ( ) {
386397 return None ;
387398 }
388- let invalid = [ "to be filled by o.e.m." , "system product name" , "default string" , "unknown" ] ;
399+ let invalid = [ "to be filled by o.e.m." , "system product name" , "system version" , " default string", "unknown" , "none" , "n/a" , "not applicable "] ;
389400 let lower = trimmed. to_ascii_lowercase ( ) ;
390401 if invalid. iter ( ) . any ( |x| lower == * x) {
391402 return None ;
392403 }
393404 Some ( trimmed. to_string ( ) )
394405}
395406
407+ /// Returns true if the given model name is a known BIOS placeholder that
408+ /// should be replaced by auto-detection on the next startup.
409+ pub ( crate ) fn is_placeholder_model_name ( name : & str ) -> bool {
410+ normalize_model_name ( name) . is_none ( )
411+ }
412+
396413/// Detects the system model name from WMI `Win32_ComputerSystemProduct`.
414+ /// Falls back to PowerShell `Get-CimInstance` if WMI is unavailable.
397415pub fn detect_model_name ( ) -> Option < String > {
398416 #[ cfg( windows) ]
399417 {
400- let com = wmi:: COMLibrary :: new ( ) . ok ( ) ?;
401- let conn = wmi:: WMIConnection :: new ( com. into ( ) ) . ok ( ) ?;
402-
403- let products: Vec < ComputerSystemProduct > = conn. query ( ) . ok ( ) . unwrap_or_default ( ) ;
404- if let Some ( v) = products
405- . iter ( )
406- . filter_map ( |p| p. version . as_deref ( ) . and_then ( normalize_model_name) )
407- . next ( )
408- {
409- return Some ( v) ;
410- }
411- if let Some ( v) = products
412- . iter ( )
413- . filter_map ( |p| p. name . as_deref ( ) . and_then ( normalize_model_name) )
414- . next ( )
415- {
416- return Some ( v) ;
418+ if let Ok ( com) = wmi:: COMLibrary :: new ( ) {
419+ if let Ok ( conn) = wmi:: WMIConnection :: new ( com. into ( ) ) {
420+ let products: Vec < ComputerSystemProduct > = conn. query ( ) . ok ( ) . unwrap_or_default ( ) ;
421+ if let Some ( v) = products
422+ . iter ( )
423+ . filter_map ( |p| p. version . as_deref ( ) . and_then ( normalize_model_name) )
424+ . next ( )
425+ {
426+ return Some ( v) ;
427+ }
428+ if let Some ( v) = products
429+ . iter ( )
430+ . filter_map ( |p| p. name . as_deref ( ) . and_then ( normalize_model_name) )
431+ . next ( )
432+ {
433+ return Some ( v) ;
434+ }
435+ let systems: Vec < ComputerSystem > = conn. query ( ) . ok ( ) . unwrap_or_default ( ) ;
436+ if let Some ( v) = systems
437+ . iter ( )
438+ . filter_map ( |s| s. model . as_deref ( ) . and_then ( normalize_model_name) )
439+ . next ( )
440+ {
441+ return Some ( v) ;
442+ }
443+ }
417444 }
418445
419- let systems: Vec < ComputerSystem > = conn. query ( ) . ok ( ) . unwrap_or_default ( ) ;
420- systems
421- . iter ( )
422- . filter_map ( |s| s. model . as_deref ( ) . and_then ( normalize_model_name) )
423- . next ( )
446+ // Fallback: query via PowerShell CIM if WMI is unavailable.
447+ let output = run_hidden_command (
448+ "powershell" ,
449+ & [
450+ "-NoProfile" ,
451+ "-Command" ,
452+ "$csp=Get-CimInstance Win32_ComputerSystemProduct;$cs=Get-CimInstance Win32_ComputerSystem;[pscustomobject]@{cspVersion=$csp.Version;cspName=$csp.Name;csModel=$cs.Model}|ConvertTo-Json -Compress" ,
453+ ] ,
454+ )
455+ . ok ( ) ?;
456+ if !output. status . success ( ) {
457+ return None ;
458+ }
459+ let raw = String :: from_utf8_lossy ( & output. stdout ) . trim ( ) . to_string ( ) ;
460+ let info = serde_json:: from_str :: < ModelNameInfo > ( & raw ) . ok ( ) ?;
461+ if let Some ( v) = info. csp_version . as_deref ( ) . and_then ( normalize_model_name) { return Some ( v) ; }
462+ if let Some ( v) = info. csp_name . as_deref ( ) . and_then ( normalize_model_name) { return Some ( v) ; }
463+ info. cs_model . as_deref ( ) . and_then ( normalize_model_name)
424464 }
425465
426466 #[ cfg( not( windows) ) ]
0 commit comments