According to the Microsoft.PowerShell.LocalAccounts module documentation:
This module is not available in 32-bit PowerShell on a 64-bit system.
If one attempts to run one's application as 32-bit on a 64-bit Windows operating system, then one receives the following error messages:
Error: The specified module 'Microsoft.PowerShell.LocalAccounts' was not loaded because no valid module file was found in any module directory.
Error: The term 'New-LocalUser' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
As others have stated, the code in the OP works if one runs one's application as 64-bit, when running on a 64-bit operating system. Add the following code before the code in the OP:
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
throw new NotSupportedException("This module is not available in 32-bit PowerShell on a 64-bit system. See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts for more information.");
}
While not related to the issue that you've describe in the OP, the code in the OP doesn't add the user to a group such as "Users", so the user won't be able to logon. It may be necessary to add the following code to the code in the OP:
Add-LocalGroupMember -Group 'Users' -Member 'TestUser'
The code below demonstrates an alternative to Add-Script. You'll notice that the code contains a check to ensure that if one is running the application on a 64-bit operating system that the application is running as 64-bit.
If you still receive an error message and your application is running as 64-bit when running on a 64-bit operating system, then verify that %windir%\System32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.LocalAccounts\1.0.0.0\Microsoft.PowerShell.LocalAccounts.dll exists.
The following shows how to use Nuget package Microsoft.PowerShell.SDK (v7.5.2) to add a local user to a computer. Some of the steps you mentioned that you already did, but I'll include them for future readers.
First, one needs to determine the .NET version supported by a particular version of Nuget package Microsoft.PowerShell.SDK (v7.5.2). Clicking on the previous URL, one sees that Microsoft.PowerShell.SDK verion 7.5.2 is supported in .NET 9.
Create a new Console App project (Framework: .NET 9) or Windows Forms App project (Framework: .NET 9)
Add an Application Manifest to your project
Note: This is used to prompt the user to execute the program as Administrator.
- In VS menu, click Project
- Select Add New Item...
- Select Application Manifest File (Windows Only) (name: app.manifest)
- Click Add
In app.manifest, replace
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
with
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Note: Ensure that you've configured NuGet Package Manager to use PackageReference in Visual Studio (before adding NuGet package(s)):
- In Visual Studio menu, click Tools
- Select Options...
- Expand NuGet Package Manager
- Select General
- Under Package Management, for Default package management format, select PackageReference.
- Click OK
Download and install NuGet package: Microsoft.PowerShell.SDK (v7.5.2)
In Solution Explorer, right-click <project name> and select Manage NuGet Packages...
Click Browse
In the search box type: Microsof.PowerShell.SDK
Select Microsoft.PowerShell.SDK
Select desired version (ex: 7.5.2)
Click Install
*Note: If a Preview Changes dialog box appears, click Apply. If a License Acceptance dialog box appears, choose I Accept or I Decline. If you chose I Accept, continue below. If you chose I Decline, then you can stop reading this post since the information below assumes that the Nuget package was successfully installed (ie: that one has accepted the license agreement).
Add the following using directives:
private static string PSAddUser(string username, string password, string fullName, string description)
{
string result = string.Empty;
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
throw new NotSupportedException("This module is not available in 32-bit PowerShell on a 64-bit system. See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts for more information.");
}
InitialSessionState iss = InitialSessionState.CreateDefault2();
//set execution policy
iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.RemoteSigned;
//import module: Microsoft.PowerShell.LocalAccounts
//string localUserModuleFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "System32", "WindowsPowerShell", "v1.0", "Modules", "Microsoft.PowerShell.LocalAccounts", "1.0.0.0");
//iss.ImportPSModulesFromPath(localUserModuleFolder);
iss.ImportPSModule("Microsoft.PowerShell.LocalAccounts"); //this may be unnecessary
using (Runspace runspace = RunspaceFactory.CreateRunspace(iss))
{
//open
runspace.Open();
using (PowerShell ps = PowerShell.Create(runspace))
{
//it's not necessary to specify 'username', since only the password is used
SecureString secureStringPass = new NetworkCredential("", password).SecurePassword;
//SecureString secureStringPass = new NetworkCredential(username, password).SecurePassword;
ps.AddCommand("New-LocalUser")
.AddParameter("Name", username)
.AddParameter("FullName", fullName)
.AddParameter("Password", secureStringPass)
.AddParameter("Description", description);
//execute command
System.Collections.ObjectModel.Collection<PSObject> outputCollectionNewLocalUser = ps.Invoke();
//check if any errors/exceptions exist
if (ps.HadErrors)
{
//read errors
foreach (ErrorRecord error in ps.Streams.Error)
{
//ToDo: add desired code (if desired, throw exception)
result += $"Error: {error.ToString()}{Environment.NewLine}";
}
}
//read output (ie: StandardOutput)
foreach (PSObject outputItem in outputCollectionNewLocalUser)
{
//create reference
string? data = outputItem.BaseObject?.ToString();
if (!String.IsNullOrEmpty(data))
result += $"{data}{Environment.NewLine}";
}
ps.Commands.Clear(); //clear previous command(s)
ps.Streams.Error.Clear(); //clear any previous error(s)
//add to 'Users' group (or any other desired group)
ps.AddCommand("Add-LocalGroupMember")
.AddParameter("Group", "Users")
.AddParameter("Member", username);
//execute command
System.Collections.ObjectModel.Collection<PSObject> outputCollectionAddLocalGroupMember = ps.Invoke();
//Add-LocalGroupMember doesn't produce any output unless there's an error
//so there's no need to read outputCollection
//check if any errors/exceptions exist
if (ps.HadErrors)
{
//read errors
foreach (ErrorRecord error in ps.Streams.Error)
{
//ToDo: add desired code (if desired, throw exception)
result += $"Error: {error.ToString()}{Environment.NewLine}";
}
}
}
}
return result;
}
Usage:
//get assembly (ie: application) name
string? applicationName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
string description = string.Empty;
if (!String.IsNullOrEmpty(applicationName))
description = $"Created by {applicationName}";
String result = PSAddUser("TestUser, "Password123!", "Test User", description);
Debug.WriteLine(result);
Resources:
.csprojto this question ?ps.AddCommand("Get-LocalUser").AddCommand("Out-String")and not seeing any problem.