Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ buildtasks
artifacts
robots.txt
syntax: regexp
(?i)src/.*bin/.*
(?i)src/.*bin/.*
.idea
/src/Orchard-Core/bin
/src/*/bin
1 change: 1 addition & 0 deletions AddPathToPSModulePath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ $paths = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine").Split(
if(!$paths.Contains($Path))
{
[System.Environment]::SetEnvironmentVariable("PSModulePath", [string]::Join(";", $paths + $Path), "Machine")
[System.Environment]::SetEnvironmentVariable("LOMBIQ_UTILITY_SCRIPTS_PATH", $pwd.Path, "Machine")
Write-Information "The path `"$Path`" was successfully added to the PSModulePath environment variable."
}
else
Expand Down
10 changes: 4 additions & 6 deletions OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,21 @@ function Reset-OrchardCoreApp


# Trying to find IIS Express and .NET host processes that run a Web Project with a matching name and terminate them.
$siteHostProcessFilter = "(Name = 'iisexpress.exe' or Name = 'dotnet.exe') and CommandLine like '%$siteName%'"
$siteHostProcesses = Get-WmiObject Win32_Process -Filter $siteHostProcessFilter
Import-Module "$env:LOMBIQ_UTILITY_SCRIPTS_PATH\src\Lombiq.UtilityScripts.Utilities\bin\Debug\netstandard2.0\Lombiq.UtilityScripts.Utilities.dll"
$siteHostProcesses = Get-ProcessByArgument $siteName

if ($siteHostProcesses -ne $null -or $siteHostProcesses.Count -gt 0)
if ($siteHostProcesses.Count -gt 0)
{
foreach ($siteHostProcess in $siteHostProcesses)
{
"Terminating application host process running `"$($siteHostProcess.CommandLine)`"!`n"

$siteHostProcess.Terminate() | Out-Null
$siteHostProcess.Process | Stop-Process
}

Start-Sleep 1
}



# Delete App_Data if exists.

$appDataPath = $("$WebProjectPath\App_Data")
Expand Down
69 changes: 69 additions & 0 deletions Utility-Scripts.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Common", "src\Lombiq.UtilityScripts.Common\Lombiq.UtilityScripts.Common.csproj", "{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.SqlServer", "src\Lombiq.UtilityScripts.SqlServer\Lombiq.UtilityScripts.SqlServer.csproj", "{79B8C1DD-ADBD-4266-B89A-D938D0614D50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Utilities", "src\Lombiq.UtilityScripts.Utilities\Lombiq.UtilityScripts.Utilities.csproj", "{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x64.ActiveCfg = Debug|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x64.Build.0 = Debug|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x86.ActiveCfg = Debug|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x86.Build.0 = Debug|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|Any CPU.Build.0 = Release|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x64.ActiveCfg = Release|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x64.Build.0 = Release|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x86.ActiveCfg = Release|Any CPU
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x86.Build.0 = Release|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|x64.ActiveCfg = Debug|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|x64.Build.0 = Debug|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|x86.ActiveCfg = Debug|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|x86.Build.0 = Debug|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|Any CPU.Build.0 = Release|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x64.ActiveCfg = Release|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x64.Build.0 = Release|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.ActiveCfg = Release|Any CPU
{79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.Build.0 = Release|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x64.ActiveCfg = Debug|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x64.Build.0 = Debug|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x86.ActiveCfg = Debug|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x86.Build.0 = Debug|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|Any CPU.Build.0 = Release|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x64.ActiveCfg = Release|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x64.Build.0 = Release|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x86.ActiveCfg = Release|Any CPU
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18}
{79B8C1DD-ADBD-4266-B89A-D938D0614D50} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18}
{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18}
EndGlobalSection
EndGlobal
62 changes: 62 additions & 0 deletions src/Lombiq.UtilityScripts.Common/Cmdlets/AsyncCmdletBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Management.Automation;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Lombiq.UtilityScripts.Common.Cmdlets
{
public abstract class AsyncCmdletBase : PSCmdlet
{
protected abstract string CmdletName { get; }

private ServiceProvider? _provider;
private IServiceProvider? _scopeProvider;

protected IServiceProvider ServiceProvider =>
_scopeProvider ?? _provider ?? throw new InvalidOperationException($"{nameof(BeginProcessing)} was not called!");

protected override void BeginProcessing()
{
var services = new ServiceCollection();
services.AddLogging(options => options.AddConsole());
services.AddSingleton<PSCmdlet>(this);
services.AddSingleton(this);

Configure(services);
_provider = services.BuildServiceProvider();
}

protected override void ProcessRecord()
{
try
{
if (_scopeProvider != null)
{
throw new InvalidOperationException("Overlapping scopes! This should not be possible.");
}

using var scope = ServiceProvider.CreateScope();
_scopeProvider = scope.ServiceProvider;

ProcessRecordAsync().Wait();

_scopeProvider = null;
}
catch (Exception exception)
{
Error(exception, ErrorCategory.NotSpecified);
}
}

protected override void EndProcessing() => _provider?.Dispose();

protected virtual void Configure(IServiceCollection services) { }

protected abstract Task ProcessRecordAsync();

protected void Info(string message) => WriteInformation(new InformationRecord(message, CmdletName));
protected void Error(Exception exception, ErrorCategory errorCategory) =>
WriteError(new ErrorRecord(exception, exception.GetType().Name, errorCategory, CmdletName));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CliWrap" Version="3.3.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0-preview-06">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Data.SqlClient;

namespace Lombiq.UtilityScripts.SqlServer.Cmdlets
{
public static class SqlConnectionExtensions
{
public static SqlCommand GetCommand(
this SqlConnection connection,
string commandText,
IDictionary<string, object>? parameters = null)
{
var command = connection.CreateCommand();
command.CommandText = commandText;

if (parameters != null)
{
foreach (var (name, value) in parameters)
{
command.Parameters.AddWithValue(name, value);
}
}

return command;
}

public static async IAsyncEnumerable<string> YieldStringColumnAsync(this SqlCommand command, int columnId = 0)
{
await using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
yield return reader.GetString(columnId);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Lombiq.UtilityScripts.Common\Lombiq.UtilityScripts.Common.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Data.SqlClient" Version="4.8.2" />
</ItemGroup>

</Project>
139 changes: 139 additions & 0 deletions src/Lombiq.UtilityScripts.SqlServer/Services/SqlServerManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;
using Lombiq.UtilityScripts.SqlServer.Cmdlets;
using Microsoft.Extensions.Logging;

namespace Lombiq.UtilityScripts.SqlServer.Services
{
public class SqlServerManager
{
private readonly ILogger<SqlServerManager> _logger;

public SqlServerManager(ILogger<SqlServerManager> logger)
{
_logger = logger;
}

public async Task<bool> CreateNewDatabase(
string sqlServerName,
string databaseName,
bool force = false,
string? userName = null,
string? password = null)
{
var connection = CreateNewConnection(sqlServerName, userName, password);
await connection.OpenAsync();

if (await TestDatabaseAsync(connection, databaseName))
{
if (force)
{
_logger.LogWarning("Dropping database \"{0}\\{1}\"!", sqlServerName, databaseName);
await KillAllProcessesAsync(connection, databaseName);
await connection.GetCommand("DROP " + databaseName).ExecuteNonQueryAsync();
}
else
{
_logger.LogWarning(
"A database with the name \"{0}\" already exists on the SQL Server at \"{1}\". Use the " +
"\"-Force\" switch to drop it and create a new database with that name.",
databaseName,
sqlServerName);

return false;
}
}

try
{
await connection.GetCommand($"CREATE DATABASE [{databaseName}];").ExecuteNonQueryAsync();
}
catch (Exception exception)
{
throw new InvalidOperationException(
$"Could not create \"{sqlServerName}\\{databaseName}\"! ({exception.Message})",
exception);
}

return true;
}

public SqlConnection CreateNewConnection(string sqlServerName, string? userName = null, string? password = null)
{
var builder = new SqlConnectionStringBuilder("Server=" + sqlServerName);

if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
{
builder.Password = userName;
builder.UserID = password;
}

return new SqlConnection(builder.ConnectionString);
}

public async Task<bool> TestServerAsync(SqlConnection connection)
{
try
{
if (connection.State != ConnectionState.Open)
{
await connection.CloseAsync();
await connection.OpenAsync();
}

var command = connection.CreateCommand();
command.CommandText = "SELECT 1";
return await command.ExecuteScalarAsync() is int response && response == 1;
}
catch
{
return false;
}
}

public async Task<bool> TestDatabaseAsync(SqlConnection connection, string databaseName)
{
// If success it also ensures that the connection is open.
if (!await TestServerAsync(connection))
{
throw new InvalidOperationException($"Could not find SQL Server for \"{nameof(connection.ConnectionString)}\"!");
}

await foreach (var name in connection.GetCommand("SELECT name FROM sys.databases").YieldStringColumnAsync())
{
if (name?.Equals(databaseName, StringComparison.OrdinalIgnoreCase) == true)
{
return true;
}
}

return false;
}

private async Task KillAllProcessesAsync(SqlConnection connection, string databaseName)
{
if (databaseName == null)
{
throw new ArgumentNullException(nameof(databaseName));
}

const string columnName = "columnName";
var commandText = connection.ServerVersion is { } serverVersion && new Version(serverVersion).Major == 8
? @$"SELECT DISTINCT req_spid as {columnName}
FROM master.dbo.syslockinfo
WHERE rsc_type = 2 AND rsc_dbid = db_id(@{nameof(databaseName)}) AND req_spid > 50"
: @$"SELECT DISTINCT request_session_id as {columnName}
FROM master.sys.dm_tran_locks
WHERE resource_type = 'DATABASE' AND resource_database_id = db_id(@{nameof(databaseName)})";

var targets = connection
.GetCommand(commandText, new Dictionary<string, object> { [nameof(databaseName)] = databaseName })
.YieldStringColumnAsync();

await foreach (var target in targets) await connection.GetCommand("KILL " + target).ExecuteNonQueryAsync();
}
}
}
Loading