0

ネットワーク内のマシンから Windows プロダクト キーを取得するための PowerShell スクリプトが動作しています。このスクリプトは、powershell コマンド ラインでは適切に実行されますが、C# から実行しようとするとエラーが返されます。私たちの会社でライセンスをチャート化するためにこれが必要です。

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

$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 として実行されていて、64 ビット レジストリではなく WOW64 レジストリを読み取っている可能性があります。これが、スクリプトの実行と 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

結果:

デバッグ: $Data
デバッグ: System.Management.ManagementBaseObject:

   TypeName: 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:

PSComputerName :
__属: 2
__CLASS : __PARAMETERS
__スーパークラス :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 2
__派生: {}
__サーバー:
__名前空間:
__道 :
戻り値: 2
uValue :
プロパティ: {戻り値、uValue}
システムプロパティ: {__GENUS、__CLASS、__SUPERCLASS、__DYNASTY...}
修飾子: {}
ClassPath : __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。この質問が役立つかもしれません: 32 ビット アプリケーションから 64 ビット レジストリを読み取る

于 2013-01-30T09:43:01.447 に答える