public void WriteVarsAndToolsToProfile()
        {
            // backup profile if already exists
            string profile_path = PowerShell.Execute("$PROFILE").Trim();

            if (File.Exists(profile_path))
            {
                string profilecontent = File.ReadAllText(profile_path);
                File.WriteAllText(Path.Combine(Path.GetDirectoryName(profile_path), "profile_backup.txt"), profilecontent);
            }

            // assemble the profile using the program's resources
            string        vars_dir = Path.Combine(resource_root_path, "vars");
            List <string> lines    = new List <string>();

            Array.ForEach(Directory.GetFiles(Path.Combine(resource_root_path, "vars")),
                          (x) => lines.AddRange(
                              File.ReadAllLines(x).Select((y) => y.Replace("[USER]", configuration["USER"]).Replace("[DISK]", configuration["DISK"]))));


            Array.ForEach(Directory.GetFiles(Path.Combine(resource_root_path, "tools")),
                          (x) => lines.AddRange(
                              File.ReadAllLines(x).Select((y) =>
                                                          y.Replace("[EXPLORER]", configuration["EXPLORER"])
                                                          .Replace("[CODE-EDITOR]", configuration["CODE-EDITOR"])
                                                          .Replace("[android-studio-exe]", configuration["android-studio-exe"])
                                                          .Replace("{{{utils}}}", configuration["utils"])
                                                          )));

            // create the profile if this does not exist
            CreateProfilePathIfNotExists();
            File.WriteAllLines(profile_path, lines);
        }
Beispiel #2
0
        public List <int> Execute(string samplesfilepath)
        {
            string pshcmd = String.Format("{0}\\overlap_compute.exe {1} {2}",
                                          GConfig.TOOL_OVERLAP_COMPUTE_PATH,
                                          Path.GetDirectoryName(samplesfilepath),
                                          Path.GetFileName(samplesfilepath));

            PowerShell.Execute(pshcmd,
                               false,
                               Path.GetDirectoryName(samplesfilepath));

            string resultFileName = Path.Combine(
                Path.GetDirectoryName(samplesfilepath),
                resultfile_prefix + Path.GetFileName(samplesfilepath));

            try
            {
                List <int> lst = SpaceSeparatedFileParser.ParseInt(resultFileName);
                return(lst);
            }
            catch (Exception ex)
            {
                File.Delete(resultFileName);
                throw ex;
            }
        }
Beispiel #3
0
        public static bool ReserveUrlForNonAdministratorUsersAndAccounts(int port, string scheme = "http", string host = "+")
        {
            string command;
            string result;

            command = $"netsh http show urlacl url={scheme}://{host}:{port}/";
            result  = CommandPrompt.Execute(command);
            if (result.Contains("Reserved URL"))
            {
                Logger.Log("Url Reservation", $"Url {scheme}://{host}:{port}/ already has a reservation.");
                return(true);
            }

            command = $"netsh http add urlacl {scheme}://{host}:{port}/ user=$env:UserName";
            try {
                result = PowerShell.Execute(command, administrator: true);
            } catch (UnauthorizedAccessException ex) {
                Logger.Log("Exception", ex.Message);
                Logger.Log("Napaka", "Nimate administratorskih pravic.", toLog: false);
                return(false);
            }

            bool success = result.Contains("URL reservation successfully added");

            if (success)
            {
                Logger.Log("Url Reservation", $"Url {scheme}://{host}:{port}/ reserved.");
            }

            return(success);
        }
