2009-09-25 84 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