/// <summary> /// ProcessRecord method. /// </summary> protected override void ProcessRecord() { try { if (CheckShouldProcess(Name)) { var user = new LocalUser { Name = Name, Description = Description, Enabled = true, FullName = FullName, UserMayChangePassword = true }; foreach (var paramName in parameterNames) { if (this.HasParameter(paramName)) { switch (paramName) { case "AccountExpires": user.AccountExpires = AccountExpires; break; case "Disabled": user.Enabled = !Disabled; break; case "UserMayNotChangePassword": user.UserMayChangePassword = !UserMayNotChangePassword; break; } } } if (AccountNeverExpires.IsPresent) user.AccountExpires = null; // Password will be null if NoPassword was given user = sam.CreateLocalUser(user, Password, PasswordNeverExpires.IsPresent); WriteObject(user); } } catch (Exception ex) { WriteError(ex.MakeErrorRecord()); } }
/// <summary> /// Construct a new LocalUser object that is a copy of another. /// </summary> /// <param name="other">The LocalUser object to copy.</param> private LocalUser(LocalUser other) : this(other.Name) { SID = other.SID; PrincipalSource = other.PrincipalSource; ObjectClass = other.ObjectClass; AccountExpires = other.AccountExpires; Description = other.Description; Enabled = other.Enabled; FullName = other.FullName; PasswordChangeableDate = other.PasswordChangeableDate; PasswordExpires = other.PasswordExpires; UserMayChangePassword = other.UserMayChangePassword; PasswordRequired = other.PasswordRequired; PasswordLastSet = other.PasswordLastSet; LastLogon = other.LastLogon; }
/// <summary> /// Enable or disable a Local User /// </summary> /// <param name="user"> /// A <see cref="LocalUser"/> object representing the user to enable or disable. /// </param> /// <param name="enable"> /// One of the <see cref="Enabling"/> enumeration values, indicating whether to /// enable or disable the user. /// </param> internal void EnableLocalUser(LocalUser user, Enabling enable) { context = new Context(enable == Enabling.Enable ? ContextOperation.Enable : ContextOperation.Disable, ContextObjectType.User, user.Name, user); if (user.SID == null) context.target = user = GetLocalUser(user.Name); EnableUser(user.SID, enable); }
/// <summary> /// Update a local user with new properties. /// </summary> /// <param name="user"> /// A <see cref="LocalUser"/> object representing the user to be updated. /// </param> /// <param name="changed"> /// A LocalUser object containing the desired changes. /// </param> /// <param name="password">A <see cref="System.Security.SecureString"/> /// object containing the new password. A null value in this parameter /// indicates that the password is not to be changed. /// </param> /// <param name="setPasswordNeverExpires"> /// Specifies whether the PasswordNeverExpires parameter was set. /// </param> /// <remarks> /// Call this overload when intending to leave the password-expired /// marker in its current state. To set the password and the /// password-expired state, call the overload with a boolean as the /// fourth parameter /// </remarks> internal void UpdateLocalUser(LocalUser user, LocalUser changed, System.Security.SecureString password, bool? setPasswordNeverExpires) { context = new Context(ContextOperation.Set, ContextObjectType.User, user.Name, user); UpdateUser(user, changed, password, PasswordExpiredState.Unchanged, setPasswordNeverExpires); }
/// <summary> /// Create a local user /// </summary> /// <param name="user">A <see cref="LocalUser"/> object containing /// information about the local user to be created. /// </param> /// <param name="password">A <see cref="System.Security.SecureString"/> containing /// the initial password to be set for the new local user. If this parameter is null, /// no password is set. /// </param> /// <param name="setPasswordNeverExpires"> /// Indicates whether PasswordNeverExpires was specified /// </param> /// <returns> /// A new LocalGroup object containing information about the newly /// created local user. /// </returns> /// <exception cref="UserExistsException"> /// Thrown when an attempt is made to create a local user that already /// exists. /// </exception> internal LocalUser CreateLocalUser(LocalUser user, System.Security.SecureString password, bool setPasswordNeverExpires) { context = new Context(ContextOperation.New, ContextObjectType.User, user.Name, user); return CreateUser(user, password, localDomainHandle, setPasswordNeverExpires); }
/// <summary> /// Rename a local user. /// </summary> /// <param name="user"> /// A <see cref="LocalUser"/> objects containing /// information about the local user to be renamed. /// </param> /// <param name="newName"> /// A string containing the new name for the local user. /// </param> /// <exception cref="UserNotFoundException"> /// Thrown when the specified user cannot be found. /// </exception> internal void RenameLocalUser(LocalUser user, string newName) { context = new Context(ContextOperation.Rename, ContextObjectType.User, user.Name, user); if (user.SID == null) context.target = user = GetLocalUser(user.Name); RenameUser(user.SID, newName); }
/// <summary> /// Set selected properties of a user. /// </summary> /// <param name="userHandle">Handle to an open SAM user.</param> /// <param name="sourceUser"> /// A <see cref="LocalUser"/> object containing the data to set into the user. /// </param> /// <param name="setFlags"> /// A combination of <see cref="UserProperties"/> values indicating the properties to be set. /// </param> /// <param name="password">A <see cref="System.Security.SecureString"/> /// object containing the new password. /// </param> /// <param name="passwordExpired">One of the /// <see cref="PasswordExpiredState"/> enumeration values indicating /// whether the password-expired state is to be explicitly set or /// left as is. If the <paramref name="password"/> parameter is null, /// this parameter is ignored. /// </param> /// <param name="setPasswordNeverExpires"> /// Nullable value the specifies whether the PasswordNeverExpires bit should be flipped /// </param> private void SetUserData(IntPtr userHandle, LocalUser sourceUser, UserProperties setFlags, System.Security.SecureString password, PasswordExpiredState passwordExpired, bool? setPasswordNeverExpires) { IntPtr buffer = IntPtr.Zero; try { UInt32 which = 0; UInt32 status = 0; UInt32 uac = GetUserAccountControl(userHandle); USER_ALL_INFORMATION info = new USER_ALL_INFORMATION(); if (setFlags.HasFlag(UserProperties.AccountExpires)) { which |= SamApi.USER_ALL_ACCOUNTEXPIRES; info.AccountExpires.QuadPart = sourceUser.AccountExpires.HasValue ? sourceUser.AccountExpires.Value.ToFileTime() : 0L; } if (setFlags.HasFlag(UserProperties.Description)) { which |= SamApi.USER_ALL_ADMINCOMMENT; info.AdminComment = new UNICODE_STRING(sourceUser.Description); } if (setFlags.HasFlag(UserProperties.Enabled)) { which |= SamApi.USER_ALL_USERACCOUNTCONTROL; if (sourceUser.Enabled) uac &= ~SamApi.USER_ACCOUNT_DISABLED; else uac |= SamApi.USER_ACCOUNT_DISABLED; } if (setFlags.HasFlag(UserProperties.FullName)) { which |= SamApi.USER_ALL_FULLNAME; info.FullName = new UNICODE_STRING(sourceUser.FullName); } if (setFlags.HasFlag(UserProperties.PasswordNeverExpires)) { // Only modify the bit if a change was requested if (setPasswordNeverExpires.HasValue) { which |= SamApi.USER_ALL_USERACCOUNTCONTROL; if (setPasswordNeverExpires.Value) uac |= SamApi.USER_DONT_EXPIRE_PASSWORD; else uac &= ~SamApi.USER_DONT_EXPIRE_PASSWORD; } } if (setFlags.HasFlag(UserProperties.PasswordRequired)) { which |= SamApi.USER_ALL_USERACCOUNTCONTROL; if (sourceUser.PasswordRequired) uac &= ~SamApi.USER_PASSWORD_NOT_REQUIRED; else uac |= SamApi.USER_PASSWORD_NOT_REQUIRED; } if (which != 0) { info.WhichFields = which; if ((which & SamApi.USER_ALL_USERACCOUNTCONTROL) != 0) info.UserAccountControl = uac; buffer = Marshal.AllocHGlobal(ClrFacade.SizeOf<USER_ALL_INFORMATION>()); ClrFacade.StructureToPtr<USER_ALL_INFORMATION>(info, buffer, false); status = SamApi.SamSetInformationUser(userHandle, USER_INFORMATION_CLASS.UserAllInformation, buffer); ThrowOnFailure(status); status = SamApi.SamFreeMemory(buffer); buffer = IntPtr.Zero; } if (setFlags.HasFlag(UserProperties.UserMayChangePassword)) SetUserMayChangePassword(userHandle, sourceUser.SID, sourceUser.UserMayChangePassword); if (password != null) SetUserPassword(userHandle, password, passwordExpired); } finally { if (buffer != IntPtr.Zero) { ClrFacade.DestroyStructure<USER_ALL_INFORMATION>(buffer); Marshal.FreeHGlobal(buffer); } } }
/// <summary> /// Update a local user with new properties. /// </summary> /// <param name="user"> /// A <see cref="LocalUser"/> object representing the user to be updated. /// </param> /// <param name="changed"> /// A LocalUser object containing the desired changes. /// </param> /// <param name="password">A <see cref="System.Security.SecureString"/> /// object containing the new password. A null value in this parameter /// indicates that the password is not to be changed. /// </param> /// <param name="passwordExpired">One of the /// <see cref="PasswordExpiredState"/> enumeration values indicating /// whether the password-expired state is to be explicitly set or /// left as is. /// If the <paramref name="password"/> parameter is null, this parameter /// is ignored. /// </param> /// <param name="setPasswordNeverExpires"> /// Indicates whether the PasswordNeverExpires parameter was specified. /// </param> private void UpdateUser(LocalUser user, LocalUser changed, System.Security.SecureString password, PasswordExpiredState passwordExpired, bool? setPasswordNeverExpires) { UserProperties properties = UserProperties.None; if (user.AccountExpires != changed.AccountExpires) properties |= UserProperties.AccountExpires; if (user.Description != changed.Description) properties |= UserProperties.Description; if (user.FullName != changed.FullName) properties |= UserProperties.FullName; if (setPasswordNeverExpires.HasValue) properties |= UserProperties.PasswordNeverExpires; if (user.UserMayChangePassword != changed.UserMayChangePassword) properties |= UserProperties.UserMayChangePassword; if (user.PasswordRequired != changed.PasswordRequired) properties |= UserProperties.PasswordRequired; if ( properties != UserProperties.None || passwordExpired != PasswordExpiredState.Unchanged || password != null) { IntPtr userHandle = IntPtr.Zero; UInt32 status = 0; try { status = SamApi.SamOpenUser(localDomainHandle, Win32.MAXIMUM_ALLOWED, user.SID.GetRid(), out userHandle); ThrowOnFailure(status); SetUserData(userHandle, changed, properties, password, passwordExpired, setPasswordNeverExpires); } finally { if (userHandle != IntPtr.Zero) status = SamApi.SamCloseHandle(userHandle); } } }
/// <summary> /// Create a populated LocalUser object from a SamRidEnumeration object, /// using an already-opened SAM user handle. /// </summary> /// <param name="sre"> /// A <see cref="SamRidEnumeration"/> object containing minimal information /// about a local user. /// </param> /// <param name="userHandle"> /// Handle to an open SAM user. /// </param> /// <returns> /// A LocalUser object, populated with user information. /// </returns> private LocalUser MakeLocalUserObject(SamRidEnumeration sre, IntPtr userHandle) { IntPtr buffer = IntPtr.Zero; UInt32 status = 0; try { USER_ALL_INFORMATION allInfo; status = SamApi.SamQueryInformationUser(userHandle, USER_INFORMATION_CLASS.UserAllInformation, out buffer); ThrowOnFailure(status); allInfo = ClrFacade.PtrToStructure<USER_ALL_INFORMATION>(buffer); var userSid = RidToSid(sre.domainHandle, sre.RelativeId); LocalUser user = new LocalUser() { PrincipalSource = GetPrincipalSource(sre), SID = userSid, Name = allInfo.UserName.ToString(), FullName = allInfo.FullName.ToString(), Description = allInfo.AdminComment.ToString(), //TODO: why is this coming up as 864000000000 (number of ticks per day)? PasswordChangeableDate = DateTimeFromSam(allInfo.PasswordCanChange.QuadPart), PasswordExpires = DateTimeFromSam(allInfo.PasswordMustChange.QuadPart), //TODO: why is this coming up as 0X7FFFFFFFFFFFFFFF (largest signed 64-bit, and well out of range of DateTime)? AccountExpires = DateTimeFromSam(allInfo.AccountExpires.QuadPart), LastLogon = DateTimeFromSam(allInfo.LastLogon.QuadPart), PasswordLastSet = DateTimeFromSam(allInfo.PasswordLastSet.QuadPart), UserMayChangePassword = GetUserMayChangePassword(userHandle, userSid), PasswordRequired = (allInfo.UserAccountControl & SamApi.USER_PASSWORD_NOT_REQUIRED) == 0, Enabled = !((allInfo.UserAccountControl & SamApi.USER_ACCOUNT_DISABLED) == SamApi.USER_ACCOUNT_DISABLED) }; return user; } finally { if (buffer != IntPtr.Zero) status = SamApi.SamFreeMemory(buffer); } }
/// <summary> /// Create a new user in the specified domain. /// </summary> /// <param name="userInfo"> /// A <see cref="LocalUser"/> object containing information about the new user. /// </param> /// <param name="password">A <see cref="System.Security.SecureString"/> containing /// the initial password to be set for the new local user. If this parameter is null, /// no password is set. /// </param> /// <param name="domainHandle"> /// Handle to the domain in which to create the new user. /// </param> /// <param name="setPasswordNeverExpires"> /// Indicates whether PasswordNeverExpires was specified /// </param> /// <returns> /// A LocalUser object that represents the newly-created user /// </returns> private LocalUser CreateUser(LocalUser userInfo, System.Security.SecureString password, IntPtr domainHandle, bool setPasswordNeverExpires) { IntPtr userHandle = IntPtr.Zero; IntPtr buffer = IntPtr.Zero; UNICODE_STRING str = new UNICODE_STRING(); UInt32 status = 0; try { UInt32 relativeId = 0; UInt32 grantedAccess = 0; str = new UNICODE_STRING(userInfo.Name); buffer = Marshal.AllocHGlobal(Marshal.SizeOf(str)); Marshal.StructureToPtr(str, buffer, false); status = SamApi.SamCreateUser2InDomain(domainHandle, ref str, (int) SamApi.USER_NORMAL_ACCOUNT, Win32.MAXIMUM_ALLOWED, out userHandle, out grantedAccess, out relativeId); ClrFacade.DestroyStructure<UNICODE_STRING>(buffer); Marshal.FreeHGlobal(buffer); buffer = IntPtr.Zero; ThrowOnFailure(status); // set the various properties of the user. A SID is required because some // operations depend on it. userInfo.SID = RidToSid(domainHandle, relativeId); SetUserData(userHandle, userInfo, UserProperties.AllCreateable, password, PasswordExpiredState.NotExpired, setPasswordNeverExpires); return MakeLocalUserObject(new SamRidEnumeration { domainHandle = domainHandle, Name = userInfo.Name, RelativeId = relativeId }, userHandle); } finally { if (buffer != IntPtr.Zero) Marshal.FreeHGlobal(buffer); if (userHandle != IntPtr.Zero) status = SamApi.SamCloseHandle(userHandle); } }
/// <summary> /// ProcessRecord method. /// </summary> protected override void ProcessRecord() { try { LocalUser user = null; if (InputObject != null) { if (CheckShouldProcess(InputObject.ToString())) { user = InputObject; } } else if (Name != null) { user = sam.GetLocalUser(Name); if (!CheckShouldProcess(Name)) { user = null; } } else if (SID != null) { user = sam.GetLocalUser(SID); if (!CheckShouldProcess(SID.ToString())) { user = null; } } if (user == null) { return; } // We start with what already exists var delta = user.Clone(); bool?passwordNeverExpires = null; foreach (var paramName in parameterNames) { if (this.HasParameter(paramName)) { switch (paramName) { case "AccountExpires": delta.AccountExpires = this.AccountExpires; break; case "Description": delta.Description = this.Description; break; case "FullName": delta.FullName = this.FullName; break; case "UserMayChangePassword": delta.UserMayChangePassword = this.UserMayChangePassword; break; case "PasswordNeverExpires": passwordNeverExpires = this.PasswordNeverExpires; break; } } } if (AccountNeverExpires.IsPresent) { delta.AccountExpires = null; } sam.UpdateLocalUser(user, delta, Password, passwordNeverExpires); } catch (Exception ex) { WriteError(ex.MakeErrorRecord()); } }