0

我有一个有效的 powershell 脚本,可以从我们网络中的一台机器上获取 Windows 产品密钥。该脚本在 powershell 命令行中运行良好,但当我尝试从 C# 运行它时返回错误。我需要这项工作来绘制我们公司的许可证。

电源外壳代码:

function Get-WindowsKey {
$target = '$server'
$hklm = 2147483650
$regPath = "Software\Microsoft\Windows NT\CurrentVersion\DefaultProductKey"
$regValue = "DigitalProductId4"
$productKey = $null
$win32os = $null
$wmi = [WMIClass]"\\$target\root\default:stdRegProv"
$data = $wmi.GetBinaryValue($hklm,$regPath,$regValue)
$binArray = ($data.uValue)[52..66]
$charsArray = "B","C","D","F","G","H","J","K","M","P","Q","R","T","V","W","X","Y","2","3","4","6","7","8","9"
For ($i = 24; $i -ge 0; $i--) {
    $k = 0
    For ($j = 14; $j -ge 0; $j--) {
        $k = $k * 256 -bxor $binArray[$j]
        $binArray[$j] = [math]::truncate($k / 24)
        $k = $k % 24
    }
    $productKey = $charsArray[$k] + $productKey
    If (($i % 5 -eq 0) -and ($i -ne 0)) {
        $productKey = "-" + $productKey
    }
}
$productkey
}
Get-WindowsKey | Format-Table -AutoSize

只需将 $server 替换为 . 或您的 IP

运行脚本的 C# 代码:

private void RunWindowsKeyScript(string IP)
{
    try
    {
        Assembly keyAssembly = this.GetType().Assembly;
        ResourceManager keyResMan = new ResourceManager("LanMap.Resources.PS script", keyAssembly);
        string keyScript = keyResMan.GetString("WindowsKey");
        keyScript = keyScript.Replace("$server", IP);
        Runspace keyRunspace = RunspaceFactory.CreateRunspace();
        keyRunspace.Open();
        Pipeline keyPipeline = keyRunspace.CreatePipeline();
        keyPipeline.Commands.AddScript(keyScript);
        keyPipeline.Commands.Add("Out-String");
        Collection<psobject> keyResults = keyPipeline.Invoke();
        keyRunspace.Close();
        StringBuilder keyStringBuilder = new StringBuilder();
        foreach (PSObject obj in keyResults)
        {
            keyStringBuilder.AppendLine(obj.ToString());
        }
    }
    catch (Exception ex)
    {
        string s = "";
        s += " ";
    }
}

如果可以的话请帮忙。我已经知道错误是在 C# GetBinaryValue 中返回 null。我就是不能让它工作。

4

2 回答 2

0

我不确定你是如何让这个以脚本形式工作的:

$target = '$server'

单引号字符串不会扩展其中的变量。这应该可以正常工作:

$target = "$server"

这通常就足够$target = $server了,但由于您正在执行字符串替换,因此最好使用双引号。

另一种可能性是您的 C# 代码作为 x86 运行,并且您正在读取 WOW64 注册表而不是 64 位注册表。这或许可以解释为什么您在运行脚本和通过 C# 应用程序运行之间看到不同的结果。

于 2013-01-29T17:45:07.540 回答
0

更新:理论见底部。

从 ISE 测试 PowerShell 代码:看起来GetBinaryValue失败了:

$target = 'localhost'
$hklm = 2147483650
$regPath = "Software\Microsoft\Windows NT\CurrentVersion\DefaultProductKey"
$regValue = "DigitalProductId4"
$productKey = $null
$win32os = $null
$wmi = [WMIClass]"\\$target\root\default:stdRegProv"
$data = $wmi.GetBinaryValue($hklm,$regPath,$regValue)

if ($data -eq $null) { Write-DEbug "Data is NULL"; return "STOP 2" }

write-debug '$Data'
write-debug ("$($data): " + ($data | gm | out-string))
write-debug ("$($data): " + ($data | fl * | out-string))

if ($data.uValue -eq $null) { Write-Debug "Data.uValue is NULL"; return "STOP 3" }
# rest cut for testing

结果是:

调试:$数据
调试:System.Management.ManagementBaseObject:

   类型名称:System.Management.ManagementBaseObject#\__PARAMETERS

名称 MemberType 定义                      
---- ---------- ----------                      
PSComputerName AliasProperty PSComputerName = __SERVER       
ReturnValue 属性 uint32 ReturnValue {get;set;}   
uValue 属性 byte[] uValue {get;set;}        
__CLASS 属性字符串 __CLASS {get;set;}       
__DERIVATION 属性字符串[] __DERIVATION {get;set;}
__DYNASTY 属性字符串 __DYNASTY {get;set;}     
__GENUS 属性 int __GENUS {get;set;}          
__NAMESPACE 属性字符串 __NAMESPACE {get;set;}   
__PATH 属性字符串 __PATH {get;set;}        
__PROPERTY_COUNT 属性 int __PROPERTY_COUNT {get;set;}
__RELPATH 属性字符串 __RELPATH {get;set;}     
__SERVER 属性字符串 __SERVER {get;set;}      
__SUPERCLASS 属性字符串 __SUPERCLASS {get;set;}  



调试:System.Management.ManagementBaseObject:

PS计算机名称:
__属:2
__CLASS : __PARAMETERS
__超类:
__DYNASTY : __参数
__RELPATH :
__PROPERTY_COUNT : 2
__派生:{}
__服务器 :
__命名空间:
__小路 :
返回值:2
u值:
属性:{ReturnValue,uValue}
系统属性:{__GENUS、__CLASS、__SUPERCLASS、__DYNASTY...}
限定符:{}
类路径:__PARAMETERS
地点 :
容器 :




调试:Data.uValue 为 NULL
停止 3

ReturnValue: 2对应于 ERROR_FILE_NOT_FOUND(假设该ReturnValue成员反映了返回值,GetBinaryValue其中 0 表示成功,否则返回标准 Windows API 错误)。

更新:

在 ISE 实例下甚至可以得到这个:

PS [32] C:\ #50> gp "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey"
gp:找不到路径“HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey”,因为它不存在。
在行:1 字符:1
+ gp "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (HKLM:\SOFTWARE\...faultProductKey:String) [Get-ItemProperty], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyCommand
 

但我可以看到关键......但是 ISE 的 64 位实例并且它可以工作。

密钥仅(直接)可用于 64 位进程,最近 Visual Studio 版本中的默认设置是大多数应用程序构建为 32 位(大多数应用程序不需要额外的地址空间),32 位 .NET 应用程序将加载 32 位PowerShell 运行时程序集。

您是否尝试过为 64 位构建应用程序?

PS。这个问题可能会有所帮助:Reading 64bit Registry from a 32bit application

于 2013-01-30T09:43:01.447 回答