diff --git a/assets/files.wxs b/assets/files.wxs
index 9e40745ec69..669c1a8f7f4 100644
--- a/assets/files.wxs
+++ b/assets/files.wxs
@@ -1964,6 +1964,11 @@
+
+
+
+
+
@@ -3074,6 +3079,15 @@
+
+
+
+
+
+
+
+
+
@@ -4064,6 +4078,12 @@
+
+
+
+
+
+
diff --git a/src/Microsoft.PowerShell.AccountManagement/Microsoft.PowerShell.AccountManagement.csproj b/src/Microsoft.PowerShell.AccountManagement/Microsoft.PowerShell.AccountManagement.csproj
new file mode 100644
index 00000000000..a672921a3d5
--- /dev/null
+++ b/src/Microsoft.PowerShell.AccountManagement/Microsoft.PowerShell.AccountManagement.csproj
@@ -0,0 +1,21 @@
+
+
+
+ PowerShell's Microsoft.PowerShell.AccountManagement project
+ $(NoWarn);CS1570
+ Microsoft.PowerShell.AccountManagement
+
+
+
+
+
+
+
+ $(DefineConstants);CORECLR
+
+
+
+
+
+
+
diff --git a/src/Microsoft.PowerShell.AccountManagement/commands/GetUserCommand.cs b/src/Microsoft.PowerShell.AccountManagement/commands/GetUserCommand.cs
new file mode 100644
index 00000000000..978ad1102a8
--- /dev/null
+++ b/src/Microsoft.PowerShell.AccountManagement/commands/GetUserCommand.cs
@@ -0,0 +1,383 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.DirectoryServices.AccountManagement;
+using System.Management.Automation;
+
+namespace Microsoft.PowerShell.Commands
+{
+ ///
+ /// The New-User cmdlet creates a new local user account.
+ ///
+ [Cmdlet(VerbsCommon.Get, "User",
+ HelpUri = "")]
+ public class GetUserCommand : PSCmdlet
+ {
+ ///
+ /// Gets or sets the type of store to which the account belongs.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public ContextType AccountStore
+ {
+ get;
+ set;
+ } = ContextType.Domain;
+
+ ///
+ /// Gets or sets options that are used for binding to the Server (domain controller or local machine).
+ ///
+ [Parameter]
+ public ContextOptions ContextOptions
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets an user credential that are used for binding to the Server (domain controller or local machine).
+ ///
+ [Parameter]
+ public PSCredential Credential
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a value that specifies whether the account may be delegated.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter DelegationPermitted
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a descriptive comment for this user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string Description
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify whether this user account is enabled or disabled.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter Enabled
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a display name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string DisplayName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a E-mail address of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string EmailAddress
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a employee ID of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string EmployeeId
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a given name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string GivenName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a Home directory of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string HomeDirectory
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a Home drive of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string HomeDrive
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a middle name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string MiddleName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a user name for the user account.
+ ///
+ [Parameter(
+ ValueFromPipeline = true,
+ ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNullOrEmpty]
+ [ValidateLength(1, 20)]
+ public string Name
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify that the new User account has no password.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter PasswordNotRequired
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify that the password will not expire.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter PasswordNeverExpires
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a container on the store to use as the root of the context.
+ /// All queries are performed under this root, and all inserts are performed into this container.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string Path
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a SAM account name for the user account.
+ ///
+ [Parameter(
+ Position = 0,
+ ValueFromPipelineByPropertyName = true)]
+ public string SamAccountName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a server/machine or domain controller where the user account will be searched from.
+ ///
+ [Parameter]
+ public string Server
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a surname of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string SurName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify whether the user is allowed to change the password on the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter UserCannotChangePassword
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a user principal name (UPN) associated with the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string UserPrincipalName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// ProcessRecord method.
+ ///
+ protected override void ProcessRecord()
+ {
+ try
+ {
+ var bindingUserName = Credential?.UserName;
+ var bindingUserPassword = Credential == null ? null : new System.Net.NetworkCredential(string.Empty, Credential.Password).Password;
+ var options = this.MyInvocation.BoundParameters.ContainsKey(nameof(ContextOptions)) ? ContextOptions : DefaultContextOptions.GetDefaultOptionForStore(AccountStore);
+ using var principalContext = new PrincipalContext(contextType: AccountStore, name: Server, container: Path, options, bindingUserName, bindingUserPassword);
+ UserPrincipal user;
+
+ if (AccountStore == ContextType.Machine)
+ {
+ user = new UserPrincipal(principalContext);
+ SetMachineUserPrincipalProperties(user);
+ }
+ else
+ {
+ user = new UserPrincipal(principalContext);
+ SetADUserPrincipalProperties(user);
+ }
+
+ PrincipalSearcher ps = new PrincipalSearcher(user);
+
+ PrincipalSearchResult results = ps.FindAll();
+
+ foreach (var principal in results)
+ {
+ WriteObject(principal);
+ }
+ }
+ catch (Exception ex)
+ {
+ WriteError(
+ new ErrorRecord(
+ ex,
+ "InvalidValue",
+ ErrorCategory.InvalidOperation,
+ null));
+ }
+ }
+
+ private void SetMachineUserPrincipalProperties(UserPrincipal userPrincipal)
+ {
+ foreach (var parameter in this.MyInvocation.BoundParameters)
+ {
+ switch (parameter.Key)
+ {
+ case "Name":
+ userPrincipal.Name = Name;
+ break;
+ case "Description":
+ userPrincipal.Description = Description;
+ break;
+ case "DisplayName":
+ userPrincipal.DisplayName = DisplayName;
+ break;
+ case "Enabled":
+ userPrincipal.Enabled = Enabled;
+ break;
+ case "PasswordNotRequired":
+ userPrincipal.PasswordNotRequired = PasswordNotRequired;
+ break;
+ case "PasswordNeverExpires":
+ userPrincipal.PasswordNeverExpires = PasswordNeverExpires;
+ break;
+ case "SamAccountName":
+ userPrincipal.SamAccountName = SamAccountName;
+ break;
+ case "UserCannotChangePassword":
+ userPrincipal.UserCannotChangePassword = UserCannotChangePassword;
+ break;
+ }
+ }
+ }
+
+ private void SetADUserPrincipalProperties(UserPrincipal userPrincipal)
+ {
+ foreach (var parameter in this.MyInvocation.BoundParameters)
+ {
+ switch (parameter.Key)
+ {
+ case "Name":
+ userPrincipal.Name = Name;
+ break;
+ case "DelegationPermitted":
+ userPrincipal.DelegationPermitted = DelegationPermitted;
+ break;
+ case "Description":
+ userPrincipal.Description = Description;
+ break;
+ case "DisplayName":
+ userPrincipal.DisplayName = DisplayName;
+ break;
+ case "Enabled":
+ userPrincipal.Enabled = Enabled;
+ break;
+ case "EmployeeId":
+ userPrincipal.EmployeeId = EmployeeId;
+ break;
+ case "EmailAddress":
+ userPrincipal.EmailAddress = EmailAddress;
+ break;
+ case "GivenName":
+ userPrincipal.GivenName = GivenName;
+ break;
+ case "HomeDirectory":
+ userPrincipal.HomeDirectory = HomeDirectory;
+ break;
+ case "HomeDrive":
+ userPrincipal.HomeDrive = HomeDrive;
+ break;
+ case "MiddleName":
+ userPrincipal.MiddleName = MiddleName;
+ break;
+ case "PasswordNotRequired":
+ userPrincipal.PasswordNotRequired = PasswordNotRequired;
+ break;
+ case "PasswordNeverExpires":
+ userPrincipal.PasswordNeverExpires = PasswordNeverExpires;
+ break;
+ case "SamAccountName":
+ userPrincipal.SamAccountName = SamAccountName;
+ break;
+ case "SurName":
+ userPrincipal.Surname = SurName;
+ break;
+ case "UserCannotChangePassword":
+ userPrincipal.UserCannotChangePassword = UserCannotChangePassword;
+ break;
+ case "UserPrincipalName":
+ userPrincipal.UserPrincipalName = UserPrincipalName;
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.PowerShell.AccountManagement/commands/NewUserCommand.cs b/src/Microsoft.PowerShell.AccountManagement/commands/NewUserCommand.cs
new file mode 100644
index 00000000000..779c086f330
--- /dev/null
+++ b/src/Microsoft.PowerShell.AccountManagement/commands/NewUserCommand.cs
@@ -0,0 +1,462 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.DirectoryServices.AccountManagement;
+using System.Management.Automation;
+
+namespace Microsoft.PowerShell.Commands
+{
+ ///
+ /// The New-User cmdlet creates a new local user account.
+ ///
+ [Cmdlet(VerbsCommon.New, "User",
+ DefaultParameterSetName = "Password",
+ SupportsShouldProcess = true,
+ HelpUri = "")]
+ public class NewUserCommand : PSCmdlet
+ {
+ ///
+ /// Gets or sets a DateTime that specifies the date and time that the account expires.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public DateTime AccountExpires
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify that the account will not expire.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter AccountNeverExpires
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets the type of store to which the account belongs.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public ContextType AccountStore
+ {
+ get;
+ set;
+ } = ContextType.Domain;
+
+ ///
+ /// Gets or sets options that are used for binding to the Server (domain controller or local machine).
+ ///
+ [Parameter]
+ public ContextOptions ContextOptions
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets an user credential that are used for binding to the Server (domain controller or local machine).
+ ///
+ [Parameter]
+ public PSCredential Credential
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a value that specifies whether the account may be delegated.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public SwitchParameter DelegationPermitted
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a descriptive comment for this user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string Description
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify whether this user account is enabled or disabled.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter Enabled
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a display name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string DisplayName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a E-mail address of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string EmailAddress
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a employee ID of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string EmployeeId
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a given name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string GivenName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a Home directory of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string HomeDirectory
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a Home drive of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string HomeDrive
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a middle name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string MiddleName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a user name for the user account.
+ ///
+ [Parameter(Mandatory = true,
+ Position = 0,
+ ValueFromPipeline = true,
+ ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNullOrEmpty]
+ [ValidateLength(1, 20)]
+ public string Name
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a password for the user account. A password can contain up to 127 characters.
+ /// Ex.: new-User -Name qw -Password $((new-object Net.NetworkCredential("", "Qwerty")).SecurePassword).
+ ///
+ [Parameter(Mandatory = true,
+ ParameterSetName = "Password",
+ ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public System.Security.SecureString Password
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify that the new User account has no password.
+ ///
+ [Parameter(Mandatory = true,
+ ParameterSetName = "NoPassword",
+ ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter PasswordNotRequired
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify that the password will not expire.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter PasswordNeverExpires
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a container on the store to use as the root of the context.
+ /// All queries are performed under this root, and all inserts are performed into this container.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string Path
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a SAM account name for the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string SamAccountName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a server/machine or domain controller where the user account will be created.
+ ///
+ [Parameter]
+ public string Server
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a surname of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNull]
+ public string SurName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify whether the user is allowed to change the password on the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter UserCannotChangePassword
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a user principal name (UPN) associated with the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string UserPrincipalName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// ProcessRecord method.
+ ///
+ protected override void ProcessRecord()
+ {
+ try
+ {
+ if (ShouldProcess(Name, NewUserStrings.ActionNewUser))
+ {
+ var bindingUserName = Credential?.UserName;
+ var bindingUserPassword = Credential == null ? null : new System.Net.NetworkCredential(string.Empty, Credential.Password).Password;
+ var options = this.MyInvocation.BoundParameters.ContainsKey(nameof(ContextOptions)) ? ContextOptions : DefaultContextOptions.GetDefaultOptionForStore(AccountStore);
+ using var principalContext = new PrincipalContext(contextType: AccountStore, name: Server, container: Path, options, bindingUserName, bindingUserPassword);
+ UserPrincipal user;
+
+ if (AccountStore == ContextType.Machine)
+ {
+ user = new UserPrincipal(principalContext);
+ SetMachineUserPrincipalProperties(user);
+ }
+ else
+ {
+ user = new UserPrincipal(principalContext);
+ SetADUserPrincipalProperties(user);
+ }
+
+ if (this.MyInvocation.BoundParameters.ContainsKey(nameof(SamAccountName)))
+ {
+ user.SamAccountName = SamAccountName;
+ }
+ else
+ {
+ // Name is mandatory and always presents.
+ user.SamAccountName = Name;
+ }
+
+ if (PasswordNotRequired.IsPresent)
+ {
+ user.Enabled = false;
+ user.PasswordNeverExpires = true;
+ user.PasswordNotRequired = true;
+ }
+ else
+ {
+ user.SetPassword(new System.Net.NetworkCredential(string.Empty, Password).Password);
+ }
+
+ user.Save();
+
+ WriteObject(user);
+ }
+ }
+ catch (Exception ex)
+ {
+ WriteError(
+ new ErrorRecord(
+ ex,
+ "InvalidValue",
+ ErrorCategory.InvalidOperation,
+ null));
+ }
+ }
+
+ private void SetMachineUserPrincipalProperties(UserPrincipal userPrincipal)
+ {
+ foreach (var parameter in this.MyInvocation.BoundParameters)
+ {
+ switch (parameter.Key)
+ {
+ case "AccountExpirationDate":
+ userPrincipal.AccountExpirationDate = !AccountNeverExpires.IsPresent ? AccountExpires : (DateTime?)null;
+ break;
+ case "Name":
+ userPrincipal.Name = Name;
+ break;
+ case "Description":
+ userPrincipal.Description = Description;
+ break;
+ case "DisplayName":
+ userPrincipal.DisplayName = DisplayName;
+ break;
+ case "Enabled":
+ userPrincipal.Enabled = Enabled;
+ break;
+ case "PasswordNeverExpires":
+ userPrincipal.PasswordNeverExpires = PasswordNeverExpires;
+ break;
+ case "UserCannotChangePassword":
+ userPrincipal.UserCannotChangePassword = UserCannotChangePassword;
+ break;
+ }
+ }
+ }
+
+ private void SetADUserPrincipalProperties(UserPrincipal userPrincipal)
+ {
+ foreach (var parameter in this.MyInvocation.BoundParameters)
+ {
+ switch (parameter.Key)
+ {
+ case "AccountExpirationDate":
+ userPrincipal.AccountExpirationDate = !AccountNeverExpires.IsPresent ? AccountExpires : (DateTime?)null;
+ break;
+ case "Name":
+ userPrincipal.Name = Name;
+ break;
+ case "DelegationPermitted":
+ userPrincipal.DelegationPermitted = DelegationPermitted;
+ break;
+ case "Description":
+ userPrincipal.Description = Description;
+ break;
+ case "DisplayName":
+ userPrincipal.DisplayName = DisplayName;
+ break;
+ case "Enabled":
+ userPrincipal.Enabled = Enabled;
+ break;
+ case "EmployeeId":
+ userPrincipal.EmployeeId = EmployeeId;
+ break;
+ case "EmailAddress":
+ userPrincipal.EmailAddress = EmailAddress;
+ break;
+ case "GivenName":
+ userPrincipal.GivenName = GivenName;
+ break;
+ case "HomeDirectory":
+ userPrincipal.HomeDirectory = HomeDirectory;
+ break;
+ case "HomeDrive":
+ userPrincipal.HomeDrive = HomeDrive;
+ break;
+ case "MiddleName":
+ userPrincipal.MiddleName = MiddleName;
+ break;
+ case "PasswordNeverExpires":
+ userPrincipal.PasswordNeverExpires = PasswordNeverExpires;
+ break;
+ case "UserCannotChangePassword":
+ userPrincipal.UserCannotChangePassword = UserCannotChangePassword;
+ break;
+ case "SurName":
+ userPrincipal.Surname = SurName;
+ break;
+ case "UserPrincipalName":
+ userPrincipal.UserPrincipalName = UserPrincipalName;
+ break;
+ }
+ }
+ }
+ }
+
+ internal static class DefaultContextOptions
+ {
+ internal static readonly ContextOptions MachineDefaultContextOption = ContextOptions.Negotiate;
+ internal static readonly ContextOptions ADDefaultContextOption = ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing;
+
+ internal static ContextOptions GetDefaultOptionForStore(ContextType storeType)
+ {
+ if (storeType == ContextType.Machine)
+ {
+ return DefaultContextOptions.MachineDefaultContextOption;
+ }
+ else
+ {
+ return DefaultContextOptions.ADDefaultContextOption;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.PowerShell.AccountManagement/commands/RemoveUserCommand.cs b/src/Microsoft.PowerShell.AccountManagement/commands/RemoveUserCommand.cs
new file mode 100644
index 00000000000..0737d44ee8d
--- /dev/null
+++ b/src/Microsoft.PowerShell.AccountManagement/commands/RemoveUserCommand.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.DirectoryServices.AccountManagement;
+using System.Management.Automation;
+
+namespace Microsoft.PowerShell.Commands
+{
+ ///
+ /// The Remove-User cmdlet creates a new local user account.
+ ///
+ [Cmdlet(VerbsCommon.Remove, "User",
+ SupportsShouldProcess = true,
+ HelpUri = "")]
+ public class RemoveUserCommand : PSCmdlet
+ {
+ ///
+ /// Gets or sets an user identity to remove.
+ ///
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)]
+ public UserPrincipal Identity
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// ProcessRecord method.
+ ///
+ protected override void ProcessRecord()
+ {
+ try
+ {
+ if (ShouldProcess(Identity.ToString(), NewUserStrings.ActionNewUser))
+ {
+ Identity.Delete();
+ }
+ }
+ catch (UnauthorizedAccessException exc)
+ {
+ WriteError(new ErrorRecord(exc, "RemoveUserFailure", ErrorCategory.PermissionDenied, Identity));
+ }
+ catch (InvalidOperationException exc)
+ {
+ WriteError(new ErrorRecord(exc, "UserAlreadyRemoved", ErrorCategory.InvalidOperation, Identity));
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.PowerShell.AccountManagement/commands/SearchAccountCommand.cs b/src/Microsoft.PowerShell.AccountManagement/commands/SearchAccountCommand.cs
new file mode 100644
index 00000000000..fb1c9cc967b
--- /dev/null
+++ b/src/Microsoft.PowerShell.AccountManagement/commands/SearchAccountCommand.cs
@@ -0,0 +1,481 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.DirectoryServices.AccountManagement;
+using System.Management.Automation;
+
+namespace Microsoft.PowerShell.Commands
+{
+ ///
+ /// The Search-Account cmdlet creates a new local user account.
+ ///
+ [Cmdlet(VerbsCommon.Search, "Account",
+ HelpUri = "")]
+ public class SearchAccountCommand : PSCmdlet
+ {
+ ///
+ /// Gets or sets the type of store to which the account belongs.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public ContextType AccountStore
+ {
+ get;
+ set;
+ } = ContextType.Domain;
+
+ ///
+ /// Gets or sets options that are used for binding to the Server (domain controller or local machine).
+ ///
+ [Parameter]
+ public ContextOptions ContextOptions
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets an user credential that are used for binding to the Server (domain controller or local machine).
+ ///
+ [Parameter]
+ public PSCredential Credential
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets an user identity to remove.
+ ///
+ [Parameter]
+ public SwitchParameter ComputersOnly
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a value that specifies whether the account may be delegated.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter DelegationPermitted
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a descriptive comment for this user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string Description
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify whether this user account is enabled or disabled.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter Enabled
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a display name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string DisplayName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a E-mail address of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string EmailAddress
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a employee ID of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string EmployeeId
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a given name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string GivenName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a Home directory of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string HomeDirectory
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a Home drive of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string HomeDrive
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a middle name of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string MiddleName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a user name for the user account.
+ ///
+ [Parameter(
+ ValueFromPipeline = true,
+ ValueFromPipelineByPropertyName = true)]
+ [ValidateNotNullOrEmpty]
+ [ValidateLength(1, 20)]
+ public string Name
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify that the new User account has no password.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter PasswordNotRequired
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify that the password will not expire.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter PasswordNeverExpires
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a container on the store to use as the root of the context.
+ /// All queries are performed under this root, and all inserts are performed into this container.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string Path
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a SAM account name for the user account.
+ ///
+ [Parameter(
+ Position = 0,
+ ValueFromPipelineByPropertyName = true)]
+ public string SamAccountName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a server/machine or domain controller where the user account will be searched from.
+ ///
+ [Parameter]
+ public string Server
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a surname of the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string SurName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to specify whether the user is allowed to change the password on the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter UserCannotChangePassword
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a user principal name (UPN) associated with the user account.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public string UserPrincipalName
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets a switch to search expired user accounts.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter AccountExpired
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// ProcessRecord method.
+ ///
+ protected override void ProcessRecord()
+ {
+ try
+ {
+ var bindingUserName = Credential?.UserName;
+ var bindingUserPassword = Credential == null ? null : new System.Net.NetworkCredential(string.Empty, Credential.Password).Password;
+ var options = this.MyInvocation.BoundParameters.ContainsKey(nameof(ContextOptions)) ? ContextOptions : DefaultContextOptions.GetDefaultOptionForStore(AccountStore);
+ using var principalContext = new PrincipalContext(contextType: AccountStore, name: Server, container: Path, options, bindingUserName, bindingUserPassword);
+ UserPrincipal user = new UserPrincipal(principalContext);
+
+ if (AccountStore == ContextType.Machine)
+ {
+ user = new UserPrincipal(principalContext);
+ SetMachineUserPrincipalProperties(user);
+
+ if (AccountExpired.IsPresent)
+ {
+ user.AdvancedSearchFilter.AccountExpirationDate(DateTime.Now, MatchType.LessThan);
+ }
+ }
+ else
+ {
+ var psuser = new PowerShellUserPrincipal(principalContext);
+ SetADUserPrincipalProperties(psuser);
+
+ if (AccountExpired.IsPresent)
+ {
+ psuser.AdvancedSearchFilter.AccountExpired();
+ }
+
+ user = psuser;
+ }
+
+ PrincipalSearcher ps = new PrincipalSearcher(user);
+
+ PrincipalSearchResult results = ps.FindAll();
+
+ foreach (var principal in results)
+ {
+ WriteObject(principal);
+ }
+ }
+ catch (Exception ex)
+ {
+ WriteError(
+ new ErrorRecord(
+ ex,
+ "InvalidValue",
+ ErrorCategory.InvalidOperation,
+ null));
+ }
+ }
+
+ private void SetMachineUserPrincipalProperties(UserPrincipal userPrincipal)
+ {
+ foreach (var parameter in this.MyInvocation.BoundParameters)
+ {
+ switch (parameter.Key)
+ {
+ case "Name":
+ userPrincipal.Name = Name;
+ break;
+ case "Description":
+ userPrincipal.Description = Description;
+ break;
+ case "DisplayName":
+ userPrincipal.DisplayName = DisplayName;
+ break;
+ case "Enabled":
+ userPrincipal.Enabled = Enabled;
+ break;
+ case "PasswordNotRequired":
+ userPrincipal.PasswordNotRequired = PasswordNotRequired;
+ break;
+ case "PasswordNeverExpires":
+ userPrincipal.PasswordNeverExpires = PasswordNeverExpires;
+ break;
+ case "SamAccountName":
+ userPrincipal.SamAccountName = SamAccountName;
+ break;
+ case "UserCannotChangePassword":
+ userPrincipal.UserCannotChangePassword = UserCannotChangePassword;
+ break;
+ }
+ }
+ }
+
+ private void SetADUserPrincipalProperties(UserPrincipal userPrincipal)
+ {
+ foreach (var parameter in this.MyInvocation.BoundParameters)
+ {
+ switch (parameter.Key)
+ {
+ case "Name":
+ userPrincipal.Name = Name;
+ break;
+ case "DelegationPermitted":
+ userPrincipal.DelegationPermitted = DelegationPermitted;
+ break;
+ case "Description":
+ userPrincipal.Description = Description;
+ break;
+ case "DisplayName":
+ userPrincipal.DisplayName = DisplayName;
+ break;
+ case "Enabled":
+ userPrincipal.Enabled = Enabled;
+ break;
+ case "EmployeeId":
+ userPrincipal.EmployeeId = EmployeeId;
+ break;
+ case "EmailAddress":
+ userPrincipal.EmailAddress = EmailAddress;
+ break;
+ case "GivenName":
+ userPrincipal.GivenName = GivenName;
+ break;
+ case "HomeDirectory":
+ userPrincipal.HomeDirectory = HomeDirectory;
+ break;
+ case "HomeDrive":
+ userPrincipal.HomeDrive = HomeDrive;
+ break;
+ case "MiddleName":
+ userPrincipal.MiddleName = MiddleName;
+ break;
+ case "PasswordNotRequired":
+ userPrincipal.PasswordNotRequired = PasswordNotRequired;
+ break;
+ case "PasswordNeverExpires":
+ userPrincipal.PasswordNeverExpires = PasswordNeverExpires;
+ break;
+ case "SamAccountName":
+ userPrincipal.SamAccountName = SamAccountName;
+ break;
+ case "SurName":
+ userPrincipal.Surname = SurName;
+ break;
+ case "UserCannotChangePassword":
+ userPrincipal.UserCannotChangePassword = UserCannotChangePassword;
+ break;
+ case "UserPrincipalName":
+ userPrincipal.UserPrincipalName = UserPrincipalName;
+ break;
+ }
+ }
+ }
+ }
+
+ ///
+ ///
+ ///
+ public class PowerShellPrincipalSearchFilter : AdvancedFilters
+ {
+ ///
+ ///
+ ///
+ public PowerShellPrincipalSearchFilter(Principal p) : base(p)
+ {
+ }
+
+ ///
+ ///
+ ///
+ public void AccountExpired()
+ {
+ this.AdvancedFilterSet("accountExpires", DateTimeToADString(DateTime.Now), typeof(int), MatchType.LessThan);
+ //this.AdvancedFilterSet("accountExpires", 0, typeof(int), MatchType.Equals);
+ }
+
+ internal static string DateTimeToADString(DateTime dateTime)
+ {
+ // DateTime --> FILETIME --> stringized FILETIME
+
+ long fileTime = dateTime.ToFileTimeUtc();
+
+ return fileTime.ToString(System.Globalization.CultureInfo.InvariantCulture);
+ }
+ }
+
+ ///
+ ///
+ ///
+ [DirectoryObjectClass("user")]
+ [DirectoryRdnPrefix("CN")]
+ public class PowerShellUserPrincipal : UserPrincipal
+ {
+ ///
+ ///
+ ///
+ public PowerShellUserPrincipal(PrincipalContext context)
+ : base(context)
+ { }
+
+ ///
+ ///
+ ///
+ public PowerShellUserPrincipal(PrincipalContext context,
+ string samAccountName,
+ string password,
+ bool enabled)
+ : base(context, samAccountName, password, enabled)
+ { }
+
+ PowerShellPrincipalSearchFilter _searchFilter;
+
+ ///
+ ///
+ ///
+ new public PowerShellPrincipalSearchFilter AdvancedSearchFilter
+ {
+ get { return _searchFilter ?? (_searchFilter = new PowerShellPrincipalSearchFilter(this)); }
+ }
+ }
+}
diff --git a/src/Microsoft.PowerShell.AccountManagement/resources/NewUserStrings.resx b/src/Microsoft.PowerShell.AccountManagement/resources/NewUserStrings.resx
new file mode 100644
index 00000000000..0c6fa1de8f7
--- /dev/null
+++ b/src/Microsoft.PowerShell.AccountManagement/resources/NewUserStrings.resx
@@ -0,0 +1,234 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Access denied.
+
+
+ Account {0} was not found.
+
+
+ Add member {0}
+
+
+ Disable local user
+
+
+ Enable local user
+
+
+ Create new local group
+
+
+ Create new local user
+
+
+ Remove local group
+
+
+ Remove member {0}
+
+
+ Remove local user
+
+
+ Rename local group to {0}
+
+
+ Rename local user to {0}
+
+
+ Modify local group
+
+
+ Modify local user
+
+
+ Group {0} already exists.
+
+
+ The group {0} still has members.
+
+
+ Group {0} was not found.
+
+
+ The operation is not allowed for group {0}.
+
+
+ The operation is not allowed for user {0}.
+
+
+ The name {0} is invalid.
+
+
+ Parameter {0} and parameter {1} may not be used together.
+
+
+ Invalid password.
+
+
+ Cannot remove the last Administrator
+
+
+ {0} is already a member of group {1}.
+
+
+ Member {0} was not found in group {1}.
+
+
+ User {0} may not be removed from its primary group.
+
+
+ The name {0} is already in use.
+
+
+ Group
+
+
+ Other
+
+
+ User
+
+
+ The password cannot be set because a password restriction is in place.
+
+
+ Principal {0} was not found.
+
+
+ RID {0} was not found.
+
+
+ An unspecified error occurred.
+
+
+ An unspecified error occurred: status = {0}
+
+
+ An unspecified error occurred: error code = {0}
+
+
+ User {0} already exists.
+
+
+ User {0} was not found.
+
+
diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
index 3d1e7d3e92e..9ff53066ef8 100644
--- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
+++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
@@ -7,6 +7,7 @@
+
diff --git a/src/Modules/Windows/Microsoft.PowerShell.AccountManagement/Microsoft.PowerShell.AccountManagement.psd1 b/src/Modules/Windows/Microsoft.PowerShell.AccountManagement/Microsoft.PowerShell.AccountManagement.psd1
new file mode 100644
index 00000000000..6bcfaa6d546
--- /dev/null
+++ b/src/Modules/Windows/Microsoft.PowerShell.AccountManagement/Microsoft.PowerShell.AccountManagement.psd1
@@ -0,0 +1,14 @@
+@{
+GUID="149658ad-65f1-4949-a657-1eebcce72656"
+Author="PowerShell"
+CompanyName="Microsoft Corporation"
+Copyright="Copyright (c) Microsoft Corporation. All rights reserved."
+ModuleVersion="1.0.0.0"
+CompatiblePSEditions = @("Core")
+PowerShellVersion="6.0"
+FunctionsToExport = @()
+CmdletsToExport= "Get-User", "Remove-User", "New-User", "Search-Account"
+AliasesToExport = @()
+NestedModules="Microsoft.PowerShell.AccountManagement.dll"
+HelpInfoURI = ''
+}
diff --git a/src/System.Management.Automation/engine/ParameterBinderBase.cs b/src/System.Management.Automation/engine/ParameterBinderBase.cs
index 8edc637b3cf..9f3dbd2cf0e 100644
--- a/src/System.Management.Automation/engine/ParameterBinderBase.cs
+++ b/src/System.Management.Automation/engine/ParameterBinderBase.cs
@@ -1267,9 +1267,20 @@ private object CoerceTypeAsNeeded(
}
}
+ string str = "null";
+ try
+ {
+ str = (result == null) ? str : result.ToString();
+ }
+ catch
+ {
+ // Sometimes ToString() can throw.
+ // This is not a reason to break the binding.
+ }
+
bindingTracer.WriteLine(
"CONVERT SUCCESSFUL using LanguagePrimitives.ConvertTo: [{0}]",
- (result == null) ? "null" : result.ToString());
+ str);
} while (false);
}
catch (NotSupportedException notSupported)
diff --git a/test/powershell/Modules/Microsoft.PowerShell.AccountManagement/AccountManagement.User.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.AccountManagement/AccountManagement.User.Tests.ps1
new file mode 100644
index 00000000000..4548fe43e56
--- /dev/null
+++ b/test/powershell/Modules/Microsoft.PowerShell.AccountManagement/AccountManagement.User.Tests.ps1
@@ -0,0 +1,184 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+try {
+ #skip all tests on non-windows platform
+ $originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
+ $PSDefaultParameterValues["it:skip"] = !$IsWindows
+
+ Describe "Validate AccountManagement user cmdlets" -Tags @('CI', 'RequireAdminOnWindows') {
+
+ BeforeAll {
+ $Password = ([char[]]([char]33..[char]95) + ([char[]]([char]97..[char]126)) + 0..9 | Sort-Object {Get-Random})[0..12] -join ''
+ $pwd = (New-Object -TypeName Net.NetworkCredential("", $Password)).SecurePassword
+ }
+
+ Context "Validate New-User" {
+
+ AfterEach {
+ if ($IsWindows) {
+ $null = net user TestUserNew /delete *>1
+ }
+ }
+
+ It "Can create New-User with only name" {
+ $result = New-User -Name TestUserNew -PasswordNotRequired -AccountStore Machine
+
+ $result.Name | Should -BeExactly TestUserNew
+ $result.Description | Should -BeNullOrEmpty
+
+ # New account is disabled by default
+ $result.Enabled | Should -BeFalse
+ $result.SID | Should -Not -BeNullOrEmpty
+ }
+
+ It "Can create New-User with password" {
+ $result = New-User -Name TestUserNew -AccountStore Machine -Password $pwd
+
+ $result.Name | Should -BeExactly TestUserNew
+ }
+
+ It "Can create New-User with explicit properties in local machine" {
+ $result = New-User -AccountStore Machine `
+ -Name TestUserNew `
+ -PasswordNotRequired `
+ -AccountNeverExpires `
+ -Description "desc" `
+ -DisplayName "disp" `
+ -SamAccountName "samq2" `
+ -UserCannotChangePassword `
+ -PasswordNeverExpires `
+ -Enabled
+
+ # For AccountStore == Machine if we set SamAccountName we get Name the same.
+ $result.Name | Should -BeExactly "samq2"
+ $result.PasswordNotRequired | Should -BeTrue
+ $result.AccountExpirationDate | Should -Be $null
+ $result.Description | Should -BeExactly "desc"
+ $result.DisplayName | Should -BeExactly "disp"
+ $result.SamAccountName | Should -BeExactly "samq2"
+ $result.UserCannotChangePassword | Should -BeTrue
+ $result.PasswordNeverExpires | Should -BeTrue
+ # Account is disable because PasswordNotRequired is set.
+ $result.Enabled | Should -BeFalse
+ }
+
+ It "Can create New-User with explicit properties in a domain" -Pending:$true {
+ # The test works only with ActiveDirectory so skip it.
+ $result = New-User -AccountStore Machine `
+ -Name TestUserNew `
+ -PasswordNotRequired `
+ -AccountNeverExpires `
+ -AccountStore Domain `
+ -DelegationPermitted `
+ -Description "desc" `
+ -DisplayName "disp" `
+ -EmailAddress "email@domain.com" `
+ -EmployeeId "empl" `
+ -GivenName "gn" `
+ -HomeDirectory "hd" `
+ -HomeDrive "hdrv" `
+ -MiddleName "mn" `
+ -SamAccountName "samq2" `
+ -SurName "sn" `
+ -UserCannotChangePassword `
+ -PasswordNeverExpires `
+ -Enabled
+
+ $result.Name | Should -BeExactly TestUserNew
+ $result.PasswordNotRequired | Should -BeTrue
+ $result.AccountExpirationDate | Should -Be $null
+ $result.DelegationPermitted | Should -BeTrue
+ $result.Description | Should -BeExactly "desc"
+ $result.DisplayName | Should -BeExactly "disp"
+ $result.EmailAddress | Should -BeExactly "email@domain.com"
+ $result.EmployeeId | Should -BeExactly "empl"
+ $result.GivenName | Should -BeExactly "gn"
+ $result.HomeDirectory | Should -BeExactly "hd"
+ $result.HomeDrive | Should -BeExactly "hdrv"
+ $result.MiddleName | Should -BeExactly "mn"
+ $result.SamAccountName | Should -BeExactly "samq2"
+ $result.SurName | Should -BeExactly "sn"
+ $result.UserCannotChangePassword | Should -BeTrue
+ $result.PasswordNeverExpires | Should -BeTrue
+ $result.Enabled | Should -BeTrue
+ }
+
+ It "Errors on Name argument of empty string, null, spaces" {
+ { New-User -Name "" -PasswordNotRequired -ErrorAction Stop } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.NewUserCommand"
+ { New-User -Name $null -PasswordNotRequired -ErrorAction Stop } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.NewUserCommand"
+ { New-User -Name " " -PasswordNotRequired -ErrorAction Stop } | Should -Throw -ErrorId "InvalidValue,Microsoft.PowerShell.Commands.NewUserCommand"
+ }
+
+ It "Error on user exists" {
+ $result = New-User -Name TestUserNew -PasswordNotRequired -AccountStore Machine
+ $exc = { New-User -Name TestUserNew -PasswordNotRequired -AccountStore Machine -ErrorAction Stop } | Should -PassThru -Throw -ErrorId "InvalidValue,Microsoft.PowerShell.Commands.NewUserCommand"
+ $exc.Exception | Should -BeOfType "System.DirectoryServices.AccountManagement.PrincipalExistsException"
+ }
+ }
+
+ Context "Validate Remove-User" {
+ AfterAll {
+ if ($IsWindows) {
+ $null = net user TestUserNew /delete *>1
+ }
+ }
+
+ BeforeEach {
+ if ($IsWindows) {
+ $userIdentity = New-User -Name TestUserNew -AccountStore Machine -Password $pwd
+ }
+ }
+
+ It "Can remove user account with pipeline" {
+ { $userIdentity | Remove-User -ErrorAction Stop } | Should -Not -Throw
+ $err = net user TestUserNew *>&1 | Out-String
+ $err | Should -BeLike "The user name could not be found*"
+ { $userIdentity | Remove-User -ErrorAction Stop } | Should -Throw -ErrorId "UserAlreadyRemoved,Microsoft.PowerShell.Commands.RemoveUserCommand"
+ }
+
+ It "Can remove user account with parameter" {
+ { Remove-User -Identity $userIdentity -ErrorAction Stop } | Should -Not -Throw
+ $err = net user TestUserNew *>&1 | Out-String
+ $err | Should -BeLike "The user name could not be found*"
+ { Remove-User -Identity $userIdentity -ErrorAction Stop } | Should -Throw -ErrorId "UserAlreadyRemoved,Microsoft.PowerShell.Commands.RemoveUserCommand"
+ }
+ }
+
+ Context "Validate Get-User" {
+ BeforeAll {
+ if ($IsWindows) {
+ $users = Get-User -AccountStore Machine
+ $userPrincipal = $users[0]
+ }
+ }
+
+ It "Can get user accounts" {
+ $users.Count | Should -BeGreaterThan 0
+ $users[0].Name | Should -Not -BeNullOrEmpty
+ $users[0].Sid | Should -Not -BeNullOrEmpty
+ $users[0].SamAccountName | Should -Not -BeNullOrEmpty
+ }
+
+ It "Can get user account with a parameter: " -TestCases: @(
+ @{ paramName = "Name"; argument = @{ Name = $userPrincipal.Name } }
+ @{ paramName = "SamAccountName"; argument = @{ SamAccountName = $userPrincipal.SamAccountName } }
+ ){
+ param ($paramName, $argument)
+
+ $users.Count | Should -BeGreaterThan 0
+
+ $u = Get-User @argument -AccountStore Machine
+
+ $u.Name | Should -BeExactly $userPrincipal.Name
+ $u.Sid | Should -BeExactly $userPrincipal.Sid
+ $u.SamAccountName | Should -BeExactly $userPrincipal.SamAccountName
+ $u.Description | Should -BeExactly $userPrincipal.Description
+ $u.DisplayName | Should -BeExactly $userPrincipal.DisplayName
+ }
+ }
+ }
+}
+finally {
+ $global:PSDefaultParameterValues = $originalDefaultParameterValues
+}