Beispiel #4
0
        public List <int> Execute(string dmrfilepath, string samplesfilepath)
        {
            string pshcmd = String.Format("{0}\\underground_filter.exe {1} {2} {3} {4}",
                                          GConfig.TOOL_UNDERGROUND_FILTER_PATH,
                                          Path.GetDirectoryName(dmrfilepath),
                                          Path.GetFileName(dmrfilepath),
                                          Path.GetDirectoryName(samplesfilepath),
                                          Path.GetFileName(samplesfilepath));

            PowerShell.Execute(pshcmd,
                               false,
                               Path.GetDirectoryName(samplesfilepath));

            string resultFileName = Path.Combine(
                Path.GetDirectoryName(samplesfilepath),
                "underground" + Path.GetFileName(samplesfilepath));

            try
            {
                List <int> lst = SpaceSeparatedFileParser.ParseInt(resultFileName);
                return(lst);
            }
            catch (Exception ex)
            {
                File.Delete(resultFileName);
                throw ex;
            }
        }
 public static void Exec(string folder_name, string filepath, string outpath, string attributes)
 {
     PowerShell.Execute(String.Format("las2txt -i {0} -o {1} -parse {2}",
                                      filepath,
                                      outpath,
                                      attributes),
                        false,
                        folder_name);
 }
