2009-09-25 72 views
1

我想從PowerShell腳本直接調用一些Win32 API。我設法與下面的代碼WNetAddConnection工作:從PowerShell調用WNetAddConnection2

$cp = New-Object Microsoft.CSharp.CSharpCodeProvider 
$cpar = New-Object System.CodeDom.Compiler.CompilerParameters 

$Code = @" 
using System; 
using System.Runtime.InteropServices; 
namespace Win32Api 
{ 
    public class Net 
    { 
     [DllImport("mpr.dll", EntryPoint = "WNetAddConnection")] 
     public static extern uint Map(string lpRemoteName, string lpPassword, string lpLocalName); 
     [DllImport("mpr.dll", EntryPoint = "WNetCancelConnection")] 
     public static extern uint Delete(string lpName, byte fForce);  
    } 
} 
"@ 

$cp.CompileAssemblyFromSource($cpar, $code) 
[Win32Api.Net]::Map("\\REMKOLAPTOP\C$", $null, "W:") 

現在我想這樣做WNetAddConnection2,雖然我找到了正確的declarations for C#我不確定如何聲明本作在PowerShell中使用。所以我的問題是:什麼是正確的「翻譯」,調用API的例子會很棒。

請注意,我不想使用非API方法像下面這樣:

$net = $(New-Object -Com WScript.Network) 
$net.MapNetworkDrive("u:", "\\computer\share") 

回答

4

我能得到下面的代碼在PowerShell 2.0中工作。請注意,我也使用一個PSCX(http://pscx.codeplex.com)函數將Windows錯誤代碼轉換爲消息。我還設置了用於輸入用戶名和密碼的交互提示的選項。包括註釋過的腳本顯示瞭如何使用PowerShell的Get-Credential cmdlet執行相同操作。

順便說一句,如果你通過變量向函數提供用戶名/密碼,一定要得到正確的命令,它是密碼後跟用戶名。這讓我咬了10分鐘,直到我終於明白我的訂單是錯的。衛生署!另一個珍聞,對於這樣的互操作幫助,一定要結帳http://www.pinvoke.net。無論如何,希望這有助於。

$WNetAddConnection2WrapperSource = @' 
using System; 
using System.Runtime.InteropServices; 

namespace Win32Api { 
    public enum ResourceScope { 
     RESOURCE_CONNECTED = 1, 
     RESOURCE_GLOBALNET, 
     RESOURCE_REMEMBERED, 
     RESOURCE_RECENT, 
     RESOURCE_CONTEXT 
    }; 

    public enum ResourceType { 
     RESOURCETYPE_ANY, 
     RESOURCETYPE_DISK, 
     RESOURCETYPE_PRINT, 
     RESOURCETYPE_RESERVED = 8 
    }; 

    [Flags] 
    public enum ResourceUsage { 
     RESOURCEUSAGE_CONNECTABLE = 0x00000001, 
     RESOURCEUSAGE_CONTAINER = 0x00000002, 
     RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004, 
     RESOURCEUSAGE_SIBLING = 0x00000008, 
     RESOURCEUSAGE_ATTACHED = 0x00000010, 
     RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | 
          RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED), 
    }; 

    public enum ResourceDisplayType { 
     RESOURCEDISPLAYTYPE_GENERIC, 
     RESOURCEDISPLAYTYPE_DOMAIN, 
     RESOURCEDISPLAYTYPE_SERVER, 
     RESOURCEDISPLAYTYPE_SHARE, 
     RESOURCEDISPLAYTYPE_FILE, 
     RESOURCEDISPLAYTYPE_GROUP, 
     RESOURCEDISPLAYTYPE_NETWORK, 
     RESOURCEDISPLAYTYPE_ROOT, 
     RESOURCEDISPLAYTYPE_SHAREADMIN, 
     RESOURCEDISPLAYTYPE_DIRECTORY, 
     RESOURCEDISPLAYTYPE_TREE, 
     RESOURCEDISPLAYTYPE_NDSCONTAINER 
    }; 

    [StructLayout(LayoutKind.Sequential)] 
    public class NetResource { 
     public ResourceScope Scope; 
     public ResourceType Type; 
     public ResourceDisplayType DisplayType; 
     public ResourceUsage Usage; 
     public string LocalName; 
     public string RemoteName; 
     public string Comment; 
     public string Provider; 
    }; 

    [Flags] 
    public enum AddConnectionOptions { 
     CONNECT_UPDATE_PROFILE = 0x00000001, 
     CONNECT_UPDATE_RECENT = 0x00000002, 
     CONNECT_TEMPORARY  = 0x00000004, 
     CONNECT_INTERACTIVE = 0x00000008, 
     CONNECT_PROMPT   = 0x00000010, 
     CONNECT_NEED_DRIVE  = 0x00000020, 
     CONNECT_REFCOUNT  = 0x00000040, 
     CONNECT_REDIRECT  = 0x00000080, 
     CONNECT_LOCALDRIVE  = 0x00000100, 
     CONNECT_CURRENT_MEDIA = 0x00000200, 
     CONNECT_DEFERRED  = 0x00000400, 
     CONNECT_RESERVED  = unchecked((int)0xFF000000), 
     CONNECT_COMMANDLINE = 0x00000800, 
     CONNECT_CMD_SAVECRED = 0x00001000, 
     CONNECT_CRED_RESET  = 0x00002000 
    } 

    public static class NativeMethods { 
     [DllImport("mpr.dll", EntryPoint="WNetAddConnection2")]  
     public static extern int WNetAddConnection2(
      NetResource netResource, string password, 
      string username, AddConnectionOptions options); 
    } 
} 
'@ 

Add-Type -TypeDefinition $WNetAddConnection2WrapperSource 

$netResource = new-object Win32Api.NetResource 
$netResource.Type = [Win32Api.ResourceType]::RESOURCETYPE_DISK 
$netResource.LocalName = 'P:' 
$netResource.RemoteName = '\\AnotherPC\C' 

# Get username and password 
#$cred = Get-Credential 
#$username = $cred.UserName 
#$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($cred.Password) 
#$password = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) 
#[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) 

$opts = [Win32Api.AddConnectionOptions]::CONNECT_INTERACTIVE -bor 
     [Win32Api.AddConnectionOptions]::CONNECT_PROMPT -bor 
     [Win32Api.AddConnectionOptions]::CONNECT_UPDATE_PROFILE 

$res = [Win32Api.NativeMethods]::WNetAddConnection2($netResource, 0, 0, $opts) 
if ($res -ne 0) { 
    # This function comes with PSCX http://pscx.codeplex.com 
    Get-ExceptionForWin32 $res 
    throw "Failed to connect" 
} 
# Display results 
net use 
+0

我在PS1.0中沒有收到任何錯誤,但它還沒有工作。腳本似乎無限期地等待。與我的代碼相比,我錯過了CompileAssemblyFromSource($ cpar,$ code),所以我會嘗試去適應它,看看它是否有效。現在將您的解決方案標記爲有用。 – Remko 2009-09-27 07:39:21

+0

此代碼在PS2.0中有效,請注意: $ res = [Win32Api.NativeMethods] :: WNetAddConnection2($ netResource,$ null,$ null,$ opts)不起作用 這裏工作的地方: $ res = [Win32Api.NativeMethods] :: WNetAddConnection2($ netResource,0,0,$ opts) – Remko 2009-09-27 11:43:18

+0

我很高興爲雅工作。在愚蠢的簽名上花了我一點時間。我只是*屁股* umed它是用戶名後跟密碼。 – 2009-09-27 16:25:45