How to create an IIS application pool and web site on Windows 10 with PowerShell and Visual Studio Code

Tasks to create an IIS application pool and web site on Windows 10 with PowerShell and Visual Studio Code:

  • Install the Visual Studio Code plugin PowerShell 0.6.2
  • Create a file iis.configuration.ps1 in Visual Studio Code:

    # Note: When run with the Visual Studio Code PowerShell debugger, make sure you use the "x64" debugger,
    #       else you will get an error: New-WebAppPool : Cannot retrieve the dynamic parameters for the cmdlet.

    Import-Module WebAdministration

    # Create application pools
    New-WebAppPool -Name "myapp.localhost" -Force

    # Create websites
    New-Website -Name "myapp.localhost" -Port 80 -HostHeader "myapp.localhost" -ApplicationPool "myapp.localhost" -PhysicalPath "c:\projects\myapp\web" -Force

        • Create a launch.json in the same folder as the iis.configuration.ps1:

          {
              "version": "0.2.0",
               "configurations": [
                  {
                      "name": "PowerShell",
                      "type": "PowerShell",
                      "request": "launch",
                      "program": "${workspaceRoot}/iis.configuration.ps1",
                      "args": [],
                      "cwd": "${workspaceRoot}/iis.configuration.ps1"
                  },
                   {
                      "name": "PowerShell x86",
                      "type": "PowerShell x86",
                      "request": "launch",
                      "program": "${workspaceRoot}/iis.configuration.ps1",
                      "args": [],
                      "cwd": "${workspaceRoot}/iis.configuration.ps1"
                  }
              ]
          }

          Now you can debug / run the iis.configuration.ps1 file, by hitting F5, make sure you selected “PowerShell” and not “PowerShell x86” on the debug tab:

          image

          Fix: Visual Studio 2013 / 2014–SQL Server 2014 – The term ‘Invoke-Sqlcmd’ is not recognized as the name of a cmdlet

           

          Note

          When you want to run / edit / debug PowerShell scripts inside Visual Studio 2013 / 2015 you will have to install the “PowerShell Tools for Visual Studio” Visual Studio extension found at: https://visualstudiogallery.msdn.microsoft.com/c9eb3ba8-0c59-4944-9a62-6eee37294597

           

          I wanted to run and debug a PowerShell script inside Visual Studio 2013 / 2015, on a machine that only had SQL Server 2014 installed as database server. This threw an exception: The term ‘Invoke-Sqlcmd’ is not recognized as the name of a cmdlet http://blog.sqlauthority.com/2014/11/23/sql-server-fix-the-term-invoke-sqlcmd-is-not-recognized-as-the-name-of-a-cmdlet/

           

          Turns out you have to update the PowerShell “PSModulePath”, so it can find the PowerShell modules containing the SQL Server 2014 cmdlets.

           

          Temp fix:

          http://stackoverflow.com/questions/29562742/invoke-sqlcmd-failing-after-automated-sql-install-with-powershell

          Existing Powershell session isn’t aware about Sql’s modules that were just installed. Take a look at environment variable $env:PSModulePath. Compare new shell’s variable to existing and you should see a missing path like …\Microsoft SQL Server\110\Tools\PowerShell\Modules\.
          For a work-around, modify the path to include module dir. Like so,

          $env:PSModulePath += ";C:\Program Files (x86)\Microsoft SQL Server\120\Tools\PowerShell\Modules"

           

          If you want to persist this extra “Module load path”, you have to change the registry:

          http://tomtalks.uk/2013/06/powershell-add-a-persistent-module-path-to-envpsmodulepath/

           

          image

           

          Now I can run and debug the following PowerShell script inside Visual Studio 2013 / 2015:

          # This sccript requires the system to allow running powershell scripts, when not allowed the following code can be used to allow running powershell scripts.
          # Set-ExecutionPolicy RemoteSigned
          # The following import statement enables the SQL Server PowerShell cmdlets, like "Invoke-Sqlcmd".
          Import-Module SqlPs
          $serverInstance = "(localdb)\v11.0"
          $database = "App"
          function ExecuteSqlFile {
          [string]$file = $args[0]
          Invoke-Sqlcmd -ServerInstance $serverInstance -Database $database -InputFile $file
          }
          ExecuteSqlFile('C:\Temp\test.sql')

          drop and create SQL Server tables based on an array with table names by using PowerShell

           

          # Add table names to the "$tables" array in the order they should be created.
          $tables = @(
          "dbo.Person",
          "dbo.Settings",
          "dbo.SmsStatus",
          "dbo.Sms"
          )
          # Create a table if it does not exist.
          # It expects the "create scripts" to be located in a subfolder "Tables".
          function CreateTable
          {
          [string]$table = $args[0]
          [string]$file = "{0}\Tables\{1}.sql" -f $PSScriptRoot, $table
          Echo("create table {0}" -f $table) 
          Invoke-Sqlcmd -ServerInstance "(localdb)\v11.0" -Database "MyDatabase" -InputFile $file
          }
          # Drop a table if it exists.
          function DropTable
          {
          [string]$table = $args[0]
          [string]$query = "if object_id('{0}') is not null begin drop table {0} end" -f $table
          Echo("drop table {0}" -f $table) 
          Invoke-Sqlcmd -ServerInstance "(localdb)\v11.0" -Database "MyDatabase" -Query $query
          }
          function DropTables
          {
          $reverseTable = $tables.Clone()
          [array]::Reverse($reverseTable)
          foreach ($table in $reverseTable) {
          DropTable $table
          }    
          }
          function CreateTables {
          foreach ($table in $tables) {
          CreateTable $table
          }
          }
          DropTables
          CreateTables
          

          Will drop all tables in $tables if they exist and then will create all tables in $tables if they do not exist.

          Use formatting–f, when writing to the output console with PowerShell

          If you want to format a string when echoing to the screen, use parentheses.

          Echo("This is {0} " -f "a test.")

           

          Will output:

          This is a test.

           

          Note

          http://stackoverflow.com/questions/17623644/what-is-the-difference-between-echo-and-write-host-in-powershell

          echo is an alias for Write-Output, which writes to the Success output stream. This allows output to be processed through pipelines or redirected into files. Write-Host writes directly to the console, so the output can’t be redirected/processed any further.

          ASP .NET MVC4 / Web Api – Create users and roles for SimpleMembershipProvider with PowerShell and C#

          If you are using the SimpleMembershipProvider for FormAuthentication in a ASP .NET MVC4 / Web Api project, the following PowerShell / C# code can be used to create and delete users and roles.

          • Create an empty XML App.config file "C:\Temp\App.config".
          • Paste the XML below in the file and save it.
          • Create an empty PowerShell file "C:\Temp\Manage_MVC_users_and_roles.ps1".
          • Paste the PowerShell code below in the file and save it.
          • Create an empty C# file "C:\Temp\Manage_MVC_users_and_roles.cs".
          • Paste the C# code below in the file and save it.
          • Execute the file "C:\Temp\Manage_MVC_users_and_roles.ps1" with PowerShell.

           

          This will create an user "test2" with password "test2" and a role "Administrators".

           

          Note

          • Database tables will automatically be created if they don’t exist.
          • De folder "C:\Temp" should contain the assemblies "System.Web.WebPages.dll" and "WebMatrix.Data.dll" and "WebMatrix.WebData.dll", this assembly can be downloaded using NuGet.

          App.config

          <?xml version="1.0" encoding="utf-8"?>
          <configuration>
          <system.web>
          <profile defaultProvider="SimpleProfileProvider">
          <providers>
          <add name="SimpleProfileProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData"
          connectionStringName="DefaultConnection" applicationName="/" />
          </providers>
          </profile>
          <membership defaultProvider="SimpleMembershipProvider">
          <providers>
          <add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
          </providers>
          </membership>
          <roleManager enabled="true" defaultProvider="SimpleRoleProvider">
          <providers>
          <add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData"/>
          </providers>
          </roleManager>
          </system.web>
          <runtime>
          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          </assemblyBinding>
          </runtime>
          </configuration>

          PowerShell code (Manage_MVC_users_and_roles.ps1)

           
          # Get folder containing this script.
          $scriptFolder = split-path $SCRIPT:MyInvocation.MyCommand.Path -parent
          # Load App.config file from scriptfolder.
          $appConfigPath = "$scriptFolder\App.config"
          [System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $appConfigPath)
          # Compile C# code to dll.
          $Assem = ( 
          "WebMatrix.Data", 
          "WebMatrix.WebData",
          "System.Security",
          "System.Web",
          "System.Web.WebPages",
          'System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
          'System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
          )
          $codePath = "$scriptFolder\Manage_MVC_users_and_roles.cs"
          $codeAssemblyName = "Manage_MVC_users_and_roles.dll"
          Add-Type -OutputType Library –ReferencedAssemblies $Assem -OutputAssembly $codeAssemblyName -Path $codePath
          # Load dll.
          $codeAssemblyPath = "$scriptFolder\$codeAssemblyName"
          Add-Type -Path $codeAssemblyPath
          # Execute C# code.
          $wrapper = New-Object Research.Rli.WebSecurityExecuter
          $wrapper.Execute($scriptFolder);
          pause
          

          C# code

          namespace Research.Rli
          {
          using System.Linq;
          public interface IWebSecurityExecuter
          {
          void Execute(string scriptFolder);
          }
          public class WebSecurityExecuter : IWebSecurityExecuter
          {
          /// <summary>
          /// Executes code found in the [WebSecurityWrapper] class in a new .net AppDomain, 
          /// To prevent assembly load errors, a new AppDomain is created, with the ApplicationBase set to the folder containing this *.cs file.
          /// </summary>
          /// <param name="scriptFolder">
          /// Folder containing this *.cs file.
          /// </param>
          public void Execute(string scriptFolder)
          {
          System.AppDomain childDomain = null;
          try
          {
          var domainSetup = new System.AppDomainSetup()
          {
          ApplicationBase = scriptFolder,
          ConfigurationFile = System.AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
          ApplicationName = System.AppDomain.CurrentDomain.SetupInformation.ApplicationName,
          LoaderOptimization = System.LoaderOptimization.MultiDomainHost
          };
          childDomain = System.AppDomain.CreateDomain("NewAppDomain", null, domainSetup);
          IWebSecurityWrapper wrapper = (IWebSecurityWrapper)childDomain.CreateInstanceAndUnwrap(typeof(WebSecurityWrapper).Assembly.FullName, typeof(WebSecurityWrapper).FullName);
          wrapper.Initialize();
          wrapper.CreateUsers();
          wrapper.CreateRoles();
          }
          finally
          {
          if (childDomain != null) System.AppDomain.Unload(childDomain);
          }
          }
          }
          public class WebSecurityWrapper : System.MarshalByRefObject, IWebSecurityWrapper
          {
          /// <summary>
          /// Initializes the database connection and creates tabels, when these tables do not exist.
          /// </summary>
          public void Initialize()
          {
          DatabaseConnectionString = @"Data Source=(LocalDb)\v11.0;Initial Catalog=MyDatabase;Integrated Security=SSPI;";
          Roles = new System.Collections.Generic.List<string>
          {
          "Administrators"
          };
          Users = new System.Collections.Generic.List<User> 
          { 
          new User { Name = "test2", Password = "test2"}
          };
          UserIdColumnName = "UserId";
          UserNameColumnName = "UserName";
          UserTableName = "UserProfile";
          // Creates user and role tables if they don't exist.
          WebMatrix.WebData.WebSecurity.InitializeDatabaseConnection(DatabaseConnectionString, "System.Data.SqlClient", UserTableName, UserIdColumnName, UserNameColumnName, true);
          }
          public string DatabaseConnectionString { get; set; }
          public System.Collections.Generic.List<string> Roles { get; set; }
          public System.Collections.Generic.List<User> Users { get; set; }
          public string UserIdColumnName { get; set; }
          public string UserNameColumnName { get; set; }
          public string UserTableName { get; set; }
          public void CreateRoles()
          {
          Roles.ForEach(x =>
          {
          var roles = (WebMatrix.WebData.SimpleRoleProvider)System.Web.Security.Roles.Provider;
          if (roles.RoleExists(x))
          {
          System.Console.WriteLine("Role [{0}] already exists.", x);
          }
          else
          {
          roles.CreateRole(x);
          }
          });
          }
          public void CreateUsers()
          {
          Users.ForEach(x =>
          {
          if (WebMatrix.WebData.WebSecurity.UserExists(x.Name))
          {
          System.Console.WriteLine("User [{0}] already exists.", x.Name);
          }
          else
          {
          WebMatrix.WebData.WebSecurity.CreateUserAndAccount(x.Name, x.Password);
          }
          });
          }
          public void DeleteRoles()
          {
          Roles.ForEach(x =>
          {
          var roles = (WebMatrix.WebData.SimpleRoleProvider)System.Web.Security.Roles.Provider;
          if (roles.RoleExists(x))
          {
          System.Collections.Generic.List<string> usersInRole = roles.GetUsersInRole(x).ToList();
          Users = new System.Collections.Generic.List<User>();
          usersInRole.ForEach(u =>
          {
          Users.Add(new User { Name = u });
          });
          DeleteUsers();
          roles.DeleteRole(x, true);
          }
          else
          {
          System.Console.WriteLine("Role [{0}] already exists.", x);
          }
          });
          }
          public void DeleteUsers()
          {
          var membership = (WebMatrix.WebData.SimpleMembershipProvider)System.Web.Security.Membership.Provider;
          Users.ForEach(x =>
          {
          if (WebMatrix.WebData.WebSecurity.UserExists(x.Name))
          {
          membership.DeleteAccount(x.Name);
          membership.DeleteUser(x.Name, true);
          }
          else
          {
          System.Console.WriteLine("User [{0}] does not exist.", x.Name);
          }
          });
          }
          public void ResetPasswordUsers()
          {
          Users.ForEach(x =>
          {
          if (WebMatrix.WebData.WebSecurity.UserExists(x.Name))
          {
          WebMatrix.WebData.WebSecurity.ResetPassword(null, x.Name);
          }
          else
          {
          System.Console.WriteLine("User [{0}] does not exist.", x.Name);
          }
          });
          }
          }
          public interface IWebSecurityWrapper
          {
          void CreateRoles();
          void CreateUsers();
          string DatabaseConnectionString { get; set; }
          void DeleteRoles();
          void DeleteUsers();
          void Initialize();
          void ResetPasswordUsers();
          System.Collections.Generic.List<string> Roles { get; set; }
          string UserIdColumnName { get; set; }
          string UserNameColumnName { get; set; }
          System.Collections.Generic.List<Research.Rli.User> Users { get; set; }
          string UserTableName { get; set; }
          }
          public class User
          {
          public string Name { get; set; }
          public string Password { get; set; }
          }
          }

          How to create an object from a C# *.cs file in PowerShell 3.0 and call a function on it.

          If you want to create an object based on the C# code in a *.cs file, by using PowerShell 3.0 you can use the following C# and PowerShell code:

           

          Create a folder "C:\Temp"

           

          image

           

          C# MyClass.cs file

          using System;
          using System.Collections.Generic;
          using System.Diagnostics;
          using System.IO;
          namespace MyNameSpace
          {
          public class MyClass
          {
          public void MyFunction()
          {
          Console.WriteLine("Hello from MyNameSpace.MyClass.MyFunction.");
          }
          }
          }
          

           

          PowerShell Execute_MyNamespace_MyClass_MyFunction.ps1

           Add-Type -Path "C:\Temp\MyClass.cs"
          $labeler = New-Object MyNameSpace.MyClass
          $labeler.MyFunction()
          pause 
          

          Execute

          image

           

          image

          Run PowerShell or batch file remotely

           

          To configure Windows PowerShell to receive remote commands in DEV

          http://www.howtogeek.com/117192/how-to-run-powershell-commands-on-remote-computers/

          1. Start Windows PowerShell with the "Run as administrator" option.
          2. On server: enable-psremoting
          3. On server: Set-ExecutionPolicy Unrestricted
          4. On server: Set-Item wsman:\localhost\client\trustedhosts * (allows any computer to connect)
          5. On server: Restart-Service WinRM
          6. On client: Set-ExecutionPolicy Unrestricted
          7. On client: Set-Item wsman:\localhost\client\trustedhosts * (allows connections to any server)
          8. On client: Restart-Service WinRM

          To run single command

          On client: Invoke-Command -ComputerName yourserver.yourdomain.com -ScriptBlock { C:\ |dir }

           

          To run multiple commands

          On client: Enter-PSSession -ComputerName yourserver.yourdomain.com

          ….

          On client: Exit-PSSession

           

          To run a PowerShell script remotely from a client batch file

          On client: create a "C:\Local.bat" file

          On client: create a "C:\Remote.ps1" file

          On client in the Remote.ps1 file: enter your powershell commands that will be executed remotely, like dir C:\

          On client in the Local.bat file: @powershell -command "Invoke-Command -ComputerName yourserver.yourdomain.com -FilePath ""C:\Remote.ps1"""

          pause

          How to start a process / application on an other computer from C#, by using PowerShell remoting

           

          You van execute a process on an other machine from C#, by using the code below:

           

          Example for calling the function

          var rc = new RemotingComponent(null);
          rc.RunRemoteProcess
          (
          @"MyMachine1", 
          "MyMachine1\Administrator", 
          "MyPassword1", 
          @"C:\Windows\System32\notepad.exe",
          string.Empty
          );

          C# class

          using System;
          using System.Collections.Generic;
          using System.IO;
          using System.Linq;
          using System.Management.Automation;
          using System.Management.Automation.Runspaces;
          using System.Security;
          using System.Text;
          namespace Research
          {
          public interface IRemotingComponent
          {
          void RunRemoteProcess(string machineName, string userName, string password, string processPath, string processArguments);
          }
          public class RemotingComponent : IRemotingComponent
          {
          public void RunRemoteProcess(string machineName, string userName, string password, string processPath, string processArguments)
          {
          var connectTo = new Uri(String.Format("http://{0}:5985/wsman", machineName));
          _logger.Info("Building powershell command.");
          var command = new StringBuilder();
          command.AppendLine("$pinfo = New-Object System.Diagnostics.ProcessStartInfo");
          command.AppendLine(string.Format(@"$pinfo.FileName = ""{0}""", processPath));
          command.AppendLine("$pinfo.UseShellExecute = $false");
          command.AppendLine("$pinfo.RedirectStandardError = $true");
          command.AppendLine("$pinfo.RedirectStandardOutput = $true");
          command.AppendLine("$pinfo.CreateNoWindow = $true");
          command.AppendLine(string.Format(@"$pinfo.WorkingDirectory = ""{0}""", new FileInfo(processPath).Directory.FullName));
          command.AppendLine(string.Format(@"$pinfo.Arguments = ""{0}""", processArguments));
          command.AppendLine("$p = New-Object System.Diagnostics.Process");
          command.AppendLine("$p.StartInfo = $pinfo");
          command.AppendLine("$p.Start() | Out-Null");
          command.AppendLine("$output = $p.StandardOutput.ReadToEnd()");
          command.AppendLine("$p.WaitForExit()");
          command.AppendLine("$output");
          string shell = @"http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
          using (var passing = new SecureString())
          {
          foreach (char c in password.ToCharArray())
          {
          passing.AppendChar(c);
          }
          passing.MakeReadOnly();
          var credentials = new PSCredential(userName, passing);
          var connection = new WSManConnectionInfo(connectTo, shell, credentials);
          using (var runspace = RunspaceFactory.CreateRunspace(connection))
          {
             runspace.Open();
          using (var powershell = PowerShell.Create())
          {
          powershell.Runspace = runspace;
          powershell.AddScript(command.ToString());
                 var results = powershell.Invoke();
          runspace.Close();
          foreach (var obj in results.Where(o => o != null))
          {
          Console.Writeline(string.Format("Output: [{0}].", obj));
          }
          }
          }
          }
          }
          }
          }
          

          Using C# in PowerShell to move files

           

          Screedump form Windows PowerShell ISE

           

          image

           

          Code

          $source = @"

          using System;
          using System.Collections.Generic;
          using System.Text;
          using System.IO;

          namespace Rvl.Demo.Common
          {
              public class MoveFiles
              {
                  public static void Move()
                  {
                      string sourceFolder = @"C:\BDATA\Test\Source"; // Source folder
                      string destinationFolder = @"C:\BDATA\Test\Destination"; // Destination folder
                      DateTime checkDateTime = new DateTime(2010, 12, 29, 13, 0, 0); // 27-dec-2010 13:00:00
                      // Loop all files in source folder
                      foreach (string file in Directory.GetFiles(sourceFolder))
                      {
                          // Calculate difference between checkDateTime and file last modified datetime in days
                          DateTime fileLastModifiedDate = File.GetLastWriteTime(file);

                          // Move files if difference in days == 0
                          if (checkDateTime.Year == fileLastModifiedDate.Year && checkDateTime.Month == fileLastModifiedDate.Month && checkDateTime.Day == fileLastModifiedDate.Day)
                          {
                              string destinationFilePath = Path.Combine(destinationFolder, Path.GetFileName(file));
                              Console.WriteLine(string.Format("Moving file [{0}] to [{1}]", file, destinationFilePath));

                              File.Move(file, destinationFilePath);
                          }
                      }
                  }
              }
          }
          "@

          Add-Type -TypeDefinition $source

          [Rvl.Demo.Common.MoveFiles]::Move()

          PowerShell function to build a Microsoft Visual Studio setup project from command line with devenv.exe

          If you want to build you’re Microsoft Visual Studio 2010 setup project in release mode, from the command line, you can use the following PowerShell function:

          function RebuildSubsystem([string]$solutionPath, [string]$projectPath, [string]$devEnvPath)
          {
              $parameters = "/Rebuild Release ""$solutionPath"" /Project ""$projectPath"" /ProjectConfig Release"
              "Process to start [$devEnvPath $parameters]"
              $process = [System.Diagnostics.Process]::Start( "$devEnvPath", $parameters )
              $process.WaitForExit()
          }

           

          To call the function use:

          RebuildSubsystem "C:\Projects\MyApplication\MyApplication.sln" "C:\Projects\MyApplication\MyApplication.Setup\MyApplication.Setup.vdproj" "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe"