开发者

PowerShell script runs from the shell, but not from my application

I am trying to create a Windows Application that will be able to run a variety of Powershell scripts.

I have a script which works as it should (when run from the Powershell prompt), and my Windows Application seems to execute it like it should, but it is unable to find the methods on my OU.

When I execute the script from the Windows Application, I get these messages out:

ERROR: The following exception occurred while retrieving member "Create": "There is no such object on the server. "

ERROR: The following exception occurred while retrieving member "Delete": "There is no such object on the server."

Powershell script:

function New-AdUser {

param (
    [string] $Username = $(throw "Parameter -Username [System.String] is required."),
    [string] $Password = $(throw "Parameter -Password [System.String] is required."),
    [string] $OrganizationalUnit = "Users",
    [string] $DisplayName,

    [string] $FirstName,

    [string] $LastName,

    [string] $Initials,
[string] $MobilePhone,
    [string] $Description,
    [switch] $CannotChangePassword,

    [switch] $PasswordNeverExpires,
    [switch] $Disabled

)

try {

    $currentDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()

    $dn = $currentDomain.GetDirectoryEntry().distinguishedName
    $ou = [ADSI] "LDAP://CN=$OrganizationalUnit,$dn"

    $userAccount = $ou.Create("user", "cn=$Username")

    $userAccount.SetInfo()



    $userAccount.userAccountControl = ($userAccount.userAccountControl.Item(0) -bxor 0x0002) #Enable the account

    $userAccount.SetInfo()


    $userAccount.sAMAccountName = $Username

    $userAccount.SetInfo()

    $userAccount.userPrincipalName = ("{0}@{1}" -f $Username, $currentDomain.Name)

    if ($DisplayName) {

        $userAccount.displayName = $DisplayName
    }

    if ($Description) {

        $userAccount.description = $Description
    }

    if ($FirstName) {

        $userAccount.givenName = $FirstName
    }


    if ($LastName) {
        $userAccount.SN = $LastName

    }


    if ($Initials) {

        $userAccount.initials = $Initials

    }



if ($MobilePhone) {
        $userAccount.mobile = $MobilePhone

}


    $userAccount.SetInfo()


    $userAccount.SetPassword($Password)

    # Password

    if ($PasswordNeverExpires) {

        $userAccount.userAccountControl = ($userAccount.userAccountControl.Item(0) -bxor 0x10000)
    }


    if ($CannotChangePassword) {
        $everyOne = [System.Security.Principal.SecurityIdentifier]'S-1-1-0'
        $EveryoneDeny = new-object System.DirectoryServices.ActiveDirectoryAccessRule ($Everyone,'ExtendedRight','Deny', [System.Guid]'ab721a53-1e2f-11d0-9819-00aa0040529b')
        $self = [System.Security.Principal.SecurityIdentifier]'S-1-5-10'
        $SelfDeny = new-object System.DirectoryServices.ActiveDirectoryAccessRule ($self,'ExtendedRight','Deny', [System.Guid]'ab721a53-1e2f-11d0-9819-00aa0040529b')

        $userAccount.get_ObjectSecurity().AddAccessRule($selfDeny)

       $userAccount.get_ObjectSecurity().AddAccessRule($EveryoneDeny)


       $userAccount.CommitChanges()
    }

    $userAccount.SetInfo()


    if ($Disabled) {
        $userAccount.userAccountControl = ($userAccount.userAccountControl.Item(0) -bxor 0x0002)

    }
    $userAccount.SetInfo()

} catch {

    Write-Error $_

    $ou.Delete("user", "cn=$Username")

    return $false

}

return $true

}

The C# code I have is this:

PowerShell ps = PowerShell.Create();

            ps.AddScript(GetScript("New-AdUser.ps1"));
            ps.Invoke();

            ps.AddCommand("New-AdUser").AddParameters(
                new List<CommandParameter>() {
                    new CommandParameter("Username", username),
                    new CommandParameter("Password", password),
                    new CommandParameter("FirstName", firstName),
                    new CommandParameter("LastName", lastName),
                    new CommandParameter("DisplayName", realName),
                    new CommandParameter("Initials", initials),
                    new CommandParameter("MobilePhone", mobilePhone),
                    new CommandParameter("OrganizationalUnit", "Users"),
                    new CommandParameter("PasswordNeverExpires")
                }
            );

            var results = ps.Invoke();

            fo开发者_如何学运维reach (var obj in results)
                Console.WriteLine(obj.ToString());

            if (ps.Streams.Error.Count > 0)
            {
                foreach (var err in ps.Streams.Error)
                    Console.WriteLine("ERROR: {0}", err.ToString());
            }


Seems that you are just creating a user in AD. By having the c# code calling a powershell script, you are adding another moving part in your script. Why not call it directly in C# code. Check this MSDN article.


The problem appears to be that the Create method on your ADSI object, $ou, doesn't exist. I would check that it is getting created properly. Run the script outside your application to ensure that it works, or have an extra line that displays its members:

$ou | Get-Member


It almost appears as though the Runspace in the application is being created with a restrictive RunspaceConfiguration, so it can't find System.DirectoryServices for the AD functionality you need.

What do you get when you run the following within in your application?

string script = @"[AppDomain]::CurrentDomain.GetAssemblies()";
PowerShell ps = new PowerShell();
ps.AddScript(script);
var output = ps.Invoke();
foreach (var a in output.Select(pso => (System.Reflection.Assembly)pso.BaseObject))
    Console.WriteLine("Assembly: " + a.FullName);

When I run that under the debugger in a plain console application I get 28 assemblies (19 outside the debugger), including System.DirectoryServices. The [AppDomain]::CurrentDomain.GetAssemblies() bit shows 16 when I run it on a vanilla command prompt. System.DirectoryServices shows up in all three lists.


When run from within C# I found that I need to add the PowerShell snap-in "Microsoft.Windows.AD" before being able to run the cmdlet's it provides.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