Comment supprimer le pool récalcitrant d'une application inexistante dans IIS?

Voici une situation peu ragoutante que j'ai rencontrée il y a déjà quelque temps. IIS ne permettait pas la suppression d'un pool.

Heureusement, tout IIS est pilotable via PowerShell. Il suffit de connaitre les bonnes commandes.

L'application bloquant la suppression du pool n'était pas visible via la console. Dans un tel cas, il faut donc commencer par identifier les sites, et les applications que IIS ne semble pas vouloir afficher. Pour cela, il y a deux commandes à connaitre :


Get-Website
Get-WebApplication

Pour l'exemple, imaginons que je trouve une application app1 qui se trouvait dans le site web site1. Pour pouvoir supprimer cette application, il faut donc utiliser la commande :


Remove-WebApplication -Name app1 -Site site1 

Pour finir, le pool nommé pool1 dans mon exemple peut être supprimé via cette commande :


Remove-WebAppPool –Name pool1

Jérémy Jeanson

Comment réaliser des tests unitaires sur l'input d'un composant Blazor ?

L'une des choses que je préfère avec Blazor, consiste dans la possibilité de tester intégralement un composant via bUnit. Un bon exemple valant toujours mieux que de long discourt, voici un cas simple permettant de résoudre deux problématiques :

  • Le besoin de modifier un input.
  • Le besoin de consulter le contenu d'un input.

Pour commencer, on peut initialiser un contexte de test, et effectuer un rendu d'un composant :


// Création du context de test 
using var context = new TestContext();

// Création du composent et rendu
var obj = context.RenderComponent<MonComposent>();


Pour modifier une input dont l'Id serait inputId, on peut utiliser le code :


obj.Find("#inputId").Change("Ma valeur");


Pour consulter le contenu d'un input dont l'ID serait inputId, on peut utiliser le code :


var actual  = obj.Find("#inputId").GetAttribute("value");


Pour finir, voici un exemple complet :


[Theory] 
[InlineData("Foo")] 
public void Exemple(String value) 
{
  // Création du context de test 
  using var context = new TestContext(); 

  // Création du composent et rendu 
  var obj = context.RenderComponent<MonComposent>(); 

  // Modification
  obj.Find("#inputId").Change(value); 

  // … ajouter des interactions avec le composant ici 

  // Vérifier la valeur de l'input 
  var actual= obj.Find("#inputId").GetAttribute("value"); 
  actual.Should().BeEquivalentTo(value);  
} 

Conclusion

Voici du code simple et efficace. Tout ce que j'aime!

Jérémy Jeanson

Comment passer des paramètres à une action deferred de Windows Installer ?

Dans un précédent article, je présentais la démarche à suivre pour exécuter une action custom avec des privilèges élevés. Cette approche passe par l'exécution de l'action dans un contexte deferred. Celui-ci a un impact sur la manière d'accéder aux propriétés via l'action custom.

Habituellement, WiX toolset permet d'utiliser la syntaxe qui suit pour accéder à des paramètres lors de l'installation. Dans le cadre d'une action custom deferred, le code suivant n'est pas utilisable.


[CustomAction] 
public static ActionResult DoSomething(Session session) 
{ 
  var destination = session["INSTALLFOLDER"]; 
  // … 
}

Il doit être remplacé par :


[CustomAction] 
public static ActionResult DoSomething(Session session) 
{ 
  var destination = session.CustomActionData["INSTALLFOLDER"]; 
  // … 
}

CustomActionData est alimenté via la propriété Value de l'action custom. Le contenu accepte une syntaxe du style nom1=valuer1;nom2=valeur2;....

Malheureusement, cette propriété ne peut pas être affectée directement. Il faut ajout une seconde action custom pour cela. Dans l'exemple suivant, j'ai créé une action custom SetDoSomethingValue qui affecter les propriétés que j'utilise dans l'action custom DoSomething.


<!-- Actions personnalisées --> 
<Binary Id="CustomActions" 
    SourceFile="CustomActions.CA.dll"/> 

