LoginSignup
7
6

More than 3 years have passed since last update.

Windows10でBASIC認証画面にIDとパスワードを自動入力するソフトを作った

Last updated at Posted at 2019-10-10

この記事の内容は、ライブラリやソフトのダウンロードなしで使えます。

やれること

下のようなWindowがでているときに本記事のプログラムを実行すると、指定のIDとパスワードを自動で入力します。

image.png

C#のコンパイル

このあたりが参考になるかと。
https://qiita.com/yuki451/items/c9c6a2b79ce96ae0d252

今回のソースに関しては、下記のようにアセンブリのパスを指定する(環境に依存するかも)。


csc /r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\UIAutomationClient\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationClient.dll ^
/r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll ^
/r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll ^
Test.cs

ソースコード

Test.cs

using System;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using System.Windows.Automation;


public static class NativeMethods
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow);

    public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public extern static bool EnumWindows(EnumWindowsDelegate lpEnumFunc,   IntPtr lparam);
}

public class Class1
{
    static AutomationElement FindCredentialWindow()
    {
        IntPtr hWnd = NativeMethods.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "Credential Dialog Xaml Host", "Windows セキュリティ");

        if ( hWnd == IntPtr.Zero ) {
            return null;
        }

        return AutomationElement.FromHandle(hWnd);
    }

    static string FindTextBlockMatches(AutomationElement aeForm, Regex r)
    {
        var elems = FindElementsByClassName(aeForm, "TextBlock");
        foreach ( AutomationElement elem in elems ) {
            var elemInfo = elem.Current;
            if ( r.IsMatch(elemInfo.Name) ) {
                return elemInfo.Name;
            }
        }
        return null;
    }

    static void InputToCredentialWindow(AutomationElement aeForm, string userId, string password)
    {
        AutomationElement aeUserId   = FindElementById(aeForm, "EditField_0");
        AutomationElement aePassword = FindElementById(aeForm, "PasswordField_1");
        AutomationElement aeOkButton = FindElementById(aeForm, "OkButton");

        if ( aeUserId != null && aePassword != null && aeOkButton != null ) {
            var vpUserId   = (ValuePattern)aeUserId.GetCurrentPattern(ValuePattern.Pattern);
            var vpPassword = (ValuePattern)aePassword.GetCurrentPattern(ValuePattern.Pattern);
            vpUserId.SetValue(userId);
            vpPassword.SetValue(password);

//  OKも自動で押す場合はこれ
//            var ipOkButton = (InvokePattern)aeOkButton.GetCurrentPattern(InvokePattern.Pattern);
//            ipOkButton.Invoke();
        }
    }

    static AutomationElement FindElementById(AutomationElement rootElement, string automationId)
    {
        var cond = new PropertyCondition(AutomationElement.AutomationIdProperty, automationId);
        return rootElement.FindFirst(TreeScope.Descendants, cond);
    }

    static AutomationElementCollection FindElementsByClassName(AutomationElement rootElement, string className)
    {
        var cond = new PropertyCondition(AutomationElement.ClassNameProperty, className);
        return rootElement.FindAll(TreeScope.Descendants, cond);
    }

    [STAThread]
    static void Main()
    {
        AutomationElement aeForm = FindCredentialWindow();
        if ( aeForm != null ) {

            // 対象サイト(?)のメッセージに応じて適宜変更. 改行とか合わせるのが面倒なので正規表現で探すようにした
            string text = FindTextBlockMatches(aeForm, new Regex("^サーバー(.*)が"));

            if ( text != null ) {
                Console.WriteLine(text);

                // 下記は ID, PASSWORD に応じて適宜変更。機密管理に注意すること。
                //  やらかし例:ソースにパスワード埋め込んだままGitHubなどでうっかり公開したりとか
                InputToCredentialWindow(aeForm, "userid", "password");
            }
            else {
                Console.WriteLine("Not found Credential window with the description.");
            }
        }
        else {
            Console.WriteLine("Not found Credential window.");
        }
    }
}

事前調査

BASIC認証の画面の構成要素を下記のツールで調べた。
https://qiita.com/kob58im/items/3587d8e595e655e9391d

参考サイト

その後

EditField_0PasswordField_1の数字が違う認証画面が出るケースに遭遇した。
Windows仕様が分からん…

さらにその後 - Edge対応

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6