0

I'm able to get a simple c# function to work, but when I introduce something more complicated such as what's below, I'm getting syntax errors and there isn't a lot of examples on how to do this.

I've made updates to the code based on advice received here, but this code still does not function properly

cls


$dagDistribution = $null;

        $distribution = 
        @'

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Management.Automation;
    using System.Management.Automation.Runspaces;
    using System.Security;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Threading;
    using System.Collections.Concurrent;
    using System.Diagnostics;
    using System.Security.Principal;    


    namespace MultiThreading
    {

        public class dagDistribution
        {

            public List<string> get(string dag)
            {
                DateTime start = DateTime.Now;

                var response = new ConcurrentBag<Collection<PSObject>>();
                var exceptions = new ConcurrentQueue<Exception>();

                string dagName = "hqdag1";

                string[] serversUnsorted = getDagMembers(dagName);
                var servers = from s in serversUnsorted orderby s select s;

                try
                {
                    Parallel.ForEach(servers, server =>
                    {
                        response.Add(runPowerShellScript(server));
                    });
                }
                catch (AggregateException ae)
                {
                    foreach (var aex in ae.InnerExceptions)
                    {
                        exceptions.Enqueue(aex);
                    }
                }

                List<string> returnValues = new List<string>();
                foreach (var item in response)
                {
                    string returnValue = parseServerResults(item);
                    returnValues.Add(returnValue);
                }

                returnValues.Sort();
                return returnValues;
            }

            private Collection<PSObject> runPowerShellScript(object server)
            {
                Collection<PSObject> psobjs = new Collection<PSObject>();
                string result = "";
                string serverName = server.ToString();

                WSManConnectionInfo wmc = new WSManConnectionInfo(new Uri("http://xxx/powershell"));
                wmc.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
                wmc.ShellUri = "http://schemas.microsoft.com/powershell/Microsoft.Exchange";

                using (Runspace runspace = RunspaceFactory.CreateRunspace(wmc))
                {
                    PowerShell powershell = PowerShell.Create();

                    if (runspace.RunspaceStateInfo.State == RunspaceState.Opened)
                    {
                        // do nothing
                    }
                    else
                    {
                        runspace.Open();
                        powershell.Runspace = runspace;
                    }

                    try
                    {
                        PSCommand command = new PSCommand();
                        command.AddScript("get-mailboxdatabase -Server " + server + " -Status");
                        powershell.Commands = command;                    
                        psobjs = powershell.Invoke();

                        if (powershell.HadErrors == true)
                        {
                            result = "Failed - " + powershell.Streams.Error[0].ToString();
                            result = result.Replace("\"", "*");
                        }
                    }
                    catch (Exception ex)
                    {
                        string fail = ex.Message;
                    }
                }
                object serverNameO = server;
                PSObject serverNameObj = new PSObject(serverNameO);
                psobjs.Insert(0, serverNameObj);

                return psobjs;
            }

            private string[] getDagMembers(string dagName)
            {
                Collection<PSObject> psobjs = new Collection<PSObject>();
                string result = "";
                string[] servers = null;

                WSManConnectionInfo wmc = new WSManConnectionInfo(new Uri("http://xxx/powershell"));
                wmc.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
                wmc.ShellUri = "http://schemas.microsoft.com/powershell/Microsoft.Exchange";


                using (Runspace runspace = RunspaceFactory.CreateRunspace(wmc))
                {
                    PowerShell powershell = PowerShell.Create();

                    if (runspace.RunspaceStateInfo.State == RunspaceState.Opened)
                    {
                        // do nothing
                    }
                    else
                    {
                        runspace.Open();
                        powershell.Runspace = runspace;
                    }

                    try
                    {
                        PSCommand command = new PSCommand();
                        command.AddScript("Get-DatabaseAvailabilityGroup -Identity " + dagName);
                        powershell.Commands = command;
                        psobjs = powershell.Invoke();

                        if (powershell.HadErrors == true)
                        {
                            result = "Failed - " + powershell.Streams.Error[0].ToString();
                            result = result.Replace("\"", "*");
                        }

                        PSPropertyInfo serversTemp = null;
                        foreach (PSObject psobj in psobjs)
                        {
                            serversTemp = psobj.Properties["servers"];
                        }

                        string s_servers = serversTemp.Value.ToString();
                        servers = s_servers.Split(' ');

                    }
                    catch (Exception ex)
                    {
                        string fail = ex.Message;
                    }
                }            

                return servers;
            }

        private string parseServerResults(Collection<PSObject> serverObjs) // needs servername, totaldbs, activedbs, passivedbs, preferencecount (11,11,11,11), mounteddbs, dismounteddbs, dagname
        {
            // called independently with each server, first object is always the server name

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            int index = 0;
            string returnValue = "";

            string serverName = "";
            int totalDbs = 0;
            int activeDbs = 0; // whichever has activation preference 1
            int passiveDbs = 0; // whichever has activation preference 2, 3 or 4       
            string activeCopyServerName = "";
            int activationPreferenceOne = 0;
            int activationPreferenceTwo = 0;
            int activationPreferenceThree = 0;
            int activationPreferenceFour = 0;
            int mountedCount = 0;
            int dismountedCount = 0;
            string dagName = "";
            string dagServerAndDatabaseName = "";

            foreach (PSObject obj in serverObjs)
            {
                if (index == 0)
                {
                    serverName = obj.ToString();
                }

                totalDbs = (serverObjs.Count - 1);

                PSMemberInfoCollection<PSPropertyInfo> props = obj.Properties;

                string currentPrimaryActivationServer = "";
                foreach (PSPropertyInfo prop in props)
                {
                    if (prop.Name == "MountedOnServer")
                    {
                        currentPrimaryActivationServer = prop.Value.ToString();
                        break;
                    }
                }

                List<string> propertyNames = new List<string>();
                foreach (PSPropertyInfo prop in props)
                {
                    string result = prop.Name + " | " + prop.Value;

                    if (prop.Name == "Mounted")
                    {
                        if (prop.Value.ToString() == "True")
                        {
                            if (currentPrimaryActivationServer.ToLower().StartsWith(serverName.ToLower()))
                            {
                                mountedCount++;
                            }
                        }
                        else
                        {
                            dismountedCount++;
                        }
                    }
                    else if (prop.Name == "MountedOnServer")
                    {
                        activeCopyServerName = prop.Value.ToString();
                    }
                    else if (prop.Name == "ActivationPreference")
                    {
                        string arr = prop.Value.ToString();
                        string[] vals = arr.Split(']');

                        foreach (string val in vals)
                        {
                            if (val != "")
                            {
                                string valTemp = val;
                                if (val.Contains("["))
                                {
                                    valTemp = val.Replace("[", "");
                                }

                                string[] preference = valTemp.Split(',');

                                string preferenceZero = preference[0].ToString().Trim();
                                string preferenceOne = preference[1].ToString().Trim();

                                if (preferenceZero.ToLower() == serverName.ToLower())
                                {
                                    if (preferenceOne == "1")
                                    {
                                        if (currentPrimaryActivationServer.ToLower().StartsWith(serverName.ToLower()))
                                        {
                                            activeDbs++;
                                        }
                                        else
                                        {
                                            passiveDbs++;
                                        }
                                    }
                                    else
                                    {
                                        if (!(currentPrimaryActivationServer.ToLower().StartsWith(serverName.ToLower())))
                                        {
                                            passiveDbs++;
                                        }
                                        else
                                        {
                                            activeDbs++;
                                        }
                                    }

                                    switch (preferenceOne)
                                    {
                                        case "1":
                                            activationPreferenceOne++;
                                            break;

                                        case "2":
                                            activationPreferenceTwo++;
                                            break;

                                        case "3":
                                            activationPreferenceThree++;
                                            break;

                                        case "4":
                                            activationPreferenceFour++;
                                            break;

                                        default:
                                            break;
                                    }
                                }
                            }
                        }
                    }
                    else if (prop.Name == "Server")
                    {
                        string activeCopyServerName2 = prop.Value.ToString();
                    }
                    else if (prop.Name == "MasterServerOrAvailabilityGroup")
                    {
                        dagName = prop.Value.ToString();
                    }
                    else if (prop.Name == "MailboxProvisioningAttributes")
                    {
                        dagServerAndDatabaseName = prop.Value.ToString();
                    }

                    propertyNames.Add(prop.Name.ToString()); // cumulative count of the property names
                }

                index++;
            }

            stopwatch.Stop();
            Console.WriteLine(serverName + " - " + stopwatch.Elapsed.ToString());

            return returnValue = serverName + "|" + totalDbs + "|" + activeDbs + "|" + passiveDbs + "|" + activationPreferenceOne + "," + activationPreferenceTwo + "," +
                activationPreferenceThree + "," + activationPreferenceFour + "|" + mountedCount + "|" + dismountedCount + "|" + dagName;
        }



        }
    }