Beispiel #6
0
        public void AsText()
        {
            // Verify that any TTY color escape commands are removed.

            using (var powershell = new PowerShell())
            {
                var result = powershell.Execute("Get-ChildItem");

                Assert.NotEmpty(result);
                Assert.DoesNotContain("\x1b[", result);
                Assert.DoesNotContain("\u001b[", result);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Ensures that the native Windows OpenSSH client is installed, prompting
        /// the user to install it if necessary.
        /// </summary>
        /// <returns><c>true</c> if OpenSSH is installed.</returns>
        public static async Task <bool> EnsureOpenSshAsync()
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            Log.Info("Checking for native Windows OpenSSH client");

            var openSshPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Sysnative", "OpenSSH", "ssh.exe");

            if (!File.Exists(openSshPath))
            {
                Log.WriteLine("Raspberry debugging requires the native Windows OpenSSH client.  See this:");
                Log.WriteLine("https://techcommunity.microsoft.com/t5/itops-talk-blog/installing-and-configuring-openssh-on-windows-server-2019/ba-p/309540");

                var button = MessageBox.Show(
                    "Raspberry debugging requires the Windows OpenSSH client.\r\n\r\nWould you like to install this now (restart required)?",
                    "Windows OpenSSH Client Required",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question,
                    MessageBoxDefaultButton.Button2);

                if (button != DialogResult.Yes)
                {
                    return(false);
                }

                // Install via Powershell: https://techcommunity.microsoft.com/t5/itops-talk-blog/installing-and-configuring-openssh-on-windows-server-2019/ba-p/309540

                await PackageHelper.ExecuteWithProgressAsync("Installing OpenSSH Client",
                                                             async() =>
                {
                    using (var powershell = new PowerShell())
                    {
                        Log.Info("Installing OpenSSH");
                        Log.Info(powershell.Execute("Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0"));
                    }

                    await Task.CompletedTask;
                });

                MessageBox.Show(
                    "Restart Windows to complete the OpenSSH Client installation.",
                    "Restart Required",
                    MessageBoxButtons.OK);

                return(false);
            }
            else
            {
                return(true);
            }
        }
Beispiel #8
0
        /// <summary>
        /// accepts a .pcd file, returns the result filepath
        /// </summary>
        public string Execute(string filepath, string resultfile_prefix, double[] radius_values)
        {
            string pshcmd = String.Format("{0}\\rbnn.exe {1} {2} {3} ",
                                          GConfig.TOOL_RBNN_PATH,
                                          Path.GetDirectoryName(filepath),
                                          Path.GetFileName(filepath),
                                          resultfile_prefix);

            pshcmd += string.Join(" ", radius_values);
            PowerShell.Execute(pshcmd,
                               true,
                               Path.GetDirectoryName(filepath));
            return(Path.Combine(Path.GetDirectoryName(filepath), resultfile_prefix) + Path.GetFileName(filepath));
        }
Beispiel #9
0
        private static void envvarlist(string searchstring)
        {
            string profile_path = PowerShell.Execute("$PROFILE").Trim();

            string[] lines       = File.ReadAllLines(profile_path);
            string[] found_lines = lines.Where(
                (x) => {
                if (x.Contains("$") && x.Contains(searchstring))
                {
                    return(true);
                }
                return(false);
            }).ToArray();
            found_lines.ToList().Sort();
            found_lines.ToList().ForEach((x) => Console.WriteLine(x));
        }
        public static bool OpenFirewallPort(string name, int port, string dir = "in", string action = "allow", string protocol = "TCP", string profile = "private")
        {
            string command;
            string result;

            command = $"netsh advfirewall firewall show rule name={name}";
            result  = PowerShell.Execute(command);
            if (!result.Contains("No rules match the specified criteria."))
            {
                if (Regex.IsMatch(result, $@"LocalPort:.*{port}{Environment.NewLine}"))
                {
                    Logger.Log("Firewall", $"Port {port} already opened.");
                    return(true);
                }
                else
                {
                    command = $"netsh advfirewall firewall delete rule name={name}";
                    try {
                        result = PowerShell.Execute(command, administrator: true);
                    } catch (UnauthorizedAccessException ex) {
                        Logger.Log("Exception", ex.Message);
                        Logger.Log("Napaka", "Nimate administratorskih pravic.", toLog: false);
                        return(false);
                    }
                }
            }

            command = $"netsh advfirewall firewall add rule name={name} dir=in action={action} protocol={protocol} profile={profile} localport={port}";
            try {
                result = PowerShell.Execute(command, administrator: true);
            } catch (UnauthorizedAccessException ex) {
                Logger.Log("Exception", ex.Message);
                Logger.Log("Napaka", "Nimate administratorskih pravic.", toLog: false);
                return(false);
            }

            bool success = result.Contains("Ok.");

            if (success)
            {
                Logger.Log("Firewall", $"Opened port {port}.");
            }

            return(success);
        }
Beispiel #11
0
        /// <summary>
        /// Executes a PowerShell command that returns a simple string result.
        /// </summary>
        /// <param name="command">The command string.</param>
        /// <param name="noEnvironmentVars">
        /// Optionally disables that environment variable subsitution (defaults to <c>false</c>).
        /// </param>
        /// <param name="logOutput">Enables logging of standard output (errors are always logged).</param>
        /// <returns>The command response.</returns>
        /// <exception cref="PowerShellException">Thrown if the command failed.</exception>
        /// <exception cref="NotImplementedException">Thrown for non-Windows operating system where PowerShell isn't available.</exception>
        public string PowerShellExecute(string command, bool noEnvironmentVars = false, bool logOutput = false)
        {
            if (PowerShell == null)
            {
                throw new NotImplementedException("PowerShell is not available on the current operating system.");
            }

            PushLogEnable(logOutput);

            try
            {
                return(PowerShell.Execute(command, noEnvironmentVars));
            }
            finally
            {
                PopLogEnable();
            }
        }
        private void CreateProfilePathIfNotExists()
        {
            string profile_path = PowerShell.Execute("$PROFILE");

            string[] parts = profile_path.Split("\\");

            Func <int, string> assemble_parts = (max) => {
                return(string.Join('\\', parts.Take(max)));
            };

            for (int i = 1; i < parts.Length - 2; i++)
            {
                string str = assemble_parts(parts.Length - i);
                if (!Directory.Exists(str))
                {
                    Directory.CreateDirectory(str);
                    Console.WriteLine($"Created directory {assemble_parts(parts.Length - i)}");
                }
            }
        }
        public void ExecuteTest(string[] args)
        {
            // load up some augmentables in AugmentableSampleResultFormat
            string str = File.ReadAllText(source_file);
            List <AugmentableObjectSample> samples = PointCloudiaFormatDeserializer.AugmentableSampleResultFormat(str);
            string pbbmdf = PointCloudiaFormatSerializer.PointBoundingBoxAndMaxDimFormat(samples);

            File.WriteAllText(pbbmdf_save_file, pbbmdf);

            string pythonscriptsdir            = @"C:\Users\km\Desktop\playground\pycharmprojects\floating_object_segmentation_scripts\other\";
            string pbmdftolidar_path           = Path.Combine(pythonscriptsdir, "PBBMDF_to_lidar.py");
            string lidar_to_number_per_line    = Path.Combine(pythonscriptsdir, "lidar_to_number_per_line.py");
            string lidar_to_dummy_rbnn_results = Path.Combine(pythonscriptsdir, "lidar_to_dummy_rbnn_results.py");
            string merge_two_lidars            = Path.Combine(pythonscriptsdir, "merge_two_lidars.py");

            // use python script to transform to lidar format
            PowerShell.Execute($"python {pbmdftolidar_path} {dmrlidar} {pbbmdf_save_file} {Path.Combine(TEST_SUBSUBDIR, "lidar_pbbmdf")} 1");
            PowerShell.Execute($"python {merge_two_lidars} {dmrlidar} {Path.Combine(TEST_SUBSUBDIR, "lidar_pbbmdf")} {Path.Combine(TEST_SUBSUBDIR, "result.txt")}");
            PowerShell.Execute($"python {lidar_to_number_per_line} {Path.Combine(TEST_SUBSUBDIR, "result.txt")} {Path.Combine(TEST_SUBSUBDIR, "resultintensity.txt")} 0");
            PowerShell.Execute($"python {lidar_to_number_per_line} {Path.Combine(TEST_SUBSUBDIR, "result.txt")} {Path.Combine(TEST_SUBSUBDIR, "resultclass.txt")} 0");
            PowerShell.Execute($"python {lidar_to_dummy_rbnn_results} {Path.Combine(TEST_SUBSUBDIR, "result.txt")} {Path.Combine(TEST_SUBSUBDIR, "resultrbnn.txt")}");
        }
Beispiel #14
0
#pragma warning restore CA1416

        /// <summary>
        /// Creates a virtual machine.
        /// </summary>
        /// <param name="machineName">The machine name.</param>
        /// <param name="memorySize">
        /// A string specifying the memory size.  This can be a long byte count or a
        /// byte count or a number with units like <b>512MiB</b>, <b>0.5GiB</b>, <b>2GiB</b>,
        /// or <b>1TiB</b>.  This defaults to <b>2GiB</b>.
        /// </param>
        /// <param name="processorCount">
        /// The number of virutal processors to assign to the machine.  This defaults to <b>4</b>.
        /// </param>
        /// <param name="driveSize">
        /// A string specifying the primary disk size.  This can be a long byte count or a
        /// byte count or a number with units like <b>512MB</b>, <b>0.5GiB</b>, <b>2GiB</b>,
        /// or <b>1TiB</b>.  Pass <c>null</c> to leave the disk alone.  This defaults to <c>null</c>.
        /// </param>
        /// <param name="drivePath">
        /// Optionally specifies the path where the virtual hard drive will be located.  Pass
        /// <c>null</c> or empty to default to <b>MACHINE-NAME.vhdx</b> located in the default
        /// Hyper-V virtual machine drive folder.
        /// </param>
        /// <param name="checkpointDrives">Optionally enables drive checkpoints.  This defaults to <c>false</c>.</param>
        /// <param name="templateDrivePath">
        /// If this is specified and <paramref name="drivePath"/> is not <c>null</c> then
        /// the hard drive template at <paramref name="templateDrivePath"/> will be copied
        /// to <paramref name="drivePath"/> before creating the machine.
        /// </param>
        /// <param name="switchName">Optional name of the virtual switch.</param>
        /// <param name="extraDrives">
        /// Optionally specifies any additional virtual drives to be created and
        /// then attached to the new virtual machine.
        /// </param>
        /// <remarks>
        /// <note>
        /// The <see cref="VirtualDrive.Path"/> property of <paramref name="extraDrives"/> may be
        /// passed as <c>null</c> or empty.  In this case, the drive name will default to
        /// being located in the standard Hyper-V virtual drivers folder and will be named
        /// <b>MACHINE-NAME-#.vhdx</b>, where <b>#</b> is the one-based index of the drive
        /// in the enumeration.
        /// </note>
        /// </remarks>
        public void AddVm(
            string machineName,
            string memorySize        = "2GiB",
            int processorCount       = 4,
            string driveSize         = null,
            string drivePath         = null,
            bool checkpointDrives    = false,
            string templateDrivePath = null,
            string switchName        = null,
            IEnumerable <VirtualDrive> extraDrives = null)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(machineName), nameof(machineName));
            CheckDisposed();

            memorySize = ByteUnits.Parse(memorySize).ToString();

            if (driveSize != null)
            {
                driveSize = ByteUnits.Parse(driveSize).ToString();
            }

            var driveFolder = DefaultDriveFolder;

            if (string.IsNullOrEmpty(drivePath))
            {
                drivePath = Path.Combine(driveFolder, $"{machineName}-[0].vhdx");
            }
            else
            {
                driveFolder = Path.GetDirectoryName(Path.GetFullPath(drivePath));
            }

            if (VmExists(machineName))
            {
                throw new HyperVException($"Virtual machine [{machineName}] already exists.");
            }

            // Copy the template VHDX file.

            if (templateDrivePath != null)
            {
                File.Copy(templateDrivePath, drivePath);
            }

            // Resize the VHDX if requested.

            if (driveSize != null)
            {
                powershell.Execute($"{HyperVNamespace}Resize-VHD -Path '{drivePath}' -SizeBytes {driveSize}");
            }

            // Create the virtual machine.

            var command = $"{HyperVNamespace}New-VM -Name '{machineName}' -MemoryStartupBytes {memorySize}  -Generation 1";

            if (!string.IsNullOrEmpty(drivePath))
            {
                command += $" -VHDPath '{drivePath}'";
            }

            if (!string.IsNullOrEmpty(switchName))
            {
                command += $" -SwitchName '{switchName}'";
            }

            try
            {
                powershell.Execute(command);
            }
            catch (Exception e)
            {
                throw new HyperVException(e.Message, e);
            }

            // We need to configure the VM's processor count and min/max memory settings.

            try
            {
                powershell.Execute($"{HyperVNamespace}Set-VM -Name '{machineName}' -ProcessorCount {processorCount} -StaticMemory -MemoryStartupBytes {memorySize}");
            }
            catch (Exception e)
            {
                throw new HyperVException(e.Message, e);
            }

            // Create and attach any additional drives as required.

            if (extraDrives != null)
            {
                var diskNumber = 1;

                foreach (var drive in extraDrives)
                {
                    if (string.IsNullOrEmpty(drive.Path))
                    {
                        drive.Path = Path.Combine(driveFolder, $"{machineName}-[{diskNumber}].vhdx");
                    }

                    if (drive.Size <= 0)
                    {
                        throw new ArgumentException("Virtual drive size must be greater than 0.", nameof(drive));
                    }

                    NeonHelper.DeleteFile(drive.Path);

                    var fixedOrDynamic = drive.IsDynamic ? "-Dynamic" : "-Fixed";

                    try
                    {
                        powershell.Execute($"{HyperVNamespace}New-VHD -Path '{drive.Path}' {fixedOrDynamic} -SizeBytes {drive.Size} -BlockSizeBytes 1MB");
                        powershell.Execute($"{HyperVNamespace}Add-VMHardDiskDrive -VMName '{machineName}' -Path \"{drive.Path}\"");
                    }
                    catch (Exception e)
                    {
                        throw new HyperVException(e.Message, e);
                    }

                    diskNumber++;
                }
            }

            // Windows 10 releases since the August 2017 Creators Update enable automatic
            // virtual drive checkpointing (which is annoying).  We're going to disable this
            // by default.

            if (!checkpointDrives)
            {
                try
                {
                    powershell.Execute($"{HyperVNamespace}Set-VM -CheckpointType Disabled -Name '{machineName}'");
                }
                catch (Exception e)
                {
                    throw new HyperVException(e.Message, e);
                }
            }

            // We need to do some extra configuration for nested virtual machines:
            //
            //      https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/nested-virtualization

            if (IsNestedVirtualization)
            {
                // Enable nested virtualization for the VM.

                powershell.Execute($"{HyperVNamespace}Set-VMProcessor -VMName '{machineName}' -ExposeVirtualizationExtensions $true");

                // Enable MAC address spoofing for the VMs network adapter.

                powershell.Execute($"{HyperVNamespace}Set-VMNetworkAdapter -VMName '{machineName}' -MacAddressSpoofing On");
            }
        }
Beispiel #15
0
        /// <summary>
        /// Creates a virtual machine.
        /// </summary>
        /// <param name="machineName">The machine name.</param>
        /// <param name="memorySize">
        /// A string specifying the memory size.  This can be a long byte count or a
        /// byte count or a number with units like <b>512MB</b>, <b>0.5GB</b>, <b>2GB</b>,
        /// or <b>1TB</b>.  This defaults to <b>2GB</b>.
        /// </param>
        /// <param name="minimumMemorySize">
        /// Optionally specifies the minimum memory size.  This defaults to <c>null</c> which will
        /// set this to <paramref name="memorySize"/>.
        /// </param>
        /// <param name="processorCount">
        /// The number of virutal processors to assign to the machine.  This defaults to <b>4</b>.
        /// </param>
        /// <param name="diskSize">
        /// A string specifying the primary disk size.  This can be a long byte count or a
        /// byte count or a number with units like <b>512MB</b>, <b>0.5GB</b>, <b>2GB</b>,
        /// or <b>1TB</b>.  This defaults to <b>64GB</b>.
        /// </param>
        /// <param name="drivePath">
        /// Optionally specifies the path where the virtual hard drive will be located.  Pass
        /// <c>null</c> or empty to default to <b>MACHINE-NAME.vhdx</b> located in the default
        /// Hyper-V virtual machine drive folder.
        /// </param>
        /// <param name="checkpointDrives">Optionally enables drive checkpoints.  This defaults to <c>false</c>.</param>
        /// <param name="templateDrivePath">
        /// If this is specified and <paramref name="drivePath"/> is not <c>null</c> then
        /// the hard drive template at <paramref name="templateDrivePath"/> will be copied
        /// to <paramref name="drivePath"/> before creating the machine.
        /// </param>
        /// <param name="switchName">Optional name of the virtual switch.</param>
        /// <param name="extraDrives">
        /// Optionally specifies any additional virtual drives to be created and
        /// then attached to the new virtual machine (e.g. for Ceph OSD).
        /// </param>
        /// <remarks>
        /// <note>
        /// The <see cref="VirtualDrive.Path"/> property of <paramref name="extraDrives"/> may be
        /// passed as <c>null</c> or empty.  In this case, the drive name will default to
        /// being located in the standard Hyper-V virtual drivers folder and will be named
        /// <b>MACHINE-NAME-#.vhdx</b>, where <b>#</b> is the one-based index of the drive
        /// in the enumeration.
        /// </note>
        /// </remarks>
        public void AddVM(
            string machineName,
            string memorySize        = "2GB",
            string minimumMemorySize = null,
            int processorCount       = 4,
            string diskSize          = "64GB",
            string drivePath         = null,
            bool checkpointDrives    = false,
            string templateDrivePath = null,
            string switchName        = null,
            IEnumerable <VirtualDrive> extraDrives = null)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(machineName));
            CheckDisposed();

            if (string.IsNullOrEmpty(minimumMemorySize))
            {
                minimumMemorySize = memorySize;
            }

            var driveFolder = DefaultDriveFolder;

            if (string.IsNullOrEmpty(drivePath))
            {
                drivePath = Path.Combine(driveFolder, $"{machineName}-[0].vhdx");
            }
            else
            {
                driveFolder = Path.GetDirectoryName(Path.GetFullPath(drivePath));
            }

            if (VMExists(machineName))
            {
                throw new HyperVException($"Virtual machine [{machineName}] already exists.");
            }

            // Copy the template VHDX file.

            if (templateDrivePath != null)
            {
                File.Copy(templateDrivePath, drivePath);
            }

            // Resize the VHDX.

            // $hack(jeff.lill):
            //
            // For some reason, the PowerShell [Resize-VHD] command does not like
            // hard disk file names formatted as we're doing (e.g. with embedded
            // square brackets).  We're going to work around this by temporarily
            // renaming the disk file while we're resizing it.

            var tempDrivePath = Path.Combine(driveFolder, Guid.NewGuid().ToString("D") + ".vhdx");

            File.Move(drivePath, tempDrivePath);

            try
            {
                powershell.Execute($"Resize-VHD -Path \"{tempDrivePath}\" -SizeBytes {diskSize}");
            }
            catch (Exception e)
            {
                throw new HyperVException(e.Message, e);
            }
            finally
            {
                // Restore the drive to its original file name.

                File.Move(tempDrivePath, drivePath);
            }

            // Create the virtual machine.

            var command = $"New-VM -Name \"{machineName}\" -MemoryStartupBytes {minimumMemorySize} -Generation 1";

            if (!string.IsNullOrEmpty(drivePath))
            {
                command += $" -VHDPath \"{drivePath}\"";
            }

            if (!string.IsNullOrEmpty(switchName))
            {
                command += $" -SwitchName \"{switchName}\"";
            }

            try
            {
                powershell.Execute(command);
            }
            catch (Exception e)
            {
                throw new HyperVException(e.Message, e);
            }

            // We need to configure the VM's processor count and min/max memory settings.

            try
            {
                powershell.Execute($"Set-VM -Name \"{machineName}\" -ProcessorCount {processorCount} -MemoryMinimumBytes {minimumMemorySize} -MemoryMaximumBytes {memorySize}");
            }
            catch (Exception e)
            {
                throw new HyperVException(e.Message, e);
            }

            // Create and attach any additional drives as required.

            if (extraDrives != null)
            {
                var diskNumber = 1;

                foreach (var drive in extraDrives)
                {
                    if (string.IsNullOrEmpty(drive.Path))
                    {
                        drive.Path = Path.Combine(driveFolder, $"{machineName}-[{diskNumber}].vhdx");
                    }

                    if (drive.Size <= 0)
                    {
                        throw new ArgumentException("Virtual drive size must be greater than 0.");
                    }

                    if (File.Exists(drive.Path))
                    {
                        File.Delete(drive.Path);
                    }

                    var fixedOrDynamic = drive.IsDynamic ? "-Dynamic" : "-Fixed";

                    try
                    {
                        powershell.Execute($"New-VHD -Path \"{drive.Path}\" {fixedOrDynamic} -SizeBytes {drive.Size} -BlockSizeBytes 1MB");
                        powershell.Execute($"Add-VMHardDiskDrive -VMName \"{machineName}\" -Path \"{drive.Path}\"");
                    }
                    catch (Exception e)
                    {
                        throw new HyperVException(e.Message, e);
                    }

                    diskNumber++;
                }
            }

            // Windows 10 releases since the August 2017 Creators Update enable automatic
            // virtual drive checkpointing (which is annoying).

            if (!checkpointDrives)
            {
                try
                {
                    powershell.Execute($"Set-VM -CheckpointType Disabled -Name \"{machineName}\"");
                }
                catch (Exception e)
                {
                    throw new HyperVException(e.Message, e);
                }
            }
        }