如何转换 WMI 返回的日期值

use*_*912 5 powershell wmi datetime

我运行此 PowerShell 脚本来查询绑定到 SQL Server 的证书:

\n
Get-WmiObject -Namespace 'ROOT\\Microsoft\\SqlServer\\ComputerManagement14' -Class SecurityCertificate | select name,expirationdate\n
Run Code Online (Sandbox Code Playgroud)\n

它正确返回证书的主题和到期日期,如下所示:

\n
name                        expirationdate\n----                        --------------\nservername.domain.com       31052014\n
Run Code Online (Sandbox Code Playgroud)\n

但是,我不知道该日期的格式是什么,因为证书显示过期为 \xe2\x80\x8eThursday, \xe2\x80\x8eAugust \xe2\x80\x8e17, \xe2\x80\x8e2023 2:34:27 AM

\n

我用谷歌搜索,但没有找到有关返回的适当类型的日期以及如何转换为[日期时间]的结果。我怎样才能理解这一点,以便我可以将其转换并用于比较?

\n

Dai*_*Dai 1

31052014表示日期+时间2023-08-15T19:08:23

TL;DR:运行此交互式 JS 片段以将 WMISecurityCertificate uint32值转换为人类可读的日期时间:

  1. 单击下面的“显示代码片段”。
  2. 向下滚动到蓝色的大“运行代码片段”按钮并单击它。
  3. 31052014然后在出现的输入框中输入数字(例如),然后单击按钮进行转换。

function convertSqlServerCertificateExpirationToDateTime( value ) {

     //debugger;

      if( typeof value !== 'number' || value < 0 ) throw new Error( "Invalid `value` argument. Should be an integer number somewhere around ~30000000." );

     const epoch = new Date( /*y:*/ 1601, /*m:*/ 0, /*d:*/ 1, /*h:*/ 0, /*m:*/ 0, /*s:*/ 0, /*ms:*/ 0 ); // JS uses 0 for January instead of 1.

     const unitsPerDay   = 0.004970966;
     const days          = value * unitsPerDay;
     const secondsPerDay = 86400;
     const addSeconds    = days * secondsPerDay;

//   const secondsSinceEpoch = value * 430;

     const t = new Date( epoch.getTime() );
     t.setSeconds( t.getSeconds() + addSeconds );
     
     console.log( "Value %o corresponds to %o", value, t );
     
     return t;
 }
 
 function doConvert() {
 
     const inputValue = document.getElementById('wmiDateTime').valueAsNumber;
     
     console.log( 'inputValue: %o', inputValue );
     
     const dt = convertSqlServerCertificateExpirationToDateTime( inputValue );
     
     document.getElementById('output1').textContent = dt.toLocaleString();
     document.getElementById('output2').textContent = dt.toISOString();
 }
Run Code Online (Sandbox Code Playgroud)
output {
    font-weight: bold;
    color: purple;
    display: block;
    margin: 1em 0; }

label { display: block; }
Run Code Online (Sandbox Code Playgroud)
<fieldset>
    <legend>WMI uint32 datetime converter</legend>
    
    <label>
        <span>Integer value:</span>
        <input type="number" min="0" id="wmiDateTime" />
    </label>
    
    <div>
        <button type="button" onclick="doConvert()">Convert</button>
    </div>
    
    <output id="output1"></output>
    <output id="output2"></output>

</fieldset>
Run Code Online (Sandbox Code Playgroud)


背景故事

这引起了我的兴趣,所以我创建了一个新的自签名证书,并克服重重困难使其与 SQL Server 2022 一起工作......

  • SQL Server 2022 的 SQL Server 配置管理器现在显示到期日期(但不显示时间,而且它是本地时间而不是 UTC,gah)。

  • 但是,使用 WMI CIM 浏览器工具(例如wmiexplorer)会显示uint32您所描述的值:

    • 在此输入图像描述
    • 在此输入图像描述
  • 我生成的证书具有以下字段(如Certificates.msc和中所示certutil

    • NotBefore
      • 2022-10-07 18:59:44
      • 30988985
    • NotAfter
      • 2023-04-07 19:09:44
      • 31025599
  • 这两个整数值之间的差是36614

  • 这两个日期之间相差 182 天 0 小时 10 分钟。

    • 182d + 0h + (10/1440)m182.00694天。
  • 36614 / 182.00694 == 201.168,因此 1 天(即 24 小时)==201.168 神秘单位

  • 现在让我们找到纪元:

    • 30988985 / 201.168 == 154,045.3
    • 30988985是纪元之后的 154,045 天。
    • 因此309889852022-10-07 18:59:44纪元就是日期+时间减去 154,045.3 天。
      • 大约在1601-01-02 11:47:44左右。
      • heeeeyyy这个日期看起来有点熟悉... 1601-01-01 00:00 是 Win32 时钟纪元!- 因此,让我们将额外的一天归因于舍入误差。
    • 还,182.00694 / 36614 == 0.00497
      • 即每个增量整数值expirationdate对应于0.00497天或430 秒(大约)。
  • 因此转换函数(在 JavaScript 中)是:

    function convertSqlServerCertificateExpirationToDateTime( value ) {
         if( typeof value !== 'number' || value < 0 ) throw new Error( "Invalid `value` argument. Should be an integer number somewhere around ~30000000." );
    
         const epoch = new Date( /*y:*/ 1601, /*m:*/ 0, /*d:*/ 1, /*h:*/ 0, /*m:*/ 0, /*s:*/ 0, /*ms:*/ 0 ); // JS uses 0 for January instead of 1.
    
         const unitsPerDay   = 0.004970966;
         const days          = value * unitsPerDay;
         const secondsPerDay = 86400;
         const addSeconds    = days * secondsPerDay;
    
         const t = new Date( epoch.getTime() );
         t.setSeconds( t.getSeconds() + addSeconds );
         return t;
    }
    
    Run Code Online (Sandbox Code Playgroud)

疼痛....

TL;DR:在运行 SQL Server 2022 的机器上本地提升的 PowerShell 中运行此命令:

PS C:\Users\Administrator> $selfSignedRootCA = New-SelfSignedCertificate -DnsName sql2022.corp.example.com -notafter (Get-Date).AddMonths(6) -CertStoreLocation Cert:\LocalMachine\My\ -KeyExportPolicy Exportable -KeyUsage CertSign,CRLSign,DigitalSignature -KeySpec KeyExchange -KeyLength 2048 -KeyUsageProperty All -KeyAlgorithm 'RSA' -HashAlgorithm 'SHA256' -Provider 'Microsoft Enhanced RSA and AES Cryptographic Provider'
Run Code Online (Sandbox Code Playgroud)
  • 选择-KeySpec KeyExchange非常重要
  • 使用-DnsNamenot -Subject,并使用 FQDN 名称。