'@

write-host "after here-string";

Add-Type -TypeDefinition $distribution -ReferencedAssemblies System.Collections, System.ComponentModel, System.Data, System.Drawing, System.Linq, System.Management.Automation, System.Security, System.Threading.Tasks, System.Windows.Forms, System.Threading, System.Collections.Concurrent, System.Security.Principal



$dagDistribution = New-Object MultiThreading.dagDistribution;

$val = $dagDistribution.get("dag2");
2
  • 1
    $@"..." defines a verbatim interpolated string. Why are you doing that? You're not using interpolation or escape characters in the strings. Commented Aug 30, 2018 at 13:44
  • That was an example I saw when searching on the internet, I have since corrected that as it was not needed. Commented Aug 30, 2018 at 18:23

1 Answer 1

7

You have two problems. Probably really just one. By default Add-Type uses the C# version 5 compiler, which is the latest one to be included in Windows. The string interpolation with $ is a newer feature. See this answer Powershell Add-Type C# 6.0.

Second, you have powershell escape characters in your C# code that shouldn't be there. Instead use a literal here-string to include arbitrary C# source. EG:

   $distribution = @'
    namespace MultiThreading
    {

        ....
    }

'@

C# has no "special" way to reference .NET Framework types, so you have to provide the compiler with a list of assemblies your code depends on.

Add-Type will use will use the current .NET Framework assemblies if you specify the "short name" of the assembly in the -ReferencedAssemblies argument. So:

Add-Type -TypeDefinition $distribution -ReferencedAssemblies System.Data, System.Xml

If you need an assembly that can't be resolved this way, you have to list the Assembly FullName, and Add-Type will try to load it.

You definitely want to avoid putting a full AssemblyName for a .NET Framework assembly in your powershell code, as that might cause your script to break when running on a machine with a different .NET Framework version, or with .NET Core.

Sign up to request clarification or add additional context in comments.

11 Comments

If I understand you correctly, changing the @" ... "@ to @' ... '@ and also changing the commands to command.AddScript("get-mailboxdatabase -Server " + server + " -Status"); and command.AddScript("Get-DatabaseAvailabilityGroup -Identity " + dagName); will correct my syntax errors? I'm getting a bunch of namespace errors now, so I believe I need something like $Assem = ( "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=????") and then Add-Type -ReferencedAssemblies $Assem -TypeDefinition $distribution -Language CSharp ; Is this correct?
I thought Add-Type uses whatever the latest .NET Framework install has with it?
With my newly updated first post, have I understood your advice correctly? My code still does not run with what is posted above, it will get namespace errors. Once I get it functioning well, I will trim the number of assemblies needed.
Those are genuine C# compilation errors. You should start with code that compiles in Visual Studio, Visual Studio Code, or with csc.exe before pasting into powershell.
One error, for instance is, cannot declare instance members in a static class which would be the same in VS.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.