using System; using System.Runtime.InteropServices; using System.Security.Principal; using System.Text; class NativeMethods { public const int LOGON32_LOGON_INTERACTIVE = 2; public const int LOGON32_LOGON_NETWORK = 3; public const int LOGON32_LOGON_BATCH = 4; public const int LOGON32_LOGON_SERVICE = 5; public const int LOGON32_LOGON_UNLOCK = 7; public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8; public const int LOGON32_LOGON_NEW_CREDENTIALS = 9; public enum SID_NAME_USE { SidTypeUser = 1, SidTypeGroup, SidTypeDomain, SidTypeAlias, SidTypeWellKnownGroup, SidTypeDeletedAccount, SidTypeInvalid, SidTypeUnknown, SidTypeComputer, } public struct LOCALGROUP_MEMBERS_INFO_0 { public IntPtr PSID; } [DllImport("kernel32.dll")] public extern static bool CloseHandle(IntPtr hToken); [DllImport("advapi32.DLL", SetLastError = true)] public static extern int LogonUser( string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool LookupAccountName( string lpSystemName, string lpAccountName, [MarshalAs(UnmanagedType.LPArray)] byte[] Sid, ref uint cbSid, StringBuilder ReferencedDomainName, ref uint cchReferencedDomainName, out SID_NAME_USE peUse); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool LookupAccountSid( string lpSystemName, [MarshalAs(UnmanagedType.LPArray)] byte[] lpSid, StringBuilder lpName, ref uint cchName, StringBuilder lpReferencedDomainName, ref uint cchReferencedDomainName, out SID_NAME_USE peUse); [DllImport("netapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int NetLocalGroupAddMembers( string servername, string groupname, uint level, ref LOCALGROUP_MEMBERS_INFO_0 buf, uint totalentries); } public class AddAdminUserHelper { public static void AddAdminUser(string domain, string username, string password) { // Get built in administrators account name StringBuilder adminGroupName = new StringBuilder(); uint adminGroupNameCapacity = (uint)adminGroupName.Capacity; StringBuilder referencedDomainName = new StringBuilder(); uint referencedDomainNameCapacity = (uint)referencedDomainName.Capacity; NativeMethods.SID_NAME_USE eUse; byte[] adminGroupSid = new byte[] { 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2 }; if (!NativeMethods.LookupAccountSid( null, adminGroupSid, adminGroupName, ref adminGroupNameCapacity, referencedDomainName, ref referencedDomainNameCapacity, out eUse)) { Console.WriteLine("LookupAccountSid failed with error " + Marshal.GetLastWin32Error()); return; } // Get a security token needed to be able to afterwards query for the user's SID IntPtr token = IntPtr.Zero; if (NativeMethods.LogonUser( username, domain, password, NativeMethods.LOGON32_LOGON_NEW_CREDENTIALS, 0, out token) == 0) { Console.WriteLine("LogonUser failed with error " + Marshal.GetLastWin32Error()); return; } // Get user's SID byte[] userSid = new byte[1024]; uint userSidLength = (uint)userSid.Length; referencedDomainName = new StringBuilder(); referencedDomainNameCapacity = (uint)referencedDomainName.Capacity; NativeMethods.SID_NAME_USE peUse; using (WindowsImpersonationContext context = WindowsIdentity.Impersonate(token)) { if (!NativeMethods.LookupAccountName( domain, username, userSid, ref userSidLength, referencedDomainName, ref referencedDomainNameCapacity, out peUse)) { Console.WriteLine("LookupAccountName failed with error " + Marshal.GetLastWin32Error()); return; } } NativeMethods.CloseHandle(token); // Add user's SID to local admins group IntPtr userSidNative = Marshal.AllocHGlobal(userSid.Length); Marshal.Copy(userSid, 0, userSidNative, (int)userSid.Length); NativeMethods.LOCALGROUP_MEMBERS_INFO_0 info0; info0.PSID = userSidNative; int r = NativeMethods.NetLocalGroupAddMembers( null, adminGroupName.ToString(), 0, ref info0, 1); Marshal.FreeHGlobal(userSidNative); if (r != 0) { Console.WriteLine("NetLocalGroupAddMembers failed by returning " + r); return; } } }
Tuesday, July 24, 2012
Adding domain user as local admin immediatly after domain join
Here's a way to add a domain user as a local admin immediatly after joining the domain, without rebooting first:
Thursday, July 12, 2012
Join a domain and rename in one reboot using WMI
If you don't take special care in your script, then renaming a machine and then joining it to a Windows domain will join it using the old name. Apparently there's an undocumented flag 0x400 on JoinDomainOrWorkGroup. At least I think it started working when I added that flag... Here's a PowerShell snippet that's working for me now:
$computer = Get-WmiObject Win32_ComputerSystem $cred = Get-Credential $computer.Rename("newmachinename", $NULL, $NULL) $computer.JoinDomainOrWorkGroup( ` "mydomain", ` ($cred.GetNetworkCredential()).Password, ` $cred.UserName, ` $NULL, ` 0x1 + 0x2 + 0x20 + 0x400)
Sunday, July 08, 2012
Windows Shares vs. FTP vs. FTPS vs. SFTP
Conducted this little test between a Windows 7 machine and Windows XP machine on a 100 Mbit switch.
Used FileZilla server for FTP and FTPS server, FileZilla as FTP and FTPS client, Cygwin OpenSSH as SFTP server and WinSCP as SFTP client.
Was surprised to see how much overhead there was on FTPS, but it could also be something specific to FileZilla.
Windows shares | FTP | FTPS | SFTP | |
---|---|---|---|---|
2700 files, 200Mb | 4,17 Mb/sec 48 secs | 4,76 Mb/sec 42 secs | 0,61 Mb/sec 326 secs | 3,03 Mb/sec 66 secs |
1 file, 550Mb | 9,82 Mb/sec 56 secs | 11,22 Mb/sec 49 secs | 11,00 Mb/sec 50 secs | 6,25 Mb/sec 88 secs |
Friday, July 06, 2012
Finding all machines a user owns in Active Directory
Here's a quick and dirty way to find all machines a user owns in Active Directory. Performance is not good though, as the objects are processed client side. I was not able to find any way of doing server side queries dealing with the ntSecurityDescriptor field. Please let me know if you find a way!
Adjust the DN strings as needed.
Adjust the DN strings as needed.
using System; using System.DirectoryServices; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { DateTime startTime = DateTime.Now; DirectoryEntry d = new DirectoryEntry("LDAP://ou=UserAccounts,dc=contoso,dc=com"); DirectorySearcher s = new DirectorySearcher(d, "(&(objectClass=user)(cn=John Smith))", new string[] { "cn", "objectsid" }); string sid = BitConverter.ToString( (byte[])s.FindOne().Properties["objectsid"][0]) .Replace("-", ""); int count = 0; d = new DirectoryEntry("LDAP://ou=Machines,dc=contoso,dc=com"); s = new DirectorySearcher(d, "(&(objectCategory=computer)(objectClass=computer)(cn=*))", new string[] { "cn", "ntSecurityDescriptor" }); s.PageSize = 500; s.SecurityMasks = SecurityMasks.Owner; foreach (SearchResult r in s.FindAll()) { count++; string cn = (string)r.Properties["cn"][0]; string sd = BitConverter.ToString((byte[])r.Properties["ntsecuritydescriptor"][0]).Replace("-", ""); if (sd.Contains(sid)) Console.WriteLine(cn); } Console.WriteLine(); Console.WriteLine("Checked " + count + " objects"); Console.WriteLine("Query finished in " + (DateTime.Now - startTime)); } } }
Tuesday, June 26, 2012
Compiling Bootstrap LESS on Windows
The current version of Bootstrap can neither be compiled on WinLess nor lessc.exe as of writing. I found that these days the easiest is actually to run the Windows version of Node.js. Standalone single .exe versions of Node.js are available. Go download the less.js source and you can make yourself a "lessjs.cmd" with something like the following:
d:\utils\node.exe d:\utils\lesscss\bin\lessc %1
Monday, April 30, 2012
Django as a micro framework, including models
The following can be used as a base when you want to avoid the normal structure Django imposes on your project, and you just want everything in a single file.
It is based on similar attempts by Ivan Sagalaev and Fahrzin Hemmati (especially this gist), and a post on stack overflow.
A thing that I consider an improvement over Fahrzin Hemmati's version is that models don't need the explicit app_label and __module__.
# # Django as a microframework skeleton, by Allan Boll, 1 May 2012 # Based on http://softwaremaniacs.org/blog/2011/01/07/django-micro-framework/en/ # and https://gist.github.com/2219751 # # # Settings # appname = 'app' from django.conf import settings if not settings.configured: settings.configure( SITE_ID=1, TEMPLATE_DIRS=['.'], DATABASES = { 'default':{ 'ENGINE':'django.db.backends.sqlite3', 'NAME': 'db', } }, DEBUG=True, TEMPLATE_DEBUG=True, ROOT_URLCONF = __name__, STATIC_URL='/static/', STATICFILES_DIRS=['./static/'], INSTALLED_APPS=( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.admin', ) ) # # Models # from django.db import models # Workaround to allow models in current file import sys sys.modules[appname+'.'] = sys.modules[__name__] old_module_name = sys.modules[__name__].__name__ sys.modules[__name__].__name__ = appname+'.' class SomeModel(models.Model): field_name = models.CharField(max_length=10) # Continuation of workaround to allow models in current file sys.modules[__name__].__name__ = old_module_name # # Views # from django.shortcuts import render def index(request): out = [] for obj in SomeModel.objects.all(): out.append(obj.field_name) return render(request, 'index.html', {'s': ', '.join(out)}) # # URL configuration # from django.conf.urls.defaults import patterns, url, include urlpatterns = patterns('', (r'^$', index), ) # # Admin site # from django.contrib import admin from django.contrib.auth.admin import UserAdmin, GroupAdmin from django.contrib.auth.models import User, Group admin.site = admin.AdminSite() admin.site.register(User, UserAdmin) admin.site.register(Group, GroupAdmin) admin.site.register(SomeModel) urlpatterns = patterns('', url(r'^admin/', include(admin.site.urls)) ) + urlpatterns # # Running # if __name__=='__main__': # Monkey patch get_app to allow models in current file get_app_orig = models.get_app def get_app(app_label,*a, **kw): if app_label==appname: return sys.modules[__name__] return get_app_orig(app_label, *a, **kw) models.get_app = get_app # Add models in current file to global list of apps models.loading.cache.app_store[type(appname+'.models',(),{'__file__':__file__})] = appname from django.core import management management.execute_from_command_line()
Friday, February 10, 2012
Sublime Text default to empty file
I recently began using the editor Sublime Text. Previously I was using Notepad++ which is also a fine editor, but not as "futuristic" as Sublime Text. I had gotten used to Notepad++'s behaviour of defaulting to an empty file when all tabs are closed, and found that this behaviour was easy to achieve in Sublime Text as well, thanks to its amazing API. To get the behaviour, drop the following Python source into something like Data/Packages/User/default_to_empty_file.py.
import sublime, sublime_plugin
class DefaultToEmptyFile(sublime_plugin.EventListener):
def on_close(self, view):
for window in sublime.windows():
if window == None:
continue
if len(window.views()) <= 1:
window.new_file()
def on_load(self, view):
window = view.window()
if window == None:
return
views = window.views()
if len(views) == 2:
for v in views:
if v != view and v.file_name() == None and v.size() == 0:
window.focus_view(v)
window.run_command('close_file')
Subscribe to:
Posts (Atom)