<CustomAction Id="DoSomething" 
    BinaryRef="CustomActions" 
    DllEntry="DoSomething" 
    Execute="deferred" 
    Return="check" 
    Impersonate="no"/> 

<CustomAction Id="SetDoSomethingValue" 
    Property="DoSomething" 
    Value="INSTALLFOLDER=[INSTALLFOLDER]"/>

Ben évidemment, l'action custom SetDoSomethingValue doit être ajoutée à la section InstallExecuteSequence, et s'exécuter avant l'action DoSomething.


<InstallExecuteSequence>
  <Custom Action="DoSomething" Before="InstallFinalize" Condition="NOT REMOVE"/> 
  <Custom Action="SetDoSomethingValue" Before="DoSomething" Condition="NOT REMOVE"/> 
</InstallExecuteSequence>

Jérémy Jeanson

Comment exécuter une action custom Windows Installer avec des privilèges élevés ?

Par défaut, lors du déploiement, une action custom s'exécute avec les privilèges de l'utilisateur courant. Celle-ci ne dispose d'aucun privilège administrateur. Le fait de fixer un scope perMachine comme ceci ne suffit pas :


<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> 
  <Package 
     Name="..." 
     Scope="perMachine"> 

Une solution peut consister dans le fait de d'utiliser un terminal avec une élévation de privilège pour lancer msiexec (msiexec /i mon-fichier.msi).

Heureusement WiX Toolset, permet de demander à Windows Installer d'exécuter une action custom avec des privilèges élever facilement. Pour cela, il faut utiliser l'option deferred pour la propriété Execute, et no pour la propriété Impersonate. La raison de ce changement est expluqée ici : Immediate Custom Actions Always Impersonate - Visual Studio Setup (microsoft.com)

Exemple :


<!-- Actions personnalisées --> 
<Binary 
    Id="CustomActions" 
    SourceFile="CustomActions.CA.dll"/> 
<CustomAction Id="DoSomething" 
    BinaryRef="CustomActions" 
    DllEntry="DoSomething" 
    Return="check" 
    Execute="deferred" 
    Impersonate="no"/>

Bien évidemment, l'action custom DoSomething doit être présente dans la séquence InstallExecuteSequence. Son exécution doit être planifiée entre InstallExecute, et InstallFinalize.


<InstallExecuteSequence>
  <Custom Action="DoSomething" Before="InstallFinalize" /> 
</InstallExecuteSequence> 

Après avoir appliqué ces modifications, l'action custom s'exécutera toujours avec des privilèges élevés.

Jérémy Jeanson

Comment automatiser l’installation de MSI avec Azure DevOps, et Release Manager ?

Automatisé le déploiement de MSI, n’a jamais été une tâche triviale. Aujourd’hui, je vous propose d’effectuer celle-ci avec Azure DevOps.

Pour l’exemple, j’utilise un pipeline de Release, et j’y ai ajouté une tâche powerShell :

Tâche PowerShell d'un pipeline de release

Dans la propriété Inline, il suffit de coller le contenu du script qui suit, et le tour est joué :


$msi = Get-ChildItem $(System.ArtifactsDirectory)\*.msi -Recurse
Write-Host "Msi trouvé : $msi"

$log = "D:\Applications\MyApp\installation.log"
if (Test-Path $log) {
        Remove-Item $log -verbose
}
 
$arguments = @( "/i", $msi, "INSTALLFOLDER=""D:\Applications\MyApp""", "/quiet","/lv",$log)
 Write-Host $arguments 
 
Start-Process msiexec.exe -ArgumentList $arguments -Wait

Ce script va piloter msiexec en mode silencieux (c’est-à-dire sans interface), et attendre la fin du déploiement. Pour diagnostiquer les éventuels problèmes qui pourraient survenir lors du déploiement, un fichier de log est créé. Ce fichier est conservé jusqu’à la prochaine exécution.

Bien évidemment, il faudra adapter la variable $arguments en fonction de vos besoins, et les différents chemins.

Ce script peut aussi être utilisé avec un pipeline de type multistage, et un job de déploiement.

Jérémy Jeanson