简体   繁体   English

脚本在Powershell中运行,但在C#中运行时出错

[英]Script running in Powershell but error when run in C#

I have a working powershell script to get the Windows product key from an machine in our network. 我有一个有效的Powershell脚本,可以从我们网络中的计算机上获取Windows产品密钥。 The script runs well in powershell comand line but returns error when I try to run it from C#. 该脚本在powershell comand行中运行良好,但是当我尝试从C#运行该脚本时返回错误。 I need this working to chart licenses in our corporation. 我需要这项工作来绘制我们公司的许可证表。

Powershell code: Powershell代码:

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

Just replace $server with . 只需将$ server替换为即可。 or your IP 或您的IP

C# code that runs script: 运行脚本的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 += " ";
    }
}

Please help if you can. 如果可以的话请帮忙。 I already know the error is that in C# GetBinaryValue returns null. 我已经知道错误是在C#中,GetBinaryValue返回null。 I just can not make it work. 我只是无法使其工作。

I'm not sure how you got this to work in script form with this: 我不确定您是如何通过以下方式以脚本形式工作的:

$target = '$server'

Single quoted strings will not expand variables inside them. 用单引号引起来的字符串不会在其中扩展变量。 This should work just fine: 这应该可以正常工作:

$target = "$server"

This would normally be sufficient $target = $server but since you're doing a string replace, it is best to stick with the double quotes. 通常$target = $server就足够$target = $server但是由于您正在执行字符串替换,因此最好坚持使用双引号。

Another possibility is that you're C# code is running as x86 and you're reading the WOW64 registry instead of the 64-bit registry. 另一种可能性是您正在将C#代码作为x86运行,并且正在读取WOW64注册表而不是64位注册表。 That might explain why you see different results between running the script and running via your C# app. 这也许可以解释为什么您在运行脚本和通过C#应用程序运行之间看到不同的结果。

Update: See bottom for theory. 更新:理论请参见底部。

Testing the PowerShell code from ISE: looks like GetBinaryValue is failing: 从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

results in: 结果是:

DEBUG: $Data
DEBUG: System.Management.ManagementBaseObject: 

   TypeName: System.Management.ManagementBaseObject#\__PARAMETERS

Name             MemberType    Definition                      
----             ----------    ----------                      
PSComputerName   AliasProperty PSComputerName = __SERVER       
ReturnValue      Property      uint32 ReturnValue {get;set;}   
uValue           Property      byte[] uValue {get;set;}        
__CLASS          Property      string __CLASS {get;set;}       
__DERIVATION     Property      string[] __DERIVATION {get;set;}
__DYNASTY        Property      string __DYNASTY {get;set;}     
__GENUS          Property      int __GENUS {get;set;}          
__NAMESPACE      Property      string __NAMESPACE {get;set;}   
__PATH           Property      string __PATH {get;set;}        
__PROPERTY_COUNT Property      int __PROPERTY_COUNT {get;set;} 
__RELPATH        Property      string __RELPATH {get;set;}     
__SERVER         Property      string __SERVER {get;set;}      
__SUPERCLASS     Property      string __SUPERCLASS {get;set;}  



DEBUG: System.Management.ManagementBaseObject: 

PSComputerName   : 
__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     : 
__DYNASTY        : __PARAMETERS
__RELPATH        : 
__PROPERTY_COUNT : 2
__DERIVATION     : {}
__SERVER         : 
__NAMESPACE      : 
__PATH           : 
ReturnValue      : 2
uValue           : 
Properties       : {ReturnValue, uValue}
SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}
Qualifiers       : {}
ClassPath        : __PARAMETERS
Site             : 
Container        : 




DEBUG: Data.uValue is NULL
STOP 3

That ReturnValue: 2 corresponds to ERROR_FILE_NOT_FOUND (assuming the ReturnValue member is reflecting the return value of GetBinaryValue where 0 is success, otherwise standard Windows API error returns). ReturnValue: 2对应于ERROR_FILE_NOT_FOUND(假定ReturnValue成员反映了GetBinaryValue的返回值,其中0为成功,否则返回标准Windows API错误)。

Update: 更新:

Under by ISE instance even get this: 在ISE实例下甚至可以获得以下信息:

PS [32] C:\ #50> gp "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey"
gp : Cannot find path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey' because it does not exist.
At line:1 char:1
+ gp "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DefaultProductKey"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (HKLM:\SOFTWARE\...faultProductKey:String) [Get-ItemProperty], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyCommand

But I can see the key... however a 64 bit instance of ISE and it works. 但是我可以看到密钥……但是ISE的64位实例可以正常工作。

The key is only available (directly) to 64bit processes, the default in recent Visual Studio versions is for most applications to be built as 32bit (most applications don't need the extra address space), a 32bit .NET application will load the 32bit PowerShell runtime assemblies. 该密钥仅(直接)适用于64位进程,最新的Visual Studio版本中的默认设置是,对于大多数应用程序,其构建为32位(大多数应用程序不需要额外的地址空间),一个32位.NET应用程序将加载32位PowerShell运行时程序集。

Have you tried building your application for 64bit? 您是否尝试过为64位构建应用程序?

PS. PS。 This question might help: Reading 64bit Registry from a 32bit application 该问题可能会有所帮助: 从32位应用程序读取64位注册表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM