c# - 从 PowerShell 调用 WNetAddConnection2

标签 c# winapi powershell wnet

我正在尝试从 PowerShell 脚本直接调用一些 Win32 API。我设法使 WNetAddConnection 使用下面的代码:

$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")

最佳答案

我能够在 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

关于c# - 从 PowerShell 调用 WNetAddConnection2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1477328/

相关文章:

c# - 在 C# 中将字符串拆分为两个字符

c# - 无法让 XmlDocument.SelectNodes 检索我的任何节点?

c# - 调用 C++ 函数时尝试读取/写入 protected 内存错误

winapi - 创建后更改窗口的类?

powershell - PSObject、Hashtable 和 PSCustomObject 之间的区别

powershell - 如何在没有附带堆栈跟踪的情况下在 PowerShell 中显示 'naked' 错误消息?

c# - 是否可以在不编译的情况下调用 C# 词法/语法分析器?

winapi - 如何使用DirectWrite在面向脚本的OpenType功能与其他OpenType功能之间取得平衡?

Python自动化Outlook电子邮件: change sender or default reply-to address

powershell - 如何为我的租户授予我的应用程序对 AAD Graph API 的完全访问权限?